mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-06 08:10:20 +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
|
// Reset candidate password /admin/candidate/{id}/reset_password
|
||||||
export const apiResetCandidatePassword = async (id: number): Promise<CreateCandidateLogin> => {
|
export const apiResetCandidatePassword = async (id: number): Promise<CreateCandidateLogin> => {
|
||||||
try {
|
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">
|
<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 Home from '$lib/components/icons/Home.svelte';
|
||||||
import TextField from '$lib/components/textfield/TextField.svelte';
|
import TextField from '$lib/components/textfield/TextField.svelte';
|
||||||
import type { CandidatePreview } from '$lib/stores/candidate';
|
import type { CandidatePreview } from '$lib/stores/candidate';
|
||||||
import CreateCandidateModal from '$lib/components/admin/CreateCandidateModal.svelte';
|
import CreateCandidateModal from '$lib/components/admin/CreateCandidateModal.svelte';
|
||||||
import Fuse from 'fuse.js';
|
import Fuse from 'fuse.js';
|
||||||
import type { PageServerData } from './$types';
|
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;
|
export let data: PageServerData;
|
||||||
|
|
||||||
|
|
@ -13,7 +15,10 @@
|
||||||
|
|
||||||
const getCandidates = async (field?: string) => {
|
const getCandidates = async (field?: string) => {
|
||||||
try {
|
try {
|
||||||
candidates = await apiListCandidates(undefined, field);
|
candidates = await apiListCandidates(
|
||||||
|
undefined,
|
||||||
|
field ?? activeFilter !== 'Vše' ? activeFilter : ''
|
||||||
|
);
|
||||||
} catch {
|
} catch {
|
||||||
console.log('error');
|
console.log('error');
|
||||||
}
|
}
|
||||||
|
|
@ -23,7 +28,7 @@
|
||||||
|
|
||||||
let filters: Array<Filter> = ['Vše', 'KBB', 'IT', 'GYM'];
|
let filters: Array<Filter> = ['Vše', 'KBB', 'IT', 'GYM'];
|
||||||
|
|
||||||
let activeFilter: Filter = 'Vše';
|
let activeFilter: Filter = filters[0];
|
||||||
|
|
||||||
const changeFilter = (filter: Filter) => {
|
const changeFilter = (filter: Filter) => {
|
||||||
activeFilter = filter;
|
activeFilter = filter;
|
||||||
|
|
@ -64,6 +69,11 @@
|
||||||
candidatesTable = fuse.search(searchValue).map((result) => result.item);
|
candidatesTable = fuse.search(searchValue).map((result) => result.item);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteCandidate = async (id: number | undefined) => {
|
||||||
|
if (id) await apiDeleteCandidate(id);
|
||||||
|
getCandidates();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if createCandidateModal}
|
{#if createCandidateModal}
|
||||||
|
|
@ -103,51 +113,7 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="flex flex-col">
|
<Table candidates={candidatesTable} on:delete={(event) => deleteCandidate(event.detail.id)} />
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue