Merge branch 'master' into admin_create_more_data

This commit is contained in:
Sebastian Pravda 2023-01-26 23:50:32 +01:00
commit 18621c55c0
No known key found for this signature in database
GPG key ID: F3BC84F08EFA3F57
22 changed files with 418 additions and 165 deletions

View file

@ -67,10 +67,10 @@ pub struct CandidateDetails {
pub name: String, pub name: String,
#[validate(length(min = 1, max = 255))] #[validate(length(min = 1, max = 255))]
pub surname: String, pub surname: String,
#[validate(length(min = 1, max = 255))]
pub birth_surname: String, pub birth_surname: String,
#[validate(length(min = 1, max = 255))] #[validate(length(min = 1, max = 255))]
pub birthplace: String, pub birthplace: String,
// NaiveDate validated natively
pub birthdate: NaiveDate, pub birthdate: NaiveDate,
#[validate(length(min = 1, max = 255))] #[validate(length(min = 1, max = 255))]
pub address: String, pub address: String,
@ -91,6 +91,7 @@ pub struct CandidateDetails {
pub grades: GradeList, pub grades: GradeList,
pub first_school: School, pub first_school: School,
pub second_school: School, pub second_school: School,
#[validate(length(min = 1, max = 255))]
pub test_language: String, pub test_language: String,
} }
impl CandidateDetails { impl CandidateDetails {

View file

@ -1,7 +1,7 @@
{ {
"baseLocale": "cs", "baseLocale": "cs",
"adapter": "svelte", "adapter": "svelte",
"esmImports": true, "esmImports": true,
"outputPath": "./src/translations", "outputPath": "./src/translations",
"$schema": "https://unpkg.com/typesafe-i18n@5.20.0/schema/typesafe-i18n.json" "$schema": "https://unpkg.com/typesafe-i18n@5.20.0/schema/typesafe-i18n.json"
} }

View file

@ -13,7 +13,9 @@
<div class="w-full text-lg font-semibold">{$LL.components.checkbox.gdprCheckBox.title()}</div> <div class="w-full text-lg font-semibold">{$LL.components.checkbox.gdprCheckBox.title()}</div>
<div class="w-full text-sm">{$LL.components.checkbox.gdprCheckBox.description()}</div> <div class="w-full text-sm">{$LL.components.checkbox.gdprCheckBox.description()}</div>
<div class="w-full text-sm"><a class="underline" href="/gdpr">{$LL.components.checkbox.gdprCheckBox.here()}</a></div> <div class="w-full text-sm">
<a class="underline" href="/gdpr">{$LL.components.checkbox.gdprCheckBox.here()}</a>
</div>
</div> </div>
</label> </label>

View file

@ -5,10 +5,10 @@
export let personalIdErr: boolean = false; export let personalIdErr: boolean = false;
export let personalIdNumber: string; export let personalIdNumber: string;
let titleOk = $LL.components.checkbox.personalIdConfirmCheckBox.titleOk({ let titleOk = $LL.components.checkbox.personalIdConfirmCheckBox.titleOk({
personalId: personalIdNumber, personalId: personalIdNumber
}); });
let titleErr = $LL.components.checkbox.personalIdConfirmCheckBox.titleErr({ let titleErr = $LL.components.checkbox.personalIdConfirmCheckBox.titleErr({
personalId: personalIdNumber, personalId: personalIdNumber
}); });
export let error: string = ''; export let error: string = '';
@ -61,7 +61,9 @@
<div class="w-full text-lg font-semibold"> <div class="w-full text-lg font-semibold">
{titleErr} {titleErr}
</div> </div>
<div class="w-full text-sm">{$LL.components.checkbox.personalIdConfirmCheckBox.whatHappened()}</div> <div class="w-full text-sm">
{$LL.components.checkbox.personalIdConfirmCheckBox.whatHappened()}
</div>
</div> </div>
</label> </label>
</div> </div>

View file

@ -160,30 +160,33 @@
<span class="font-bold">{$baseCandidateData.applications[1]}</span></span <span class="font-bold">{$baseCandidateData.applications[1]}</span></span
> >
{/if} {/if}
<span>{$LL.input.address()}: <span class="font-bold">{$candidateData.candidate.address}</span></span>
<span <span
>{$LL.input.birthDate()}: <span class="font-bold">{$candidateData.candidate.birthdate}</span >{$LL.input.address()}:
></span <span class="font-bold">{$candidateData.candidate.address}</span></span
> >
<span <span
>{$LL.input.birthPlace()}: <span class="font-bold">{$candidateData.candidate.birthplace}</span >{$LL.input.birthDate()}:
></span <span class="font-bold">{$candidateData.candidate.birthdate}</span></span
> >
<span <span
>{$LL.input.personalIdentificationNumber()}: <span class="font-bold" >{$LL.input.birthPlace()}:
>{$candidateData.candidate.personalIdNumber}</span <span class="font-bold">{$candidateData.candidate.birthplace}</span></span
></span
> >
<span <span
>{$LL.input.schoolIzo()}: <span class="font-bold">{$candidateData.candidate.schoolName}</span >{$LL.input.personalIdentificationNumber()}:
></span <span class="font-bold">{$candidateData.candidate.personalIdNumber}</span></span
> >
<span <span
>{$LL.input.insuranceNumber()}: <span class="font-bold" >{$LL.input.schoolIzo()}:
>{$candidateData.candidate.healthInsurance}</span <span class="font-bold">{$candidateData.candidate.schoolName}</span></span
></span
> >
<span>{$LL.input.telephone()}: <span class="font-bold">{$candidateData.candidate.telephone}</span></span <span
>{$LL.input.insuranceNumber()}:
<span class="font-bold">{$candidateData.candidate.healthInsurance}</span></span
>
<span
>{$LL.input.telephone()}:
<span class="font-bold">{$candidateData.candidate.telephone}</span></span
> >
</div> </div>
<div <div
@ -202,7 +205,9 @@
>{parent.name + ' ' + parent.surname}</span >{parent.name + ' ' + parent.surname}</span
> >
<span>{$LL.input.email()}: <span class="font-bold">{parent.email}</span></span> <span>{$LL.input.email()}: <span class="font-bold">{parent.email}</span></span>
<span>{$LL.input.telephone()}: <span class="font-bold">{parent.telephone}</span></span> <span
>{$LL.input.telephone()}: <span class="font-bold">{parent.telephone}</span></span
>
</div> </div>
{/each} {/each}
</div> </div>

View file

@ -105,7 +105,8 @@
{#if status === 'uploaded'} {#if status === 'uploaded'}
<button <button
class="mr-3 rounded-xl bg-[#ef8b46] py-0.5 px-2 text-white shadow-md transition-all duration-300 hover:bg-orange-400" class="mr-3 rounded-xl bg-[#ef8b46] py-0.5 px-2 text-white shadow-md transition-all duration-300 hover:bg-orange-400"
on:click={debounce(() => dispatch('delete'), 150)}>{$LL.components.dashboard.dashboardUploadCard.delete()}</button on:click={debounce(() => dispatch('delete'), 150)}
>{$LL.components.dashboard.dashboardUploadCard.delete()}</button
> >
{/if} {/if}
<StatusNotificationDot {status} /> <StatusNotificationDot {status} />
@ -133,9 +134,16 @@
> >
<div class="hidden items-center xl:block"> <div class="hidden items-center xl:block">
{#if bytesTotal === 0 || Math.round(progress * 100) === 100} {#if bytesTotal === 0 || Math.round(progress * 100) === 100}
<h2 class="text-xl font-bold">{status === 'submitted' ? $LL.components.dashboard.dashboardUploadCard.sent() : $LL.components.dashboard.dashboardUploadCard.uploaded()}</h2> <h2 class="text-xl font-bold">
{status === 'submitted'
? $LL.components.dashboard.dashboardUploadCard.sent()
: $LL.components.dashboard.dashboardUploadCard.uploaded()}
</h2>
{:else} {:else}
<h2 class="text-xl">{$LL.components.dashboard.dashboardUploadCard.uploaded()} {((bytesTotal / 1_000_000) * progress).toFixed(1)} MB</h2> <h2 class="text-xl">
{$LL.components.dashboard.dashboardUploadCard.uploaded()}
{((bytesTotal / 1_000_000) * progress).toFixed(1)} MB
</h2>
<h2 class="self-center text-xl">z {(bytesTotal / 1_000_000).toFixed(1)} MB</h2> <h2 class="self-center text-xl">z {(bytesTotal / 1_000_000).toFixed(1)} MB</h2>
{/if} {/if}
</div> </div>

View file

@ -49,8 +49,8 @@
} }
.view { .view {
@apply z-10; @apply z-10;
@apply absolute top-0 right-0 bottom-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 md:top-auto md:bottom-auto md:left-auto md:m-0;
@apply md:h-screen md:w-[75vw]; @apply md:h-screen md:w-[60vw];
@apply md:my-auto; @apply md:my-auto;
@apply bg-white; @apply bg-white;
} }

View file

@ -0,0 +1,41 @@
<script lang="ts">
export let itemLabel: string;
export let highlighted: boolean;
</script>
<li class="autocomplete-items" class:autocomplete-active={highlighted} on:click on:keydown={null}>
{@html itemLabel}
</li>
<style>
li.autocomplete-items {
list-style: none;
border-bottom: 1px solid #d4d4d4;
z-index: 99;
/*position the autocomplete items to be the same width as the container:*/
top: 100%;
left: 0;
right: 0;
padding: 10px;
cursor: pointer;
background-color: #fff;
}
li.autocomplete-items:hover {
/*when hovering an item:*/
background-color: #81921f;
color: white;
}
li.autocomplete-items:active {
/*when navigating through the items using the arrow keys:*/
background-color: DodgerBlue !important;
color: #ffffff;
}
.autocomplete-active {
/*when navigating through the items using the arrow keys:*/
background-color: DodgerBlue !important;
color: #ffffff;
}
</style>

View file

@ -0,0 +1,145 @@
<script lang="ts">
import LL from '$i18n/i18n-svelte';
import schoollistString from '$lib/assets/schoollist.txt?raw';
import School from './School.svelte';
import type { School as SchoolType } from '$lib/stores/candidate';
const schoolList: Array<string> = schoollistString.split(';');
let filteredSchools: Array<string> = [];
const filterSchools = () => {
let storageArr: Array<string> = [];
if (schoolNameInputValue) {
schoolList.forEach((school) => {
if (school.toLowerCase().startsWith(schoolNameInputValue.toLowerCase())) {
storageArr = [...storageArr, makeMatchBold(school)];
}
});
}
filteredSchools = storageArr;
};
let searchInput: HTMLInputElement;
let optionsList: HTMLUListElement;
let schoolNameInputValue = '';
let schoolFieldInputValue = '';
$: if (!schoolNameInputValue) {
filteredSchools = [];
hiLiteIndex = -1;
}
const setInputVal = (schoolName: string) => {
schoolNameInputValue = removeBold(schoolName);
filteredSchools = [];
hiLiteIndex = -1;
searchInput.focus();
};
const makeMatchBold = (str: string) => {
let matched = str.substring(0, schoolNameInputValue.length);
let makeBold = `<strong>${matched}</strong>`;
let boldedMatch = str.replace(matched, makeBold);
return boldedMatch;
};
const removeBold = (str: string) => {
return str.replace(/<(.)*?>/g, '');
};
let hiLiteIndex: number = 0;
const navigateList = (e: KeyboardEvent) => {
if (e.key === 'ArrowDown') {
if (hiLiteIndex < filteredSchools.length - 1) {
hiLiteIndex++;
// scroll optionsList
let option = optionsList.children[hiLiteIndex];
if (option) {
option.scrollIntoView({ block: 'nearest' });
}
}
} else if (e.key === 'ArrowUp') {
if (hiLiteIndex > 0) {
hiLiteIndex--;
}
} else if (e.key === 'Enter') {
if (hiLiteIndex > -1) {
setInputVal(filteredSchools[hiLiteIndex]);
}
}
};
export let selectedSchool: SchoolType;
export let error: string = '';
schoolFieldInputValue = selectedSchool.field;
schoolNameInputValue = selectedSchool.name;
$: selectedSchool.field = schoolFieldInputValue;
$: selectedSchool.name = schoolNameInputValue;
</script>
<svelte:window on:keydown={navigateList} />
<div class="autocomplete">
<div class="flex">
<input
class:error
class="flex-1"
type="text"
bind:this={searchInput}
bind:value={schoolNameInputValue}
on:input={filterSchools}
placeholder={$LL.input.schoolName()}
/>
<input
class:error
class="ml-2 w-2/5"
type="text"
bind:value={schoolFieldInputValue}
placeholder={$LL.input.fieldOfStudy()}
/>
</div>
{#if filteredSchools.length > 0}
<ul bind:this={optionsList} class="schoolAutocompleteList">
{#each filteredSchools as country, i}
<School
itemLabel={country}
highlighted={i === hiLiteIndex}
on:click={() => setInputVal(country)}
/>
{/each}
</ul>
{/if}
</div>
<style lang="postcss">
div,
input {
@apply w-full;
}
div {
@apply relative flex items-center justify-center;
}
input {
@apply hover:border-sspsBlue w-full rounded-lg border border-2 bg-[#f8fafb] p-3 text-xl shadow-lg outline-none transition-colors duration-300;
}
.error {
@apply border-red-700;
}
.autocomplete {
@apply relative;
}
.schoolAutocompleteList {
@apply absolute top-20 z-50;
@apply w-full;
@apply max-h-72 overflow-scroll;
}
</style>

View file

@ -1,7 +1,6 @@
import type { GradeBackend } from '$lib/components/grades/GradesTable.svelte'; import type { GradeBackend } from '$lib/components/grades/GradesTable.svelte';
import { writable } from 'svelte/store'; import { writable } from 'svelte/store';
export interface School { export interface School {
name: string; name: string;
field: string; field: string;
@ -90,8 +89,8 @@ export const candidateData = writable<CandidateData>({
schoolName: '', schoolName: '',
healthInsurance: '', healthInsurance: '',
grades: [], grades: [],
firstSchool: {name: '', field: ''}, firstSchool: { name: '', field: '' },
secondSchool: {name: '', field: ''}, secondSchool: { name: '', field: '' },
testLanguage: '' testLanguage: ''
}, },
parents: [] parents: []

View file

@ -1,73 +1,78 @@
// TODO: nefunguje pro lidi nar. pred 1.1.1954 :D // TODO: nefunguje pro lidi nar. pred 1.1.1954 :D
export const isPersonalIdNumberValid = (personalIdNumber: string): boolean => { export const isPersonalIdNumberValid = (personalIdNumber: string): boolean => {
const idFmt = personalIdNumber.split('/').join(''); const idFmt = personalIdNumber.split('/').join('');
const lastDigitCheck = const lastDigitCheck =
Number(idFmt.slice(0, 9)) % 11 === Number(idFmt.at(-1)) || 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;
if (lastDigitCheck && divisibleBy11) { if (lastDigitCheck && divisibleBy11) {
return true; return true;
} else { } else {
return false; return false;
} }
}; };
export const isPersonalIdNumberWithBirthdateValid = ( export const isPersonalIdNumberWithBirthdateValid = (
personalIdNumber: string, personalIdNumber: string,
birthdate: string birthdate: string
): boolean => { ): 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.split('/').join(''); const idFmt = personalIdNumber.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 = const monthValid =
idMonth === dateMonth || idMonth === dateMonth ||
idMonth === dateMonth + 50 || idMonth === dateMonth + 50 ||
idMonth === dateMonth + 20 || idMonth === dateMonth + 20 ||
idMonth === dateMonth + 70; idMonth === dateMonth + 70;
if ( if (
idFmt.slice(0, 2) === dateFmt.slice(0, 2) && idFmt.slice(0, 2) === dateFmt.slice(0, 2) &&
monthValid && monthValid &&
idFmt.slice(4, 6) === dateFmt.slice(4, 6) && idFmt.slice(4, 6) === dateFmt.slice(4, 6) &&
divisionValid divisionValid
) { ) {
return true; return true;
} else { } else {
return false; return false;
} }
}; };
export const deriveBirthdateFromPersonalId = (personalIdNumber: string): export const deriveBirthdateFromPersonalId = (
[birthdate: string, sex: 'MUŽ' | 'ŽENA'] => { personalIdNumber: string
const year = Number(personalIdNumber.slice(0, 2)); ): [birthdate: string, sex: 'MUŽ' | 'ŽENA'] => {
const idMonth = Number(personalIdNumber.slice(2, 4)); const year = Number(personalIdNumber.slice(0, 2));
let month; const idMonth = Number(personalIdNumber.slice(2, 4));
let sex: 'MUŽ' | 'ŽENA'; let month;
if (idMonth > 12 && idMonth <= 32) { let sex: 'MUŽ' | 'ŽENA';
month = idMonth - 20; if (idMonth > 12 && idMonth <= 32) {
sex = 'MUŽ'; month = idMonth - 20;
} else if (idMonth > 50 && idMonth <= 52) { sex = 'MUŽ';
month = idMonth - 50; } else if (idMonth > 50 && idMonth <= 52) {
sex = 'ŽENA'; month = idMonth - 50;
} else if (idMonth > 70 && idMonth <= 82) { sex = 'ŽENA';
month = idMonth - 70; } else if (idMonth > 70 && idMonth <= 82) {
sex = 'ŽENA'; month = idMonth - 70;
} else { sex = 'ŽENA';
month = idMonth; } else {
sex = 'MUŽ'; month = idMonth;
}; sex = 'MUŽ';
const day = Number(personalIdNumber.slice(4, 6)); }
const day = Number(personalIdNumber.slice(4, 6));
const birthdate = `${day}.${month}.${year}`;
return [birthdate, sex];
};
const birthdate = `${day}.${month}.${year}`; const birthdate = `${day}.${month}.${year}`;
return [birthdate, sex]; return [birthdate, sex];

View file

@ -23,8 +23,8 @@ export const load: PageServerLoad = async ({ fetch, params }) => {
schoolName: '', schoolName: '',
healthInsurance: '', healthInsurance: '',
grades: [], grades: [],
firstSchool: {name: '', field: ''}, firstSchool: { name: '', field: '' },
secondSchool: {name: '', field: ''}, secondSchool: { name: '', field: '' },
testLanguage: '' testLanguage: ''
}, },
parents: [] parents: []

View file

@ -111,6 +111,7 @@
.string() .string()
.required() .required()
.matches(/^([0-3]?[0-9])\.(0?[1-9]|1[0-2])\.[0-9]{4}$/), .matches(/^([0-3]?[0-9])\.(0?[1-9]|1[0-2])\.[0-9]{4}$/),
birthSurname: yup.string().required(),
sex: yup.string(), sex: yup.string(),
address: yup.string(), address: yup.string(),
street: yup.string().required(), street: yup.string().required(),
@ -136,16 +137,17 @@
semester: yup.string().required() semester: yup.string().required()
}) })
.required() .required()
).required(), )
.required(),
firstSchool: yup.object().shape({ firstSchool: yup.object().shape({
name: yup.string().required(), name: yup.string().required(),
field: yup.string().required(), field: yup.string().required()
}), }),
secondSchool: yup.object().shape({ secondSchool: yup.object().shape({
name: yup.string().required(), name: yup.string().required(),
field: yup.string().required(), field: yup.string().required()
}), }),
testLanguage: yup.string().required(), testLanguage: yup.string().required()
}), }),
parents: yup.array().of( parents: yup.array().of(
yup.object().shape({ yup.object().shape({
@ -186,7 +188,12 @@
unknown unknown
> >
? { ? {
[K2 in keyof (typeof formInitialValues)[K]]: string; [K2 in keyof (typeof formInitialValues)[K]]: (typeof formInitialValues)[K][K2] extends Record<
string,
unknown
>
? { [K4 in keyof (typeof formInitialValues)[K][K2]]: string }
: string;
} }
: (typeof formInitialValues)[K] extends Array<Record<string, unknown>> : (typeof formInitialValues)[K] extends Array<Record<string, unknown>>
? Array<{ [K3 in keyof (typeof formInitialValues)[K][number]]: string }> ? Array<{ [K3 in keyof (typeof formInitialValues)[K][number]]: string }>
@ -277,7 +284,7 @@
const isPageInvalid = (index: number): boolean => { const isPageInvalid = (index: number): boolean => {
switch (index) { switch (index) {
case 0: case 0:
if ($typedErrors['personalIdOk'] || $typedErrors['personalIdErr']) { if ($typedErrors['personalIdOk'] || $typedErrors['personalIdErr']) {
return true; return true;
} }
break; break;
@ -363,7 +370,7 @@
return '+' + telephone.match(/[0-9]{1,3}/g)!.join(' '); return '+' + telephone.match(/[0-9]{1,3}/g)!.join(' ');
}; };
// TODO
/* $form.candidate.personalIdNumber = data.whoami.personalIdNumber; /* $form.candidate.personalIdNumber = data.whoami.personalIdNumber;
const [birthdate, sex] = deriveBirthdateFromPersonalId(data.whoami.personalIdNumber); const [birthdate, sex] = deriveBirthdateFromPersonalId(data.whoami.personalIdNumber);
$form.candidate.birthdate = birthdate; $form.candidate.birthdate = birthdate;
@ -376,6 +383,7 @@
details.parents.map( details.parents.map(
(x) => (x.telephone = x.telephone != '' ? formatTelephone(x.telephone) : '') (x) => (x.telephone = x.telephone != '' ? formatTelephone(x.telephone) : '')
); );
form.set({ form.set({
gdpr: true, gdpr: true,
linkOk: true, linkOk: true,
@ -414,16 +422,12 @@
<SvelteToast /> <SvelteToast />
<div class="form relative bg-center"> <div class="form relative bg-center">
<div class="bottom-5/24 absolute flex w-full flex-col md:h-auto"> <div class="bottom-5/24 absolute flex w-full flex-col md:h-auto">
<!-- TODO: Find different way how to display SchoolBadge --> <div class="<md:hidden self-center">
{#if pageIndex !== 0 && pageIndex !== 7} <SchoolBadge />
<div class="<md:h-24 <md:w-24 h-32 w-32 self-center"> </div>
<SchoolBadge />
</div>
{/if}
<form on:submit={handleSubmit} id="triggerForm" class="invisible hidden" /> <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">{$LL.candidate.register.first.title()}</h1>
<h1 class="title mt-8">{$LL.candidate.register.first.title()}</h1> <h1 class="title mt-8">{$LL.candidate.register.first.title()}</h1>
<p class="description mt-8 block text-center"> <p class="description mt-8 block text-center">
{$LL.candidate.register.first.description()} {$LL.candidate.register.first.description()}
@ -475,17 +479,18 @@
<div class="field flex"> <div class="field flex">
<span class="w-[50%]"> <span class="w-[50%]">
<NameField <NameField
error={$typedErrors['candidate']['name'] || $typedErrors['candidate']['surname']} error={$typedErrors['candidate']['name'] ||
$typedErrors['candidate']['surname']}
bind:valueName={$form.candidate.name} bind:valueName={$form.candidate.name}
bind:valueSurname={$form.candidate.surname} bind:valueSurname={$form.candidate.surname}
placeholder="Jméno a příjmení" placeholder={$LL.input.nameSurname()}
/> />
</span> </span>
<span class="w-[50%] ml-2"> <span class="ml-2 w-[50%]">
<TextField <TextField
error={$typedErrors['candidate']['birthSurname']} error={$typedErrors['candidate']['birthSurname']}
bind:value={$form.candidate.birthSurname} bind:value={$form.candidate.birthSurname}
placeholder="Rodné příjmení (pokud odlišné)" placeholder={$LL.input.birthSurname()}
/> />
</span> </span>
</div> </div>
@ -494,25 +499,25 @@
<EmailField <EmailField
error={$typedErrors['candidate']['email']} error={$typedErrors['candidate']['email']}
bind:value={$form.candidate.email} bind:value={$form.candidate.email}
placeholder="E-mail" placeholder={$LL.input.email()}
/> />
</span> </span>
<span class="w-[50%] ml-2"> <span class="ml-2 w-[50%]">
<TelephoneField <TelephoneField
error={$typedErrors['candidate']['telephone']} error={$typedErrors['candidate']['telephone']}
bind:value={$form.candidate.telephone} bind:value={$form.candidate.telephone}
placeholder="Telefon" placeholder={$LL.input.telephone()}
/> />
</span> </span>
</div> </div>
<span class="field"> <span class="field">
<TextField <TextField
error={$typedErrors['candidate']['city']} error={$typedErrors['candidate']['city']}
bind:value={$form.candidate.city} bind:value={$form.candidate.city}
type="text" type="text"
placeholder="Město" placeholder={$LL.input.city()}
helperText="Uveďte poštovní směrovací číslo. (např. 602 00)" helperText="Uveďte poštovní směrovací číslo. (např. 602 00)"
/> />
</span> </span>
</div> </div>
<div class="field flex"> <div class="field flex">
@ -522,7 +527,7 @@
$typedErrors['candidate']['houseNumber']} $typedErrors['candidate']['houseNumber']}
bind:valueName={$form.candidate.street} bind:valueName={$form.candidate.street}
bind:valueSurname={$form.candidate.houseNumber} bind:valueSurname={$form.candidate.houseNumber}
placeholder="Ulice a č. p." placeholder={$LL.input.address()}
helperText="Uveďte ulici a číslo popisné (např. Preslova 72)." helperText="Uveďte ulici a číslo popisné (např. Preslova 72)."
/> />
</span> </span>
@ -531,7 +536,7 @@
error={$typedErrors['candidate']['zip']} error={$typedErrors['candidate']['zip']}
bind:value={$form.candidate.zip} bind:value={$form.candidate.zip}
type="number" type="number"
placeholder="PSČ" placeholder={$LL.input.zipCode()}
helperText="Uveďte poštovní směrovací číslo. (např. 602 00)" helperText="Uveďte poštovní směrovací číslo. (např. 602 00)"
/> />
</span> </span>
@ -541,19 +546,18 @@
{:else if pageIndex === 4} {:else if pageIndex === 4}
<h1 class="title mt-8">{pageTexts[2]}</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">
Pro registraci je potřeba vyplnit několik údajů o Vás. Tyto údaje budou použity pro {$LL.candidate.register.fourth.description()}
přijímací řízení. Všechny údaje jsou důležité.
</p> </p>
<div class="field flex w-full"> <div class="field flex w-full">
<span class="w-[50%]"> <span class="w-[50%]">
<SelectField <SelectField
error={$typedErrors['candidate']['citizenship']} error={$typedErrors['candidate']['citizenship']}
bind:value={$form.candidate.citizenship} bind:value={$form.candidate.citizenship}
placeholder="Občanství" placeholder={$LL.input.citizenship()}
options={['Česká republika', 'Slovenská republika', 'Ukrajina', 'Jiné']} options={['Česká republika', 'Slovenská republika', 'Ukrajina', 'Jiné']}
/> />
</span> </span>
<span class="w-[50%] ml-2"> <span class="ml-2 w-[50%]">
<SelectField <SelectField
error={$typedErrors['candidate']['testLanguage']} error={$typedErrors['candidate']['testLanguage']}
bind:value={$form.candidate.testLanguage} bind:value={$form.candidate.testLanguage}
@ -570,13 +574,15 @@
placeholder={$LL.input.birthDate()} placeholder={$LL.input.birthDate()}
helperText="TODO: (Uveďte ve formátu DD.MM.RRRR)" helperText="TODO: (Uveďte ve formátu DD.MM.RRRR)"
/> />
<TextField <div class="ml-2">
error={$typedErrors['candidate']['birthplace']} <TextField
bind:value={$form.candidate.birthplace} error={$typedErrors['candidate']['birthplace']}
type="text" bind:value={$form.candidate.birthplace}
placeholder={$LL.input.birthPlace()} type="text"
helperText="TODO: (Místo narození)" placeholder={$LL.input.birthPlace()}
/> helperText="TODO: (Místo narození)"
/>
</div>
</div> </div>
<div class="field flex items-center justify-center"> <div class="field flex items-center justify-center">
{#if $form.candidate.citizenship === 'Česká republika' || !$form.candidate.citizenship} {#if $form.candidate.citizenship === 'Česká republika' || !$form.candidate.citizenship}
@ -608,14 +614,14 @@
error={$typedErrors['candidate']['schoolName']} error={$typedErrors['candidate']['schoolName']}
type="number" type="number"
bind:value={$form.candidate.schoolName} bind:value={$form.candidate.schoolName}
placeholder="IZO školy" placeholder={$LL.input.schoolIzo()}
/> />
{:else} {:else}
<TextField <TextField
error={$typedErrors['candidate']['schoolName']} error={$typedErrors['candidate']['schoolName']}
type="text" type="text"
bind:value={$form.candidate.schoolName} bind:value={$form.candidate.schoolName}
placeholder="Název školy" placeholder={$LL.input.schoolName()}
/> />
{/if} {/if}
</span> </span>
@ -625,11 +631,10 @@
error={$typedErrors['candidate']['healthInsurance']} error={$typedErrors['candidate']['healthInsurance']}
type="text" type="text"
bind:value={$form.candidate.healthInsurance} bind:value={$form.candidate.healthInsurance}
placeholder="Číslo zdravotní pojišťovny" placeholder={$LL.input.insuranceNumber()}
/> />
</span> </span>
</div> </div>
{:else if pageIndex === 5} {:else if pageIndex === 5}
<h1 class="title mt-8">{pageTexts[3]}</h1> <h1 class="title mt-8">{pageTexts[3]}</h1>
<p class="description mt-8 block text-center"> <p class="description mt-8 block text-center">
@ -689,13 +694,24 @@
</span> </span>
</div> </div>
{:else if pageIndex === 7} {:else if pageIndex === 7}
<h1 class="title mt-8">Přihlášky na školy</h1> <h1 class="title mt-8">{pageTexts[5]}</h1>
<div class="flex flex-col justify-between h-full"> <p class="description my-8 block text-center">
<span> {$LL.candidate.register.seventh.description()}
<SchoolSelect bind:selectedSchool={$form.candidate.firstSchool}></SchoolSelect> </p>
<div class="flex h-full flex-col justify-between">
<span class="field">
<SchoolSelect
error={$typedErrors['candidate']['firstSchool']['name'] ||
$typedErrors['candidate']['firstSchool']['field']}
bind:selectedSchool={$form.candidate.firstSchool}
/>
</span> </span>
<span class="mt-10 w-full"> <span class="field mt-10">
<SchoolSelect bind:selectedSchool={$form.candidate.secondSchool}></SchoolSelect> <SchoolSelect
error={$typedErrors['candidate']['secondSchool']['name'] ||
$typedErrors['candidate']['secondSchool']['field']}
bind:selectedSchool={$form.candidate.secondSchool}
/>
</span> </span>
</div> </div>
{:else if pageIndex === 8} {:else if pageIndex === 8}

View file

@ -25,7 +25,11 @@
{$LL.candidate.auth.login.description()} {$LL.candidate.auth.login.description()}
</p> </p>
<div class="w-4/5 lg:w-3/5"> <div class="w-4/5 lg:w-3/5">
<TextField bind:value={applicationValue} placeholder={$LL.input.evidenceNumber()} type="number" /> <TextField
bind:value={applicationValue}
placeholder={$LL.input.evidenceNumber()}
type="number"
/>
</div> </div>
<div class="mt-8 w-4/5 lg:w-3/5"> <div class="mt-8 w-4/5 lg:w-3/5">
<Submit on:click={redirectToCode} value={$LL.input.submit()} /> <Submit on:click={redirectToCode} value={$LL.input.submit()} />

View file

@ -58,9 +58,9 @@ const cs: BaseTranslation = {
'Zde můžete zadat údaje o druhém zákonném zástupci. Škole tím umožníte lépe komunikovat.' 'Zde můžete zadat údaje o druhém zákonném zástupci. Škole tím umožníte lépe komunikovat.'
}, },
seventh: { seventh: {
title: 'Dokončení registrace', title: 'Přihlášky na školy',
description: description:
'Zadejte prosím své občanství, rodné číslo, či jeho alternativu Vaší země a obor na který se hlásíte.' 'Zde můžete vyplnit přihlášky na školy v pořadí Vašeho výběru. V případě, že jste podali přihlášku na více škol, vyplňte přihlášky na školy v pořadí Vašeho výběru.'
}, },
eighth: { eighth: {
title: 'Poslední krok', title: 'Poslední krok',
@ -100,7 +100,7 @@ const cs: BaseTranslation = {
}, },
missing: { missing: {
title: 'Soubory nebyly nahrány!', title: 'Soubory nebyly nahrány!',
description: 'Nahrajte včechny soubory prosím', description: 'Nahrajte včechny soubory prosím'
} }
} }
}, },
@ -122,7 +122,7 @@ const cs: BaseTranslation = {
ok: 'Vše je v pořádku', ok: 'Vše je v pořádku',
whatHappened: 'Co se děje?', whatHappened: 'Co se děje?',
titleOk: 'Potvrzuji, že moje rodné číslo je {personalId}', titleOk: 'Potvrzuji, že moje rodné číslo je {personalId}',
titleErr: 'Ne, moje rodné číslo není {personalId}', titleErr: 'Ne, moje rodné číslo není {personalId}'
}, },
gdprCheckBox: { gdprCheckBox: {
title: 'Souhlasím se zpracováním osobních údajů', title: 'Souhlasím se zpracováním osobních údajů',
@ -134,6 +134,7 @@ const cs: BaseTranslation = {
input: { input: {
optional: 'nepovinné', optional: 'nepovinné',
nameSurname: 'Jméno a příjmení', nameSurname: 'Jméno a příjmení',
birthSurname: 'Rodné příjmení',
email: 'E-mail', email: 'E-mail',
telephone: 'Telefon', telephone: 'Telefon',
address: 'Ulice a č. p.', address: 'Ulice a č. p.',
@ -153,6 +154,8 @@ const cs: BaseTranslation = {
password: 'Heslo', password: 'Heslo',
submit: 'Odeslat', submit: 'Odeslat',
continue: 'Pokračovat', continue: 'Pokračovat',
fieldOfStudy: 'Obor',
selectedSchool: 'Vybraná škola',
parent: { parent: {
nameSurname: 'Jméno a příjmení zákonného zástupce', nameSurname: 'Jméno a příjmení zákonného zástupce',
email: 'E-mail zákonného zástupce', email: 'E-mail zákonného zástupce',

View file

@ -1,11 +1,10 @@
import type { FormattersInitializer } from 'typesafe-i18n' import type { FormattersInitializer } from 'typesafe-i18n';
import type { Locales, Formatters } from './i18n-types.js' import type { Locales, Formatters } from './i18n-types.js';
export const initFormatters: FormattersInitializer<Locales, Formatters> = (locale: Locales) => { export const initFormatters: FormattersInitializer<Locales, Formatters> = (locale: Locales) => {
const formatters: Formatters = { const formatters: Formatters = {
// add your formatter functions here // add your formatter functions here
} };
return formatters return formatters;
} };

View file

@ -129,11 +129,11 @@ type RootTranslation = {
} }
seventh: { seventh: {
/** /**
* Dokončení registrace * Přihlášky na školy
*/ */
title: string title: string
/** /**
* Zadejte prosím své občanství, rodné číslo, či jeho alternativu Vaší země a obor na který se hlásíte. * Zde můžete vyplnit přihlášky na školy v pořadí Vašeho výběru. V případě, že jste podali přihlášku na více škol, vyplňte přihlášky na školy v pořadí Vašeho výběru.
*/ */
description: string description: string
} }
@ -317,6 +317,10 @@ type RootTranslation = {
* Jméno a příjmení * Jméno a příjmení
*/ */
nameSurname: string nameSurname: string
/**
* Rodné příjmení
*/
birthSurname: string
/** /**
* E-mail * E-mail
*/ */
@ -393,6 +397,14 @@ type RootTranslation = {
* Pokračovat * Pokračovat
*/ */
'continue': string 'continue': string
/**
* Obor
*/
fieldOfStudy: string
/**
* Vybraná škola
*/
selectedSchool: string
parent: { parent: {
/** /**
* Jméno a příjmení zákonného zástupce * Jméno a příjmení zákonného zástupce
@ -527,11 +539,11 @@ export type TranslationFunctions = {
} }
seventh: { seventh: {
/** /**
* Dokončení registrace * Přihlášky na školy
*/ */
title: () => LocalizedString title: () => LocalizedString
/** /**
* Zadejte prosím své občanství, rodné číslo, či jeho alternativu Vaší země a obor na který se hlásíte. * Zde můžete vyplnit přihlášky na školy v pořadí Vašeho výběru. V případě, že jste podali přihlášku na více škol, vyplňte přihlášky na školy v pořadí Vašeho výběru.
*/ */
description: () => LocalizedString description: () => LocalizedString
} }
@ -708,6 +720,10 @@ export type TranslationFunctions = {
* Jméno a příjmení * Jméno a příjmení
*/ */
nameSurname: () => LocalizedString nameSurname: () => LocalizedString
/**
* Rodné příjmení
*/
birthSurname: () => LocalizedString
/** /**
* E-mail * E-mail
*/ */
@ -784,6 +800,14 @@ export type TranslationFunctions = {
* Pokračovat * Pokračovat
*/ */
'continue': () => LocalizedString 'continue': () => LocalizedString
/**
* Obor
*/
fieldOfStudy: () => LocalizedString
/**
* Vybraná škola
*/
selectedSchool: () => LocalizedString
parent: { parent: {
/** /**
* Jméno a příjmení zákonného zástupce * Jméno a příjmení zákonného zástupce

View file

@ -1,6 +1,6 @@
import adapter from '@sveltejs/adapter-node'; import adapter from '@sveltejs/adapter-node';
import preprocess from 'svelte-preprocess'; import preprocess from 'svelte-preprocess';
import path from "path"; import path from 'path';
import { windi } from 'svelte-windicss-preprocess'; import { windi } from 'svelte-windicss-preprocess';
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
@ -11,9 +11,8 @@ const config = {
kit: { kit: {
adapter: adapter({ out: 'build' }), adapter: adapter({ out: 'build' }),
alias: { alias: {
$i18n: path.resolve('./src/translations'), $i18n: path.resolve('./src/translations')
} }
} }
}; };

View file

@ -9,6 +9,6 @@
"resolveJsonModule": true, "resolveJsonModule": true,
"skipLibCheck": true, "skipLibCheck": true,
"sourceMap": true, "sourceMap": true,
"strict": true, "strict": true
} }
} }