mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-16 13:01:13 +00:00
Merge pull request #134 from EETagent/admin_page_improvements
(frontend) admin page improvements
This commit is contained in:
commit
ac4aa9643f
7 changed files with 90 additions and 46 deletions
|
|
@ -8,6 +8,22 @@ import type {
|
|||
import axios from 'axios';
|
||||
import { API_URL, errorHandler, type Fetch } from '.';
|
||||
|
||||
export const apiWhoami = async (fetchSsr?: Fetch): Promise<CreateCandidate> => {
|
||||
const apiFetch = fetchSsr || fetch;
|
||||
try {
|
||||
const res = await apiFetch(API_URL + '/admin/whoami', {
|
||||
method: 'GET',
|
||||
credentials: 'include'
|
||||
});
|
||||
if (res.status != 200) {
|
||||
throw Error(await res.text());
|
||||
}
|
||||
return await res.json();
|
||||
} catch (e) {
|
||||
throw errorHandler(e, 'Failed to fetch whoami');
|
||||
}
|
||||
};
|
||||
|
||||
// Login as admin /admin/login
|
||||
export const apiLogin = async (data: AdminLogin): Promise<number> => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
}
|
||||
|
||||
.modal {
|
||||
@apply absolute;
|
||||
@apply fixed;
|
||||
@apply p-4;
|
||||
@apply rounded-xl;
|
||||
@apply transform:
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
<tbody>
|
||||
{#each candidates as candidate}
|
||||
<tr class="border-b bg-white hover:cursor-pointer">
|
||||
<td class="text-gray-900"
|
||||
<td class="text-gray-900 hover:text-sspsBlue hover:font-bold"
|
||||
><a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
import Document from '../icons/Document.svelte';
|
||||
import Download from '../icons/Download.svelte';
|
||||
import { sticky } from 'tippy.js';
|
||||
import Logout from '../icons/Logout.svelte';
|
||||
|
||||
export let showDetails: boolean;
|
||||
|
||||
|
|
@ -50,19 +51,7 @@
|
|||
delay: 0
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
class="icon"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"
|
||||
/></svg
|
||||
>
|
||||
<Logout />
|
||||
</span>
|
||||
{:else}
|
||||
<span
|
||||
|
|
|
|||
13
frontend/src/lib/components/icons/Logout.svelte
Normal file
13
frontend/src/lib/components/icons/Logout.svelte
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<svg
|
||||
class="h-10 w-10"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
><path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"
|
||||
/></svg
|
||||
>
|
||||
|
After Width: | Height: | Size: 302 B |
|
|
@ -1,10 +1,19 @@
|
|||
import type { LayoutServerLoad } from './$types';
|
||||
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import { apiWhoami } from '$lib/@api/admin';
|
||||
|
||||
export const load: LayoutServerLoad = ({ cookies }) => {
|
||||
export const load: LayoutServerLoad = async ({ cookies, fetch }) => {
|
||||
const isAuthenticated = cookies.get('id');
|
||||
if (!isAuthenticated) {
|
||||
throw redirect(302, '/admin/auth/login');
|
||||
|
||||
if (isAuthenticated) {
|
||||
const whoami = await apiWhoami(fetch).catch(() => {
|
||||
throw redirect(302, '/admin/auth/logout');
|
||||
});
|
||||
return {
|
||||
whoami: whoami
|
||||
};
|
||||
} else {
|
||||
throw redirect(302, '/admin/auth/logout');
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,44 +9,52 @@
|
|||
import Table from '$lib/components/admin/table/Table.svelte';
|
||||
|
||||
import bacgkround from '$lib/assets/background.jpg';
|
||||
import Logout from '$lib/components/icons/Logout.svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
export let data: PageServerData;
|
||||
|
||||
let candidates: Array<CandidatePreview> = data.preview;
|
||||
|
||||
const getCandidates = async (field?: string) => {
|
||||
const getCandidates = async () => {
|
||||
try {
|
||||
candidates = await apiListCandidates(
|
||||
undefined,
|
||||
field ?? activeFilter !== 'Vše' ? activeFilter : ''
|
||||
);
|
||||
candidates = await apiListCandidates(undefined, activeFilter.filter);
|
||||
} catch {
|
||||
console.log('error');
|
||||
}
|
||||
};
|
||||
|
||||
type Filter = 'Vše' | 'KBB' | 'IT' | 'GYM';
|
||||
type Class = 'Vše' | 'KBB' | 'IT' | 'GYM';
|
||||
|
||||
let filters: Array<Filter> = ['Vše', 'KBB', 'IT', 'GYM'];
|
||||
type Filter = {
|
||||
class: Class;
|
||||
filter: string | undefined;
|
||||
};
|
||||
|
||||
let filters: Array<Filter> = [
|
||||
{
|
||||
class: 'Vše',
|
||||
filter: undefined
|
||||
},
|
||||
{
|
||||
class: 'KBB',
|
||||
filter: 'KB'
|
||||
},
|
||||
{
|
||||
class: 'IT',
|
||||
filter: 'IT'
|
||||
},
|
||||
{
|
||||
class: 'GYM',
|
||||
filter: 'G'
|
||||
}
|
||||
];
|
||||
|
||||
let activeFilter: Filter = filters[0];
|
||||
|
||||
const changeFilter = (filter: Filter) => {
|
||||
const changeFilter = async (filter: Filter) => {
|
||||
activeFilter = filter;
|
||||
switch (activeFilter) {
|
||||
case 'Vše':
|
||||
getCandidates();
|
||||
break;
|
||||
case 'KBB':
|
||||
getCandidates('KB');
|
||||
break;
|
||||
case 'IT':
|
||||
getCandidates('IT');
|
||||
break;
|
||||
case 'GYM':
|
||||
getCandidates('G');
|
||||
break;
|
||||
}
|
||||
await getCandidates();
|
||||
};
|
||||
|
||||
let scrollTop = 0;
|
||||
|
|
@ -88,6 +96,10 @@
|
|||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const logout = async () => {
|
||||
goto('/admin/auth/logout');
|
||||
};
|
||||
</script>
|
||||
|
||||
{#if createCandidateModal}
|
||||
|
|
@ -98,7 +110,7 @@
|
|||
{/if}
|
||||
|
||||
<div>
|
||||
<header class="h-14 w-full">
|
||||
<header class="absolute h-14 w-full">
|
||||
<img class="h-12 w-full object-cover blur-sm filter" src={bacgkround} alt="Background" />
|
||||
</header>
|
||||
<div class="flex flex-row">
|
||||
|
|
@ -106,12 +118,17 @@
|
|||
{#each filters as filter}
|
||||
<div class:selected={filter === activeFilter}>
|
||||
<Home />
|
||||
<button on:click={() => changeFilter(filter)}>{filter}</button>
|
||||
<button on:click={() => changeFilter(filter)}>{filter.class}</button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="body relative overflow-scroll">
|
||||
<h1 class="text-3xl font-semibold">Uchazeči</h1>
|
||||
<div class="flex items-center">
|
||||
<h1 class="text-3xl font-semibold">Uchazeči</h1>
|
||||
<button class="ml-2" on:click={logout}>
|
||||
<Logout />
|
||||
</button>
|
||||
</div>
|
||||
<div class="controls my-8">
|
||||
<TextField on:keyup={search} bind:value={searchValue} placeholder="Hledat" />
|
||||
<button
|
||||
|
|
@ -157,14 +174,14 @@
|
|||
@apply flex items-center;
|
||||
@apply rounded-xl;
|
||||
|
||||
@apply transition-all duration-300;
|
||||
@apply transition-all duration-200;
|
||||
|
||||
@apply hover:bg-sspsBlue focus:bg-sspsBlue;
|
||||
@apply hover:text-white focus:text-white;
|
||||
}
|
||||
|
||||
.list div :global(path) {
|
||||
@apply transition-all duration-300;
|
||||
@apply transition-all duration-100;
|
||||
}
|
||||
|
||||
.list div:hover :global(path) {
|
||||
|
|
@ -194,7 +211,7 @@
|
|||
.body {
|
||||
@apply h-full w-full;
|
||||
@apply float-left overflow-hidden;
|
||||
@apply my-6 mx-12 ml-[27rem];
|
||||
@apply my-6 mx-12 mt-16 ml-[27rem];
|
||||
}
|
||||
|
||||
.body .controls {
|
||||
|
|
|
|||
Loading…
Reference in a new issue