mirror of
https://github.com/danbulant/Portfolio
synced 2026-05-26 21:41:50 +00:00
Merge pull request #121 from EETagent/more_prod_fixes
(frontend) more prod fixes
This commit is contained in:
commit
1367ffcf7b
18 changed files with 370 additions and 306 deletions
|
|
@ -10,4 +10,5 @@ COPY --from=builder /portfolio/target/release/portfolio /usr/local/bin/portfolio
|
||||||
VOLUME ["/portfolio"]
|
VOLUME ["/portfolio"]
|
||||||
WORKDIR /portfolio
|
WORKDIR /portfolio
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
ENTRYPOINT ["portfolio"]
|
ENTRYPOINT ["portfolio"]
|
||||||
|
|
|
||||||
40
frontend/src/global.d.ts
vendored
40
frontend/src/global.d.ts
vendored
|
|
@ -1,18 +1,24 @@
|
||||||
declare type FileDropEvent = import("filedrop-svelte/event").FileDropEvent;
|
declare type FileDropEvent = import('filedrop-svelte/event').FileDropEvent;
|
||||||
declare type FileDropSelectEvent = import("filedrop-svelte/event").FileDropSelectEvent;
|
declare type FileDropSelectEvent = import('filedrop-svelte/event').FileDropSelectEvent;
|
||||||
declare type FileDropDragEvent = import("filedrop-svelte/event").FileDropDragEvent;
|
declare type FileDropDragEvent = import('filedrop-svelte/event').FileDropDragEvent;
|
||||||
declare namespace svelte.JSX {
|
declare namespace svelte.JSX {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
interface HTMLAttributes<T> {
|
interface HTMLAttributes<T> {
|
||||||
onfiledrop?: (event: CustomEvent<FileDropSelectEvent> & { target: EventTarget & T }) => void;
|
onfiledrop?: (event: CustomEvent<FileDropSelectEvent> & { target: EventTarget & T }) => void;
|
||||||
onfiledragenter?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
|
onfiledragenter?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
|
||||||
onfiledragleave?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
|
onfiledragleave?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
|
||||||
onfiledragover?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
|
onfiledragover?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
|
||||||
onfiledialogcancel?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
|
onfiledialogcancel?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
|
||||||
onfiledialogclose?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
|
onfiledialogclose?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
|
||||||
onfiledialogopen?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
|
onfiledialogopen?: (event: CustomEvent<FileDropEvent> & { target: EventTarget & T }) => void;
|
||||||
onwindowfiledragenter?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
|
onwindowfiledragenter?: (
|
||||||
onwindowfiledragleave?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
|
event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }
|
||||||
onwindowfiledragover?: (event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }) => void;
|
) => void;
|
||||||
}
|
onwindowfiledragleave?: (
|
||||||
}
|
event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }
|
||||||
|
) => void;
|
||||||
|
onwindowfiledragover?: (
|
||||||
|
event: CustomEvent<FileDropDragEvent> & { target: EventTarget & T }
|
||||||
|
) => void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,9 +123,7 @@ export const apiFetchCandidate = async (id: number, fetchSsr?: Fetch): Promise<C
|
||||||
|
|
||||||
// SSR compatible
|
// SSR compatible
|
||||||
// List all candidates /admin/list/candidates
|
// List all candidates /admin/list/candidates
|
||||||
export const apiListCandidatesCSV = async (
|
export const apiListCandidatesCSV = async (fetchSsr?: Fetch): Promise<Blob> => {
|
||||||
fetchSsr?: Fetch,
|
|
||||||
): Promise<Blob> => {
|
|
||||||
const apiFetch = fetchSsr || fetch;
|
const apiFetch = fetchSsr || fetch;
|
||||||
try {
|
try {
|
||||||
const res = await apiFetch(API_URL + '/admin/list/candidates_csv', {
|
const res = await apiFetch(API_URL + '/admin/list/candidates_csv', {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
try {
|
try {
|
||||||
login = await apiCreateCandidate(data);
|
login = await apiCreateCandidate(data);
|
||||||
dispatch('created');
|
dispatch('created');
|
||||||
|
error = '';
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
error = (e as ApiError).msg;
|
error = (e as ApiError).msg;
|
||||||
|
|
@ -47,7 +48,10 @@
|
||||||
{:else}
|
{:else}
|
||||||
<h1 class="text-sspsBlue text-3xl font-semibold">Registrace nového uchazeče</h1>
|
<h1 class="text-sspsBlue text-3xl font-semibold">Registrace nového uchazeče</h1>
|
||||||
{#if error}
|
{#if error}
|
||||||
<div class="my-2 bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative" role="alert">
|
<div
|
||||||
|
class="relative my-2 rounded border border-red-400 bg-red-100 px-4 py-3 text-red-700"
|
||||||
|
role="alert"
|
||||||
|
>
|
||||||
<span class="block sm:inline">{error}</span>
|
<span class="block sm:inline">{error}</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,18 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import debounce from 'just-debounce-it';
|
import debounce from 'just-debounce-it';
|
||||||
|
|
||||||
import { apiDeltePortfolio, apiGetPortfolio, apiLogout, apiSubmitPortfolio } from '$lib/@api/candidate';
|
import {
|
||||||
|
apiDeltePortfolio,
|
||||||
|
apiGetPortfolio,
|
||||||
|
apiLogout,
|
||||||
|
apiSubmitPortfolio
|
||||||
|
} from '$lib/@api/candidate';
|
||||||
import Circles from '$lib/components/icons/Circles.svelte';
|
import Circles from '$lib/components/icons/Circles.svelte';
|
||||||
import { fetchSubmProgress, type Status } from '$lib/stores/portfolio';
|
import { fetchSubmProgress, type Status } from '$lib/stores/portfolio';
|
||||||
import StatusNotificationBig from './StatusNotificationBig.svelte';
|
import StatusNotificationBig from './StatusNotificationBig.svelte';
|
||||||
import InfoButton from './InfoButton.svelte';
|
import InfoButton from './InfoButton.svelte';
|
||||||
import { baseCandidateData, candidateData } from '$lib/stores/candidate';
|
import { baseCandidateData, candidateData } from '$lib/stores/candidate';
|
||||||
import tippy, {sticky} from 'tippy.js';
|
import tippy, { sticky } from 'tippy.js';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
export let title: string;
|
export let title: string;
|
||||||
|
|
@ -61,19 +66,19 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const editDetails = async () => {
|
const editDetails = async () => {
|
||||||
goto('/register?edit=true')
|
goto('/register?edit=true');
|
||||||
}
|
};
|
||||||
|
|
||||||
const logout = async () => {
|
const logout = async () => {
|
||||||
await apiLogout();
|
await apiLogout();
|
||||||
goto("/auth/login");
|
goto('/auth/login');
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="card flex flex-col">
|
<div class="card flex flex-col">
|
||||||
<div class="infoBar <2xl:flex-col flex flex-row-reverse">
|
<div class="infoBar <2xl:flex-col flex flex-row-reverse">
|
||||||
<StatusNotificationBig {loading} {status} on:click={debounce(handleNotificationClick, 150)} />
|
<StatusNotificationBig {loading} {status} on:click={debounce(handleNotificationClick, 150)} />
|
||||||
<div class="mr-4 <2xl:mr-1">
|
<div class="<2xl:mr-1 mr-4">
|
||||||
<div on:click on:keydown class="flex flex-col">
|
<div on:click on:keydown class="flex flex-col">
|
||||||
<div class="<2xl:ml-auto <2xl:flex-row <2xl:my-2 flex flex-col">
|
<div class="<2xl:ml-auto <2xl:flex-row <2xl:my-2 flex flex-col">
|
||||||
<InfoButton
|
<InfoButton
|
||||||
|
|
@ -89,7 +94,7 @@
|
||||||
<div class="relative my-2 flex flex-col overflow-hidden">
|
<div class="relative my-2 flex flex-col overflow-hidden">
|
||||||
<div>
|
<div>
|
||||||
<div class="mt-[5%] flex flex-col">
|
<div class="mt-[5%] flex flex-col">
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<h3>{title}</h3>
|
<h3>{title}</h3>
|
||||||
<span
|
<span
|
||||||
on:click={logout}
|
on:click={logout}
|
||||||
|
|
@ -101,15 +106,28 @@
|
||||||
sticky: true,
|
sticky: true,
|
||||||
plugins: [sticky]
|
plugins: [sticky]
|
||||||
}}
|
}}
|
||||||
class="<2xl:hidden hover:cursor-pointer">
|
class="<2xl:hidden hover:cursor-pointer"
|
||||||
<svg class="w-10 h-10 stroke-sspsBlueDark" 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"></path></svg>
|
>
|
||||||
|
<svg
|
||||||
|
class="stroke-sspsBlueDark 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
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{#if showDetails}
|
{#if showDetails}
|
||||||
<div class="overflow-scroll flex justify-between">
|
<div class="flex justify-between overflow-scroll">
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
use:tippy={{
|
use:tippy={{
|
||||||
|
|
@ -121,7 +139,10 @@
|
||||||
}}
|
}}
|
||||||
class="mt-4 flex flex-col justify-between leading-10"
|
class="mt-4 flex flex-col justify-between leading-10"
|
||||||
>
|
>
|
||||||
<span>Ev. č. přihlášky: <span class="font-bold">{$baseCandidateData.applicationId}</span></span>
|
<span
|
||||||
|
>Ev. č. přihlášky: <span class="font-bold">{$baseCandidateData.applicationId}</span
|
||||||
|
></span
|
||||||
|
>
|
||||||
<span>Obor: <span class="font-bold">{$candidateData.candidate.study}</span></span>
|
<span>Obor: <span class="font-bold">{$candidateData.candidate.study}</span></span>
|
||||||
<span>Adresa: <span class="font-bold">{$candidateData.candidate.address}</span></span>
|
<span>Adresa: <span class="font-bold">{$candidateData.candidate.address}</span></span>
|
||||||
<span
|
<span
|
||||||
|
|
@ -133,10 +154,12 @@
|
||||||
></span
|
></span
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
>Rodné číslo: <span class="font-bold">{$candidateData.candidate.personalIdNumber}</span
|
>Rodné číslo: <span class="font-bold"
|
||||||
|
>{$candidateData.candidate.personalIdNumber}</span
|
||||||
></span
|
></span
|
||||||
>
|
>
|
||||||
<span>Telefon: <span class="font-bold">{$candidateData.candidate.telephone}</span></span>
|
<span>Telefon: <span class="font-bold">{$candidateData.candidate.telephone}</span></span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
use:tippy={{
|
use:tippy={{
|
||||||
|
|
@ -167,8 +190,23 @@
|
||||||
sticky: true,
|
sticky: true,
|
||||||
plugins: [sticky]
|
plugins: [sticky]
|
||||||
}}
|
}}
|
||||||
on:click={(_) => editDetails()} on:keydown={(_) => editDetails()} class="mt-4 hover:cursor-pointer">
|
on:click={(_) => editDetails()}
|
||||||
<svg class="w-10 h-10 stroke-sspsBlue" 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="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path></svg>
|
on:keydown={(_) => editDetails()}
|
||||||
|
class="mt-4 hover:cursor-pointer"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
class="stroke-sspsBlue 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="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
|
||||||
|
/></svg
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
@ -182,7 +220,7 @@
|
||||||
|
|
||||||
@apply bg-[#f8fbfc];
|
@apply bg-[#f8fbfc];
|
||||||
@apply rounded-3xl;
|
@apply rounded-3xl;
|
||||||
@apply px-7 py-10 <2xl:px-5 <2xl:py-5;
|
@apply <2xl:px-5 <2xl:py-5 px-7 py-10;
|
||||||
|
|
||||||
@apply transition-all duration-300;
|
@apply transition-all duration-300;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@
|
||||||
clearInterval(dashAnimationInterval);
|
clearInterval(dashAnimationInterval);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const onFileDrop = (dropped: Files) => {
|
const onFileDrop = (dropped: Files) => {
|
||||||
console.log(dropped);
|
console.log(dropped);
|
||||||
if (dropped.accepted.length > 0) {
|
if (dropped.accepted.length > 0) {
|
||||||
|
|
|
||||||
|
|
@ -88,8 +88,21 @@
|
||||||
}}
|
}}
|
||||||
on:click={(_) => logout()}
|
on:click={(_) => logout()}
|
||||||
on:keydown={(_) => logout()}
|
on:keydown={(_) => logout()}
|
||||||
class="icon logoutIcon ml-1 hover:cursor-pointer">
|
class="icon logoutIcon ml-1 hover:cursor-pointer"
|
||||||
<svg class="w-10 h-10 icon logoutIcon" 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"></path></svg>
|
>
|
||||||
|
<svg
|
||||||
|
class="icon logoutIcon 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
|
||||||
|
>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,7 @@
|
||||||
}
|
}
|
||||||
.view {
|
.view {
|
||||||
@apply z-10 overflow-scroll;
|
@apply z-10 overflow-scroll;
|
||||||
@apply rounded-3xl md:rounded-none;
|
@apply absolute top-0 right-0 bottom-0 left-0 m-auto md:top-auto md:bottom-auto md:left-auto md:m-0;
|
||||||
@apply absolute top-0 right-0 bottom-0 left-0 m-auto h-[90vh] w-[90vw] md:top-auto md:bottom-auto md:left-auto md:m-0;
|
|
||||||
@apply md:h-screen md:w-[50vw];
|
@apply md:h-screen md:w-[50vw];
|
||||||
@apply md:my-auto;
|
@apply md:my-auto;
|
||||||
@apply bg-white;
|
@apply bg-white;
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ export interface CreateCandidateLogin extends CreateCandidate {
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const baseCandidateData= writable<CreateCandidate>({
|
export const baseCandidateData = writable<CreateCandidate>({
|
||||||
applicationId: 0,
|
applicationId: 0,
|
||||||
personalIdNumber: ''
|
personalIdNumber: ''
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
import type { PageServerData } from './$types';
|
import type { PageServerData } from './$types';
|
||||||
import Table from '$lib/components/admin/table/Table.svelte';
|
import Table from '$lib/components/admin/table/Table.svelte';
|
||||||
|
|
||||||
import bacgkround from "$lib/assets/background.jpg";
|
import bacgkround from '$lib/assets/background.jpg';
|
||||||
|
|
||||||
export let data: PageServerData;
|
export let data: PageServerData;
|
||||||
|
|
||||||
|
|
@ -87,7 +87,7 @@
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if createCandidateModal}
|
{#if createCandidateModal}
|
||||||
|
|
@ -98,8 +98,8 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<header class="w-full h-14">
|
<header class="h-14 w-full">
|
||||||
<img class="h-12 w-full object-cover filter blur-sm" src={bacgkround} alt="Background">
|
<img class="h-12 w-full object-cover blur-sm filter" src={bacgkround} alt="Background" />
|
||||||
</header>
|
</header>
|
||||||
<div class="flex flex-row">
|
<div class="flex flex-row">
|
||||||
<div class="list fixed">
|
<div class="list fixed">
|
||||||
|
|
@ -116,12 +116,12 @@
|
||||||
<TextField on:keyup={search} bind:value={searchValue} placeholder="Hledat" />
|
<TextField on:keyup={search} bind:value={searchValue} placeholder="Hledat" />
|
||||||
<button
|
<button
|
||||||
on:click={openCreateCandidateModal}
|
on:click={openCreateCandidateModal}
|
||||||
class="bg-gray-500 hover:bg-gray-600 ml-3 w-2/5 rounded-lg p-3 py-4 text-xl font-semibold text-white transition-colors duration-300"
|
class="ml-3 w-2/5 rounded-lg bg-gray-500 p-3 py-4 text-xl font-semibold text-white transition-colors duration-300 hover:bg-gray-600"
|
||||||
>Nový uchazeč</button
|
>Nový uchazeč</button
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
on:click={downloadCSV}
|
on:click={downloadCSV}
|
||||||
class="bg-gray-500 hover:bg-gray-600 ml-3 w-2/5 rounded-lg p-3 py-4 text-xl font-semibold text-white transition-colors duration-300"
|
class="ml-3 w-2/5 rounded-lg bg-gray-500 p-3 py-4 text-xl font-semibold text-white transition-colors duration-300 hover:bg-gray-600"
|
||||||
>CSV</button
|
>CSV</button
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
<p class="text-sspsGray mt-8 text-center font-light">
|
<p class="text-sspsGray mt-8 text-center font-light">
|
||||||
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /> Fusce suscipit libero eget elit.
|
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /> Fusce suscipit libero eget elit.
|
||||||
</p>
|
</p>
|
||||||
<div class="mt-8 flex w-3/5 flex-col">
|
<div class="mt-8 flex w-4/5 flex-col lg:w-3/5">
|
||||||
<span>
|
<span>
|
||||||
<TextField bind:value={adminIdValue} placeholder="Admin id" type="number" />
|
<TextField bind:value={adminIdValue} placeholder="Admin id" type="number" />
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -42,7 +42,7 @@
|
||||||
<PasswordField bind:value={adminPasswordValue} placeholder="Heslo" />
|
<PasswordField bind:value={adminPasswordValue} placeholder="Heslo" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-8 w-3/5">
|
<div class="mt-8 w-4/5 lg:w-3/5">
|
||||||
<Submit value="Odeslat" on:click={login} />
|
<Submit value="Odeslat" on:click={login} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export const load: LayoutServerLoad = async ({ cookies, fetch }) => {
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
whoami: whoami
|
whoami: whoami
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
throw redirect(302, '/auth/logout');
|
throw redirect(302, '/auth/logout');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="dashboard dashboardMobile">
|
<div class="dashboard dashboardMobile">
|
||||||
<div class="name md:my-10 mx-auto w-[90%]">
|
<div class="name mx-auto w-[90%] md:my-10">
|
||||||
<DashboardInfoCard
|
<DashboardInfoCard
|
||||||
status={getUploadStatus($submissionProgress.status)}
|
status={getUploadStatus($submissionProgress.status)}
|
||||||
title={$candidateData.candidate.name + ' ' + $candidateData.candidate.surname ?? ''}
|
title={$candidateData.candidate.name + ' ' + $candidateData.candidate.surname ?? ''}
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@ import type { PageServerLoad } from './$types';
|
||||||
export const load: PageServerLoad = async ({ fetch }) => {
|
export const load: PageServerLoad = async ({ fetch }) => {
|
||||||
const details: CandidateData | undefined = await apiFetchDetails(fetch).catch((e) => {
|
const details: CandidateData | undefined = await apiFetchDetails(fetch).catch((e) => {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
candidate: details,
|
candidate: details
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
let details = data.candidate;
|
let details = data.candidate;
|
||||||
|
|
||||||
|
|
||||||
const formInitialValues = {
|
const formInitialValues = {
|
||||||
gdpr: false,
|
gdpr: false,
|
||||||
candidate: {
|
candidate: {
|
||||||
|
|
@ -140,11 +139,10 @@
|
||||||
// TODO: validate on admin dashboard, move somewhere
|
// TODO: validate on admin dashboard, move somewhere
|
||||||
// TODO: nefunguje pro lidi nar. pred 1.1.1954 :D
|
// TODO: nefunguje pro lidi nar. pred 1.1.1954 :D
|
||||||
const isPersonalIdNumberValid = (personalIdNumber: string): boolean => {
|
const isPersonalIdNumberValid = (personalIdNumber: string): boolean => {
|
||||||
const idFmt = personalIdNumber
|
const idFmt = personalIdNumber.split('/').join('');
|
||||||
.split('/')
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
const lastDigitCheck = Number(idFmt.slice(0, 9)) % 11 === Number(idFmt.at(-1)) ||
|
const lastDigitCheck =
|
||||||
|
Number(idFmt.slice(0, 9)) % 11 === Number(idFmt.at(-1)) ||
|
||||||
Number(idFmt.slice(0, 9)) % 11 === 10; // an edge case that could occur
|
Number(idFmt.slice(0, 9)) % 11 === 10; // an edge case that could occur
|
||||||
const divisibleBy11 = Number(idFmt) % 11 === 0;
|
const divisibleBy11 = Number(idFmt) % 11 === 0;
|
||||||
|
|
||||||
|
|
@ -153,26 +151,30 @@
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const isPersonalIdNumberWithBirthdateValid = (personalIdNumber: string, birthdate: string): boolean => {
|
const isPersonalIdNumberWithBirthdateValid = (
|
||||||
|
personalIdNumber: string,
|
||||||
|
birthdate: string
|
||||||
|
): boolean => {
|
||||||
const dateFmt = birthdate
|
const dateFmt = birthdate
|
||||||
.split('.')
|
.split('.')
|
||||||
.map((x) => x.padStart(2, '0'))
|
.map((x) => x.padStart(2, '0'))
|
||||||
.reverse()
|
.reverse()
|
||||||
.join('')
|
.join('')
|
||||||
.slice(2);
|
.slice(2);
|
||||||
const idFmt = personalIdNumber
|
const idFmt = personalIdNumber.split('/').join('');
|
||||||
.split('/')
|
|
||||||
.join('');
|
|
||||||
|
|
||||||
const divisionValid = isPersonalIdNumberValid(personalIdNumber);
|
const divisionValid = isPersonalIdNumberValid(personalIdNumber);
|
||||||
|
|
||||||
const idMonth = Number(idFmt.slice(2, 4));
|
const idMonth = Number(idFmt.slice(2, 4));
|
||||||
const dateMonth = Number(dateFmt.slice(2, 4));
|
const dateMonth = Number(dateFmt.slice(2, 4));
|
||||||
const monthValid = idMonth === dateMonth || idMonth === dateMonth + 50 ||
|
const monthValid =
|
||||||
idMonth === dateMonth + 20 || idMonth === dateMonth + 70;
|
idMonth === dateMonth ||
|
||||||
|
idMonth === dateMonth + 50 ||
|
||||||
|
idMonth === dateMonth + 20 ||
|
||||||
|
idMonth === dateMonth + 70;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
idFmt.slice(0, 2) === dateFmt.slice(0, 2) &&
|
idFmt.slice(0, 2) === dateFmt.slice(0, 2) &&
|
||||||
monthValid &&
|
monthValid &&
|
||||||
|
|
@ -183,7 +185,6 @@
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSubmit = async (values: CandidateData) => {
|
const onSubmit = async (values: CandidateData) => {
|
||||||
|
|
@ -192,7 +193,12 @@
|
||||||
let oldValues = JSON.parse(JSON.stringify(values));
|
let oldValues = JSON.parse(JSON.stringify(values));
|
||||||
try {
|
try {
|
||||||
if (values.candidate.citizenship === 'Česká republika') {
|
if (values.candidate.citizenship === 'Česká republika') {
|
||||||
if (!isPersonalIdNumberWithBirthdateValid(values.candidate.personalIdNumber, values.candidate.birthdate)) {
|
if (
|
||||||
|
!isPersonalIdNumberWithBirthdateValid(
|
||||||
|
values.candidate.personalIdNumber,
|
||||||
|
values.candidate.birthdate
|
||||||
|
)
|
||||||
|
) {
|
||||||
alert('Rodné číslo neodpovídá oficiální specifikaci či datumu narození'); // TODO: alerts
|
alert('Rodné číslo neodpovídá oficiální specifikaci či datumu narození'); // TODO: alerts
|
||||||
throw new Error('Rodné číslo neodpovídá datumu narození');
|
throw new Error('Rodné číslo neodpovídá datumu narození');
|
||||||
}
|
}
|
||||||
|
|
@ -212,7 +218,6 @@
|
||||||
(x) => x.name !== '' && x.surname !== '' && x.email !== '' && x.telephone !== ''
|
(x) => x.name !== '' && x.surname !== '' && x.email !== '' && x.telephone !== ''
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
await apiFillDetails(values);
|
await apiFillDetails(values);
|
||||||
goto('/dashboard');
|
goto('/dashboard');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
@ -220,7 +225,7 @@
|
||||||
console.error('error while submitting data: ' + e);
|
console.error('error while submitting data: ' + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const { form, errors, handleSubmit, handleChange } = createForm({
|
const { form, errors, handleSubmit, handleChange } = createForm({
|
||||||
initialValues: formInitialValues,
|
initialValues: formInitialValues,
|
||||||
|
|
@ -292,267 +297,269 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatTelephone = (telephone: string) => {
|
const formatTelephone = (telephone: string) => {
|
||||||
return '+' + telephone
|
return '+' + telephone.match(/[0-9]{1,3}/g)!.join(' ');
|
||||||
.match(/[0-9]{1,3}/g)!
|
};
|
||||||
.join(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (details !== undefined) {
|
if (details !== undefined) {
|
||||||
details.candidate.birthdate = details.candidate.birthdate
|
details.candidate.birthdate = details.candidate.birthdate.split('-').reverse().join('.');
|
||||||
.split('-')
|
|
||||||
.reverse()
|
details.candidate.telephone = formatTelephone(details.candidate.telephone);
|
||||||
.join('.');
|
details.parents.map(
|
||||||
|
(x) => (x.telephone = x.telephone != '' ? formatTelephone(x.telephone) : '')
|
||||||
details.candidate.telephone = formatTelephone(details.candidate.telephone);
|
);
|
||||||
details.parents.map((x) => x.telephone = x.telephone != '' ? formatTelephone(x.telephone) : '');
|
form.set({
|
||||||
form.set({
|
gdpr: true,
|
||||||
gdpr: true,
|
candidate: {
|
||||||
candidate: {
|
...details.candidate
|
||||||
...details.candidate
|
},
|
||||||
},
|
parents: [
|
||||||
parents: [
|
|
||||||
{
|
{
|
||||||
...details.parents[0]
|
...details.parents[0]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
...details.parents[1] ?? {
|
...(details.parents[1] ?? {
|
||||||
name: '',
|
name: '',
|
||||||
surname: '',
|
surname: '',
|
||||||
email: '',
|
email: '',
|
||||||
telephone: ''
|
telephone: ''
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
pageIndex = 1; // skip gdpr page
|
pageIndex = 1; // skip gdpr page
|
||||||
pageTexts[1] = 'Úprava osobních údajů'
|
pageTexts[1] = 'Úprava osobních údajů';
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SplitLayout>
|
<SplitLayout>
|
||||||
<div class="form relative">
|
<div class="form relative">
|
||||||
<div class="overflow-scroll h-[65%] md:h-auto absolute bottom-3/12 flex flex-col w-full">
|
<div class="bottom-3/12 absolute flex w-full flex-col overflow-scroll md:h-auto">
|
||||||
<div class="h-32 w-32 <md:hidden self-center mb-4">
|
<div class="<md:h-24 <md:w-24 mb-4 h-32 w-32 self-center">
|
||||||
<SchoolBadge />
|
<SchoolBadge />
|
||||||
</div>
|
</div>
|
||||||
<form on:submit={handleSubmit} id="triggerForm" class="invisible hidden"></form>
|
<form on:submit={handleSubmit} id="triggerForm" class="invisible hidden" />
|
||||||
{#if pageIndex === 0}
|
{#if pageIndex === 0}
|
||||||
<form on:submit={handleSubmit}>
|
<form on:submit={handleSubmit}>
|
||||||
<h1 class="title mt-8">{pageTexts[0]}</h1>
|
<h1 class="title mt-8">{pageTexts[0]}</h1>
|
||||||
|
<p class="description mt-8 block text-center">
|
||||||
|
V rámci portálu pro přijímací řízení zpracováváme mnoho osobních údajů. Proto je nutný
|
||||||
|
Váš souhlas s jejich zpracováním. O bezpečnosti zpracování Vašich osobních údajů si
|
||||||
|
můžete přečíst
|
||||||
|
<a href="/bezpecnost" class="text-sspsBlue underline"> zde</a>.
|
||||||
|
</p>
|
||||||
|
<div class="field">
|
||||||
|
<GdprCheckBox
|
||||||
|
on:change={handleChange}
|
||||||
|
bind:value={$form.gdpr}
|
||||||
|
error={$typedErrors['gdpr']}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{:else if pageIndex === 1}
|
||||||
|
<form on:submit={handleSubmit}>
|
||||||
|
<h1 class="title mt-8">{pageTexts[1]}</h1>
|
||||||
|
<p class="description mt-8 block text-center">
|
||||||
|
V rámci usnadnění přijímacího řízení jsme připravili online formulář, který Vám pomůže s
|
||||||
|
vyplněním potřebných údajů.
|
||||||
|
</p>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<span class="field">
|
||||||
|
<NameField
|
||||||
|
error={$typedErrors['candidate']['name'] || $typedErrors['candidate']['surname']}
|
||||||
|
on:change={handleChange}
|
||||||
|
bind:valueName={$form.candidate.name}
|
||||||
|
bind:valueSurname={$form.candidate.surname}
|
||||||
|
placeholder="Jméno a příjmení"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span class="field">
|
||||||
|
<EmailField
|
||||||
|
error={$typedErrors['candidate']['email']}
|
||||||
|
on:change={handleChange}
|
||||||
|
bind:value={$form.candidate.email}
|
||||||
|
placeholder="E-mail"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span class="field">
|
||||||
|
<TelephoneField
|
||||||
|
error={$typedErrors['candidate']['telephone']}
|
||||||
|
on:change={handleChange}
|
||||||
|
bind:value={$form.candidate.telephone}
|
||||||
|
placeholder="Telefon"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{:else if pageIndex === 2}
|
||||||
|
<h1 class="title mt-8">{pageTexts[2]}</h1>
|
||||||
<p class="description mt-8 block text-center">
|
<p class="description mt-8 block text-center">
|
||||||
V rámci portálu pro přijímací řízení zpracováváme mnoho osobních údajů. Proto je nutný Váš
|
Pro registraci je potřeba vyplnit několik údajů o Vás. Tyto údaje budou použity pro
|
||||||
souhlas s jejich zpracováním. O bezpečnosti zpracování Vašich osobních údajů si můžete přečíst
|
přijímací řízení. Všechny údaje jsou důležité.
|
||||||
<a href="/bezpecnost" class="text-sspsBlue underline"> zde</a>.
|
|
||||||
</p>
|
</p>
|
||||||
<div class="field">
|
<div class="flex w-full flex-col">
|
||||||
<GdprCheckBox
|
<span class="field">
|
||||||
on:change={handleChange}
|
<TextField
|
||||||
bind:value={$form.gdpr}
|
error={$typedErrors['candidate']['address']}
|
||||||
error={$typedErrors['gdpr']}
|
on:change={handleChange}
|
||||||
/>
|
bind:value={$form.candidate.address}
|
||||||
|
type="text"
|
||||||
|
placeholder="Adresa trvalého bydliště"
|
||||||
|
helperText="Uveďte ulici, č.p., město, PSČ"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span class="field">
|
||||||
|
<TextField
|
||||||
|
error={$typedErrors['candidate']['birthplace']}
|
||||||
|
on:change={handleChange}
|
||||||
|
bind:value={$form.candidate.birthplace}
|
||||||
|
type="text"
|
||||||
|
placeholder="Místo narození"
|
||||||
|
helperText="Uveďte město"
|
||||||
|
icon
|
||||||
|
>
|
||||||
|
<div slot="icon" class="text-sspsBlue flex items-center justify-center">
|
||||||
|
<Home />
|
||||||
|
</div>
|
||||||
|
</TextField>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
{:else if pageIndex === 1}
|
<div class="field flex items-center">
|
||||||
<form on:submit={handleSubmit}>
|
<TextField
|
||||||
<h1 class="title mt-8">{pageTexts[1]}</h1>
|
error={$typedErrors['candidate']['birthdate']}
|
||||||
|
on:change={handleChange}
|
||||||
|
bind:value={$form.candidate.birthdate}
|
||||||
|
type="text"
|
||||||
|
placeholder="Datum narození"
|
||||||
|
helperText="TODO: (Uveďte ve formátu DD.MM.RRRR)"
|
||||||
|
/>
|
||||||
|
<div class="ml-2">
|
||||||
|
<SelectField
|
||||||
|
error={$typedErrors['candidate']['sex']}
|
||||||
|
on:change={handleChange}
|
||||||
|
bind:value={$form.candidate.sex}
|
||||||
|
options={['Žena', 'Muž']}
|
||||||
|
placeholder="Pohlaví"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{:else if pageIndex === 3}
|
||||||
|
<h1 class="title mt-8">{pageTexts[3]}</h1>
|
||||||
<p class="description mt-8 block text-center">
|
<p class="description mt-8 block text-center">
|
||||||
V rámci usnadnění přijímacího řízení jsme připravili online formulář, který Vám pomůže s
|
Sběr dat o zákonném zástupci je klíčový pro získání důležitých kontaktů a informací.
|
||||||
vyplněním potřebných údajů.
|
|
||||||
</p>
|
</p>
|
||||||
<div class="flex flex-col">
|
<div class="flex w-full flex-col">
|
||||||
<span class="field">
|
<span class="field">
|
||||||
<NameField
|
<NameField
|
||||||
error={$typedErrors['candidate']['name'] || $typedErrors['candidate']['surname']}
|
error={$typedErrors['parents'][0]['name'] || $typedErrors['parents'][0]['surname']}
|
||||||
on:change={handleChange}
|
on:change={handleChange}
|
||||||
bind:valueName={$form.candidate.name}
|
bind:valueName={$form.parents[0].name}
|
||||||
bind:valueSurname={$form.candidate.surname}
|
bind:valueSurname={$form.parents[0].surname}
|
||||||
placeholder="Jméno a příjmení"
|
placeholder="Jméno a příjmení zákonného zástupce"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="field">
|
<span class="field">
|
||||||
<EmailField
|
<EmailField
|
||||||
error={$typedErrors['candidate']['email']}
|
error={$typedErrors['parents'][0]['email']}
|
||||||
on:change={handleChange}
|
on:change={handleChange}
|
||||||
bind:value={$form.candidate.email}
|
bind:value={$form.parents[0].email}
|
||||||
placeholder="E-mail"
|
placeholder="E-mail zákonného zástupce"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="field">
|
<span class="field">
|
||||||
<TelephoneField
|
<TelephoneField
|
||||||
error={$typedErrors['candidate']['telephone']}
|
error={$typedErrors['parents'][0]['telephone']}
|
||||||
on:change={handleChange}
|
on:change={handleChange}
|
||||||
bind:value={$form.candidate.telephone}
|
bind:value={$form.parents[0].telephone}
|
||||||
placeholder="Telefon"
|
placeholder="Telefon zákonného zástupce"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
{:else if pageIndex === 4}
|
||||||
{:else if pageIndex === 2}
|
<h1 class="title mt-8">{pageTexts[4]}</h1>
|
||||||
<h1 class="title mt-8">{pageTexts[2]}</h1>
|
<p class="description mt-8 block text-center">
|
||||||
<p class="description mt-8 block text-center">
|
Zde můžete zadat údaje o druhém zákonném zástupci. Škole tím umožníte lépe komunikovat.
|
||||||
Pro registraci je potřeba vyplnit několik údajů o Vás. Tyto údaje budou použity pro
|
</p>
|
||||||
přijímací řízení. Všechny údaje jsou důležité.
|
<div class="flex w-full flex-col">
|
||||||
</p>
|
<span class="field">
|
||||||
<div class="flex w-full flex-col">
|
<NameField
|
||||||
<span class="field">
|
error={$typedErrors['parents'][1]['name'] || $typedErrors['parents'][1]['surname']}
|
||||||
<TextField
|
on:change={handleChange}
|
||||||
error={$typedErrors['candidate']['address']}
|
bind:valueName={$form.parents[1].name}
|
||||||
on:change={handleChange}
|
bind:valueSurname={$form.parents[1].surname}
|
||||||
bind:value={$form.candidate.address}
|
placeholder="Jméno a příjmení zákonného zástupce (nepovinné)"
|
||||||
type="text"
|
/>
|
||||||
placeholder="Adresa trvalého bydliště"
|
|
||||||
helperText="Uveďte ulici, č.p., město, PSČ"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span class="field">
|
|
||||||
<TextField
|
|
||||||
error={$typedErrors['candidate']['birthplace']}
|
|
||||||
on:change={handleChange}
|
|
||||||
bind:value={$form.candidate.birthplace}
|
|
||||||
type="text"
|
|
||||||
placeholder="Místo narození"
|
|
||||||
helperText="Uveďte město"
|
|
||||||
icon
|
|
||||||
>
|
|
||||||
<div slot="icon" class="text-sspsBlue flex items-center justify-center">
|
|
||||||
<Home />
|
|
||||||
</div>
|
|
||||||
</TextField>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="field flex items-center">
|
|
||||||
<TextField
|
|
||||||
error={$typedErrors['candidate']['birthdate']}
|
|
||||||
on:change={handleChange}
|
|
||||||
bind:value={$form.candidate.birthdate}
|
|
||||||
type="text"
|
|
||||||
placeholder="Datum narození"
|
|
||||||
helperText="TODO: (Uveďte ve formátu DD.MM.RRRR)"
|
|
||||||
/>
|
|
||||||
<div class="ml-2">
|
|
||||||
<SelectField
|
|
||||||
error={$typedErrors['candidate']['sex']}
|
|
||||||
on:change={handleChange}
|
|
||||||
bind:value={$form.candidate.sex}
|
|
||||||
options={['Žena', 'Muž']}
|
|
||||||
placeholder="Pohlaví"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{:else if pageIndex === 3}
|
|
||||||
<h1 class="title mt-8">{pageTexts[3]}</h1>
|
|
||||||
<p class="description mt-8 block text-center">
|
|
||||||
Sběr dat o zákonném zástupci je klíčový pro získání důležitých kontaktů a informací.
|
|
||||||
</p>
|
|
||||||
<div class="flex w-full flex-col">
|
|
||||||
<span class="field">
|
|
||||||
<NameField
|
|
||||||
error={$typedErrors['parents'][0]['name'] || $typedErrors['parents'][0]['surname']}
|
|
||||||
on:change={handleChange}
|
|
||||||
bind:valueName={$form.parents[0].name}
|
|
||||||
bind:valueSurname={$form.parents[0].surname}
|
|
||||||
placeholder="Jméno a příjmení zákonného zástupce"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span class="field">
|
|
||||||
<EmailField
|
|
||||||
error={$typedErrors['parents'][0]['email']}
|
|
||||||
on:change={handleChange}
|
|
||||||
bind:value={$form.parents[0].email}
|
|
||||||
placeholder="E-mail zákonného zástupce"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span class="field">
|
|
||||||
<TelephoneField
|
|
||||||
error={$typedErrors['parents'][0]['telephone']}
|
|
||||||
on:change={handleChange}
|
|
||||||
bind:value={$form.parents[0].telephone}
|
|
||||||
placeholder="Telefon zákonného zástupce"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
{:else if pageIndex === 4}
|
|
||||||
<h1 class="title mt-8">{pageTexts[4]}</h1>
|
|
||||||
<p class="description mt-8 block text-center">
|
|
||||||
Zde můžete zadat údaje o druhém zákonném zástupci. Škole tím umožníte lépe komunikovat.
|
|
||||||
</p>
|
|
||||||
<div class="flex w-full flex-col">
|
|
||||||
<span class="field">
|
|
||||||
<NameField
|
|
||||||
error={$typedErrors['parents'][1]['name'] || $typedErrors['parents'][1]['surname']}
|
|
||||||
on:change={handleChange}
|
|
||||||
bind:valueName={$form.parents[1].name}
|
|
||||||
bind:valueSurname={$form.parents[1].surname}
|
|
||||||
placeholder="Jméno a příjmení zákonného zástupce (nepovinné)"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span class="field">
|
|
||||||
<EmailField
|
|
||||||
error={$typedErrors['parents'][1]['email']}
|
|
||||||
on:change={handleChange}
|
|
||||||
bind:value={$form.parents[1].email}
|
|
||||||
placeholder="E-mail zákonného zástupce (nepovinné)"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span class="field">
|
|
||||||
<TelephoneField
|
|
||||||
error={$typedErrors['parents'][1]['telephone']}
|
|
||||||
on:change={handleChange}
|
|
||||||
bind:value={$form.parents[1].telephone}
|
|
||||||
placeholder="Telefon zákonného zástupce (nepovinné)"
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
<span class="field">
|
||||||
{:else if pageIndex === 5}
|
<EmailField
|
||||||
<h1 class="title mt-8">{pageTexts[5]}</h1>
|
error={$typedErrors['parents'][1]['email']}
|
||||||
<p class="description mt-8 block text-center">
|
on:change={handleChange}
|
||||||
Zadejte prosím své občanství, rodné číslo, či jeho alternativu Vaší země a obor na který se hlásíte.
|
bind:value={$form.parents[1].email}
|
||||||
</p>
|
placeholder="E-mail zákonného zástupce (nepovinné)"
|
||||||
<div class="flex w-full flex-row md:flex-col">
|
/>
|
||||||
<span class="field">
|
</span>
|
||||||
<SelectField
|
<span class="field">
|
||||||
error={$typedErrors['candidate']['citizenship']}
|
<TelephoneField
|
||||||
on:change={handleChange}
|
error={$typedErrors['parents'][1]['telephone']}
|
||||||
bind:value={$form.candidate.citizenship}
|
on:change={handleChange}
|
||||||
placeholder="Občanství"
|
bind:value={$form.parents[1].telephone}
|
||||||
options={['Česká republika', 'Slovenská republika', 'Ukrajina', 'Jiné']}
|
placeholder="Telefon zákonného zástupce (nepovinné)"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="field ml-2 md:ml-0">
|
</div>
|
||||||
<TextField on:change={handleChange} type="text" placeholder="Evidenční číslo přihlášky" />
|
{:else if pageIndex === 5}
|
||||||
</span>
|
<h1 class="title mt-8">{pageTexts[5]}</h1>
|
||||||
</div>
|
<p class="description mt-8 block text-center">
|
||||||
<div class="field flex items-center justify-center">
|
Zadejte prosím své občanství, rodné číslo, či jeho alternativu Vaší země a obor na který
|
||||||
{#if $form.candidate.citizenship === 'Česká republika' || !$form.candidate.citizenship}
|
se hlásíte.
|
||||||
<IdField
|
</p>
|
||||||
error={$typedErrors['candidate']['personalIdNumber']}
|
<div class="flex w-full flex-row md:flex-col">
|
||||||
on:change={handleChange}
|
<span class="field">
|
||||||
bind:value={$form.candidate.personalIdNumber}
|
<SelectField
|
||||||
placeholder="Rodné číslo"
|
error={$typedErrors['candidate']['citizenship']}
|
||||||
/>
|
on:change={handleChange}
|
||||||
{:else}
|
bind:value={$form.candidate.citizenship}
|
||||||
<TextField
|
placeholder="Občanství"
|
||||||
error={$typedErrors['candidate']['personalIdNumber']}
|
options={['Česká republika', 'Slovenská republika', 'Ukrajina', 'Jiné']}
|
||||||
on:change={handleChange}
|
/>
|
||||||
bind:value={$form.candidate.personalIdNumber}
|
</span>
|
||||||
placeholder="Rodné číslo"
|
<span class="field ml-2 md:ml-0">
|
||||||
/>
|
<TextField
|
||||||
{/if}
|
on:change={handleChange}
|
||||||
<span class="ml-2">
|
type="text"
|
||||||
<SelectField
|
placeholder="Evidenční číslo přihlášky"
|
||||||
error={$typedErrors['candidate']['study']}
|
/>
|
||||||
on:change={handleChange}
|
</span>
|
||||||
bind:value={$form.candidate.study}
|
</div>
|
||||||
placeholder="Obor"
|
<div class="field flex items-center justify-center">
|
||||||
options={['KB', 'IT', 'G']}
|
{#if $form.candidate.citizenship === 'Česká republika' || !$form.candidate.citizenship}
|
||||||
/>
|
<IdField
|
||||||
</span>
|
error={$typedErrors['candidate']['personalIdNumber']}
|
||||||
</div>
|
on:change={handleChange}
|
||||||
{/if}
|
bind:value={$form.candidate.personalIdNumber}
|
||||||
|
placeholder="Rodné číslo"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<TextField
|
||||||
|
error={$typedErrors['candidate']['personalIdNumber']}
|
||||||
|
on:change={handleChange}
|
||||||
|
bind:value={$form.candidate.personalIdNumber}
|
||||||
|
placeholder="Rodné číslo"
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
<span class="ml-2">
|
||||||
|
<SelectField
|
||||||
|
error={$typedErrors['candidate']['study']}
|
||||||
|
on:change={handleChange}
|
||||||
|
bind:value={$form.candidate.study}
|
||||||
|
placeholder="Obor"
|
||||||
|
options={['KB', 'IT', 'G']}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="controls w-full absolute bottom-1/12">
|
<div class="controls bottom-1/12 absolute w-full">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<Submit
|
<Submit
|
||||||
on:click={async (e) => {
|
on:click={async (e) => {
|
||||||
|
|
@ -569,8 +576,8 @@
|
||||||
value={pageIndex === pageCount ? 'Odeslat' : 'Pokračovat'}
|
value={pageIndex === pageCount ? 'Odeslat' : 'Pokračovat'}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 md:mt-8 flex flex-row justify-center">
|
<div class="mt-4 flex flex-row justify-center md:mt-8">
|
||||||
{#each Array(pageCount + 1) as _, i}
|
{#each Array(pageCount + 1) as _, i}
|
||||||
<button
|
<button
|
||||||
class:dotActive={i === pageIndex}
|
class:dotActive={i === pageIndex}
|
||||||
|
|
@ -578,7 +585,7 @@
|
||||||
pageIndex -= pageIndex === pageCount ? 1 : 0;
|
pageIndex -= pageIndex === pageCount ? 1 : 0;
|
||||||
await handleSubmit(e);
|
await handleSubmit(e);
|
||||||
pagesFilled = pagesFilled.map((_, i) => !isPageInvalid(i));
|
pagesFilled = pagesFilled.map((_, i) => !isPageInvalid(i));
|
||||||
|
|
||||||
const progress = pagesFilled.slice(0, i).every((item) => item === true);
|
const progress = pagesFilled.slice(0, i).every((item) => item === true);
|
||||||
if (progress) {
|
if (progress) {
|
||||||
pageIndex = i;
|
pageIndex = i;
|
||||||
|
|
@ -594,7 +601,7 @@
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
.field {
|
.field {
|
||||||
@apply mt-4 md:mt-8 w-full;
|
@apply mt-4 w-full md:mt-8 lg:mx-auto lg:w-4/5;
|
||||||
}
|
}
|
||||||
.form {
|
.form {
|
||||||
@apply flex flex-col;
|
@apply flex flex-col;
|
||||||
|
|
@ -618,6 +625,6 @@
|
||||||
@apply text-gray-500;
|
@apply text-gray-500;
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
@apply text-sspsBlue text-4xl font-semibold text-center;
|
@apply text-sspsBlue text-center text-4xl font-semibold;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,13 @@
|
||||||
<SchoolBadge />
|
<SchoolBadge />
|
||||||
<h1 class="text-sspsBlue mt-8 text-4xl font-semibold">Přihlášení</h1>
|
<h1 class="text-sspsBlue mt-8 text-4xl font-semibold">Přihlášení</h1>
|
||||||
<p class="text-sspsGray my-8 text-center font-light">
|
<p class="text-sspsGray my-8 text-center font-light">
|
||||||
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.<br /> Fusce suscipit libero eget elit.
|
Evidenční číslo je jedinečné číslo přidělené uchazeči, které slouží k jeho identifikaci<br /> a
|
||||||
|
přihlášení se do systému.
|
||||||
</p>
|
</p>
|
||||||
<div class="w-3/5">
|
<div class="w-4/5 lg:w-3/5">
|
||||||
<TextField bind:value={applicationValue} placeholder="Ev. číslo" type="number" />
|
<TextField bind:value={applicationValue} placeholder="Ev. číslo" type="number" />
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-8 w-3/5">
|
<div class="mt-8 w-4/5 lg:w-3/5">
|
||||||
<Submit on:click={redirectToCode} value="Odeslat" />
|
<Submit on:click={redirectToCode} value="Odeslat" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -123,14 +123,14 @@
|
||||||
.modal {
|
.modal {
|
||||||
@apply flex flex-col items-center justify-center;
|
@apply flex flex-col items-center justify-center;
|
||||||
@apply mx-auto my-auto;
|
@apply mx-auto my-auto;
|
||||||
@apply h-[90vh] w-[90vw] md:h-4/5 md:w-4/5;
|
@apply h-full w-full md:h-4/5 md:w-4/5;
|
||||||
@apply rounded-3xl;
|
@apply md:rounded-3xl;
|
||||||
@apply bg-white;
|
@apply bg-white;
|
||||||
}
|
}
|
||||||
input {
|
input {
|
||||||
@apply text-sspsBlue text-center font-semibold;
|
@apply text-sspsBlue text-center font-semibold;
|
||||||
@apply transition-colors duration-300;
|
@apply transition-colors duration-300;
|
||||||
@apply focus:border-sspsBlue hover:border-sspsBlue rounded-xl border border-2 bg-[#f8fafb] p-3 md:caret-transparent shadow-lg outline-none;
|
@apply focus:border-sspsBlue hover:border-sspsBlue rounded-xl border border-2 bg-[#f8fafb] p-3 shadow-lg outline-none md:caret-transparent;
|
||||||
}
|
}
|
||||||
.separater {
|
.separater {
|
||||||
@apply bg-sspsBlue mr-2 hidden h-2 w-8 md:block;
|
@apply bg-sspsBlue mr-2 hidden h-2 w-8 md:block;
|
||||||
|
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
<h1 class="text-6xl">Welcome to SvelteKit</h1>
|
|
||||||
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
|
|
||||||
Loading…
Reference in a new issue