mirror of
https://github.com/danbulant/Portfolio
synced 2026-05-24 12:35:31 +00:00
Merge pull request #113 from EETagent/user_delete
(frontend) delete user on dashboard
This commit is contained in:
commit
a438091c99
4 changed files with 149 additions and 48 deletions
|
|
@ -29,6 +29,16 @@ export const apiCreateCandidate = async (data: CreateCandidate): Promise<CreateC
|
|||
}
|
||||
};
|
||||
|
||||
// Deletes candidate /admin/candidate/{id}
|
||||
export const apiDeleteCandidate = async (id: number): Promise<string> => {
|
||||
try {
|
||||
const res = await axios.delete(API_URL + `/admin/candidate/${id}`, { withCredentials: true });
|
||||
return res.data;
|
||||
} catch (e) {
|
||||
throw errorHandler(e, 'Candidate creation failed');
|
||||
}
|
||||
};
|
||||
|
||||
// Reset candidate password /admin/candidate/{id}/reset_password
|
||||
export const apiResetCandidatePassword = async (id: number): Promise<CreateCandidateLogin> => {
|
||||
try {
|
||||
|
|
|
|||
60
frontend/src/lib/components/admin/table/Table.svelte
Normal file
60
frontend/src/lib/components/admin/table/Table.svelte
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
<script lang="ts">
|
||||
import Delete from '$lib/components/button/Delete.svelte';
|
||||
import type { CandidatePreview } from '$lib/stores/candidate';
|
||||
|
||||
export let candidates: Array<CandidatePreview> = [];
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col">
|
||||
<div class="overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||
<div class="inline-block min-w-full py-4 sm:px-6 lg:px-8">
|
||||
<div class="overflow-hidden rounded-md border-2 border-[#dfe0e9] ">
|
||||
<table class="min-w-full text-center ">
|
||||
<thead class="bg-[#f6f4f4] ">
|
||||
<tr>
|
||||
<th scope="col"> Ev. č. přihlásky </th>
|
||||
<th scope="col"> Jméno </th>
|
||||
<th scope="col"> Příjmení </th>
|
||||
<th scope="col"> Obor </th>
|
||||
<th scope="col" />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each candidates as candidate}
|
||||
<tr class="border-b bg-white hover:cursor-pointer">
|
||||
<td class="text-gray-900"
|
||||
><a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="/admin/candidate/{candidate.applicationId}">{candidate.applicationId}</a
|
||||
></td
|
||||
>
|
||||
<td class="text-gray-900">
|
||||
{candidate.name}
|
||||
</td>
|
||||
<td class="text-gray-900">
|
||||
{candidate.surname}
|
||||
</td>
|
||||
<td class="text-gray-900">
|
||||
{candidate.study}
|
||||
</td>
|
||||
<td class="text-sm">
|
||||
<Delete id={candidate.applicationId} on:delete value="Odstranit" />
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
th {
|
||||
@apply px-6 py-4 text-sm font-medium text-gray-900;
|
||||
}
|
||||
td {
|
||||
@apply whitespace-nowrap px-6 py-4 text-sm;
|
||||
}
|
||||
</style>
|
||||
65
frontend/src/lib/components/button/Delete.svelte
Normal file
65
frontend/src/lib/components/button/Delete.svelte
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte';
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let value: string;
|
||||
|
||||
export let id: number | undefined;
|
||||
|
||||
let isPrepared = false;
|
||||
|
||||
const buttonLogic = () => {
|
||||
if (isPrepared) {
|
||||
dispatch('delete', {
|
||||
id: id
|
||||
});
|
||||
} else {
|
||||
dispatch('prepared', {
|
||||
id: id
|
||||
});
|
||||
isPrepared = true;
|
||||
setTimeout(() => {
|
||||
isPrepared = false;
|
||||
}, 3000);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<button on:click={buttonLogic} class="animate-bounce" class:isPrepared>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="mr-2 h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
|
||||
{value}
|
||||
</button>
|
||||
|
||||
<style lang="postcss">
|
||||
button {
|
||||
@apply inline-flex items-center;
|
||||
@apply bg-red-700;
|
||||
@apply @apply rounded-lg p-3 font-semibold
|
||||
text-white transition-colors duration-300;
|
||||
|
||||
animation: none !important;
|
||||
}
|
||||
button:hover {
|
||||
@apply bg-red-800;
|
||||
}
|
||||
|
||||
.isPrepared {
|
||||
@apply bg-red-800;
|
||||
animation: bounce 1s infinite !important;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
<script lang="ts">
|
||||
import { apiListCandidates } from '$lib/@api/admin';
|
||||
import { apiDeleteCandidate, apiListCandidates } from '$lib/@api/admin';
|
||||
import Home from '$lib/components/icons/Home.svelte';
|
||||
import TextField from '$lib/components/textfield/TextField.svelte';
|
||||
import type { CandidatePreview } from '$lib/stores/candidate';
|
||||
import CreateCandidateModal from '$lib/components/admin/CreateCandidateModal.svelte';
|
||||
import Fuse from 'fuse.js';
|
||||
import type { PageServerData } from './$types';
|
||||
import Delete from '$lib/components/button/Delete.svelte';
|
||||
import Table from '$lib/components/admin/table/Table.svelte';
|
||||
|
||||
export let data: PageServerData;
|
||||
|
||||
|
|
@ -13,7 +15,10 @@
|
|||
|
||||
const getCandidates = async (field?: string) => {
|
||||
try {
|
||||
candidates = await apiListCandidates(undefined, field);
|
||||
candidates = await apiListCandidates(
|
||||
undefined,
|
||||
field ?? activeFilter !== 'Vše' ? activeFilter : ''
|
||||
);
|
||||
} catch {
|
||||
console.log('error');
|
||||
}
|
||||
|
|
@ -23,7 +28,7 @@
|
|||
|
||||
let filters: Array<Filter> = ['Vše', 'KBB', 'IT', 'GYM'];
|
||||
|
||||
let activeFilter: Filter = 'Vše';
|
||||
let activeFilter: Filter = filters[0];
|
||||
|
||||
const changeFilter = (filter: Filter) => {
|
||||
activeFilter = filter;
|
||||
|
|
@ -64,6 +69,11 @@
|
|||
candidatesTable = fuse.search(searchValue).map((result) => result.item);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteCandidate = async (id: number | undefined) => {
|
||||
if (id) await apiDeleteCandidate(id);
|
||||
getCandidates();
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if createCandidateModal}
|
||||
|
|
@ -103,51 +113,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="flex flex-col">
|
||||
<div class="overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||
<div class="inline-block min-w-full py-4 sm:px-6 lg:px-8">
|
||||
<div class="overflow-hidden rounded-md border-2 border-[#dfe0e9] ">
|
||||
<table class="min-w-full text-center ">
|
||||
<thead class="bg-[#f6f4f4] ">
|
||||
<tr>
|
||||
<th scope="col" class="px-6 py-4 text-sm font-medium text-gray-900">
|
||||
Ev. č. přihlásky
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-4 text-sm font-medium text-gray-900"> Jméno </th>
|
||||
<th scope="col" class="px-6 py-4 text-sm font-medium text-gray-900">
|
||||
Příjmení
|
||||
</th>
|
||||
<th scope="col" class="px-6 py-4 text-sm font-medium text-gray-900"> Obor </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each candidatesTable as candidate}
|
||||
<tr class="border-b bg-white hover:cursor-pointer">
|
||||
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-900"
|
||||
><a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="/admin/candidate/{candidate.applicationId}"
|
||||
>{candidate.applicationId}</a
|
||||
></td
|
||||
>
|
||||
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-900">
|
||||
{candidate.name}
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-900">
|
||||
{candidate.surname}
|
||||
</td>
|
||||
<td class="whitespace-nowrap px-6 py-4 text-sm text-gray-900">
|
||||
{candidate.study}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Table candidates={candidatesTable} on:delete={(event) => deleteCandidate(event.detail.id)} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue