mirror of
https://github.com/danbulant/Portfolio
synced 2026-05-27 14:02:14 +00:00
Merge pull request #193 from EETagent/frontend_prod_form
Frontend prod form
This commit is contained in:
commit
dce07ce2cb
22 changed files with 3115 additions and 131 deletions
|
|
@ -54,7 +54,6 @@ export const apiFetchSubmissionProgress = async (fetchSsr?: Fetch): Promise<Subm
|
||||||
export const apiWhoami = async (fetchSsr?: Fetch): Promise<BaseCandidate> => {
|
export const apiWhoami = async (fetchSsr?: Fetch): Promise<BaseCandidate> => {
|
||||||
const apiFetch = fetchSsr || fetch;
|
const apiFetch = fetchSsr || fetch;
|
||||||
try {
|
try {
|
||||||
console.log(API_URL + '/candidate/whoami');
|
|
||||||
const res = await apiFetch(API_URL + '/candidate/whoami', {
|
const res = await apiFetch(API_URL + '/candidate/whoami', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
credentials: 'include'
|
credentials: 'include'
|
||||||
|
|
@ -100,7 +99,6 @@ export const apiFillDetails = async (data: CandidateData): Promise<CandidateData
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(data);
|
|
||||||
try {
|
try {
|
||||||
const res = await axios.post(API_URL + '/candidate/details', data, { withCredentials: true });
|
const res = await axios.post(API_URL + '/candidate/details', data, { withCredentials: true });
|
||||||
return res.data;
|
return res.data;
|
||||||
|
|
|
||||||
195
frontend/src/lib/assets/list/countries.json
Normal file
195
frontend/src/lib/assets/list/countries.json
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
[
|
||||||
|
"Česká republika",
|
||||||
|
"Slovenská republika",
|
||||||
|
"Ukrajina",
|
||||||
|
"Afghánistán",
|
||||||
|
"Albánie",
|
||||||
|
"Alžírsko",
|
||||||
|
"Andorra",
|
||||||
|
"Angola",
|
||||||
|
"a Antigua Barbuda",
|
||||||
|
"Argentina",
|
||||||
|
"Arménie",
|
||||||
|
"Austrálie",
|
||||||
|
"Ázerbájdžán",
|
||||||
|
"Bahamy",
|
||||||
|
"Bahrajn",
|
||||||
|
"Bangladéš",
|
||||||
|
"Barbados",
|
||||||
|
"Belgie",
|
||||||
|
"Belize",
|
||||||
|
"Bělorusko",
|
||||||
|
"Benin",
|
||||||
|
"Bhútán",
|
||||||
|
"Bolívie",
|
||||||
|
"Hercegovina a Bosna",
|
||||||
|
"Botswana",
|
||||||
|
"Brazílie",
|
||||||
|
"Brunej",
|
||||||
|
"Bulharsko",
|
||||||
|
"Faso Burkina",
|
||||||
|
"Burundi",
|
||||||
|
"Čad",
|
||||||
|
"Černá Hora",
|
||||||
|
"Čína",
|
||||||
|
"Dánsko",
|
||||||
|
"Dominika",
|
||||||
|
"republika Dominikánská",
|
||||||
|
"Džibutsko",
|
||||||
|
"Egypt",
|
||||||
|
"Ekvádor",
|
||||||
|
"Eritrea",
|
||||||
|
"Estonsko",
|
||||||
|
"Etiopie",
|
||||||
|
"Fidži",
|
||||||
|
"Filipíny",
|
||||||
|
"Finsko",
|
||||||
|
"Francie",
|
||||||
|
"Gabon",
|
||||||
|
"Gambie",
|
||||||
|
"Ghana",
|
||||||
|
"Grenada",
|
||||||
|
"Gruzie",
|
||||||
|
"Guatemala",
|
||||||
|
"Guinea",
|
||||||
|
"Guinea-Bissau",
|
||||||
|
"Guyana",
|
||||||
|
"Haiti",
|
||||||
|
"Honduras",
|
||||||
|
"Chile",
|
||||||
|
"Chorvatsko",
|
||||||
|
"Indie",
|
||||||
|
"Indonésie",
|
||||||
|
"Irák",
|
||||||
|
"Írán",
|
||||||
|
"Irsko",
|
||||||
|
"Island",
|
||||||
|
"Itálie",
|
||||||
|
"Izrael",
|
||||||
|
"Jamajka",
|
||||||
|
"Japonsko",
|
||||||
|
"Jemen",
|
||||||
|
"Jižní Afrika",
|
||||||
|
"Jižní Korea",
|
||||||
|
"Jižní Súdán",
|
||||||
|
"Jordánsko",
|
||||||
|
"Kambodža",
|
||||||
|
"Kamerun",
|
||||||
|
"Kanada",
|
||||||
|
"Kapverdy",
|
||||||
|
"Katar",
|
||||||
|
"Kazachstán",
|
||||||
|
"Keňa",
|
||||||
|
"Kiribati",
|
||||||
|
"Kolumbie",
|
||||||
|
"Komory",
|
||||||
|
"Konžská republika",
|
||||||
|
"Konžská demokratická republika",
|
||||||
|
"Kostarika",
|
||||||
|
"Kuba",
|
||||||
|
"Kuvajt",
|
||||||
|
"Kypr",
|
||||||
|
"Kyrgyzstán",
|
||||||
|
"Laos",
|
||||||
|
"Lesotho",
|
||||||
|
"Libanon",
|
||||||
|
"Libérie",
|
||||||
|
"Libye",
|
||||||
|
"Lichtenštejnsko",
|
||||||
|
"Litva",
|
||||||
|
"Lotyšsko",
|
||||||
|
"Lucembursko",
|
||||||
|
"Madagaskar",
|
||||||
|
"Maďarsko",
|
||||||
|
"Malajsie",
|
||||||
|
"Malawi",
|
||||||
|
"Maledivy",
|
||||||
|
"Mali",
|
||||||
|
"Malta",
|
||||||
|
"Maroko",
|
||||||
|
"Marshallovy ostrovy",
|
||||||
|
"Mauricius",
|
||||||
|
"Mauritánie",
|
||||||
|
"Mexiko",
|
||||||
|
"Mikronésie",
|
||||||
|
"Moldavsko",
|
||||||
|
"Monako",
|
||||||
|
"Mongolsko",
|
||||||
|
"Mosambik",
|
||||||
|
"Myanmar (Barma)",
|
||||||
|
"Namibie",
|
||||||
|
"Nauru",
|
||||||
|
"Německo",
|
||||||
|
"Nepál",
|
||||||
|
"Niger",
|
||||||
|
"Nigérie",
|
||||||
|
"Nikaragua",
|
||||||
|
"Nizozemsko",
|
||||||
|
"Norsko",
|
||||||
|
"Zéland Nový",
|
||||||
|
"Omán",
|
||||||
|
"Pákistán",
|
||||||
|
"Palau",
|
||||||
|
"Panama",
|
||||||
|
"Papua Nová Guinea",
|
||||||
|
"Paraguay",
|
||||||
|
"Peru",
|
||||||
|
"Pobřeží slonoviny",
|
||||||
|
"Polsko",
|
||||||
|
"Portugalsko",
|
||||||
|
"Rakousko",
|
||||||
|
"Rovníková Guinea",
|
||||||
|
"Rumunsko",
|
||||||
|
"Rusko",
|
||||||
|
"Rwanda",
|
||||||
|
"Řecko",
|
||||||
|
"Salvador",
|
||||||
|
"Samoa",
|
||||||
|
"Marino San",
|
||||||
|
"Saúdská Arábie",
|
||||||
|
"Senegal",
|
||||||
|
"Korea Severní",
|
||||||
|
"Makedonie Severní",
|
||||||
|
"Seychely",
|
||||||
|
"Sierra Leone",
|
||||||
|
"Singapur",
|
||||||
|
"Slovinsko",
|
||||||
|
"Somálsko",
|
||||||
|
"arabské emiráty Spojené",
|
||||||
|
"království Spojené",
|
||||||
|
"americké státy Spojené",
|
||||||
|
"Srbsko",
|
||||||
|
"republika Středoafrická",
|
||||||
|
"Súdán",
|
||||||
|
"Surinam",
|
||||||
|
"Lucie Svatá",
|
||||||
|
"a Nevis Svatý Kryštof",
|
||||||
|
"Princův Svatý a ostrov Tomáš",
|
||||||
|
"Vincenc a Grenadiny Svatý",
|
||||||
|
"Svazijsko",
|
||||||
|
"Sýrie",
|
||||||
|
"Šalomounovy ostrovy",
|
||||||
|
"Španělsko",
|
||||||
|
"Šrí",
|
||||||
|
"Švédsko",
|
||||||
|
"Švýcarsko",
|
||||||
|
"Tádžikistán",
|
||||||
|
"Tanzanie",
|
||||||
|
"Thajsko",
|
||||||
|
"Togo",
|
||||||
|
"Tonga",
|
||||||
|
"a Trinidad Tobago",
|
||||||
|
"Tunisko",
|
||||||
|
"Turecko",
|
||||||
|
"Turkmenistán",
|
||||||
|
"Tuvalu",
|
||||||
|
"Uganda",
|
||||||
|
"Uruguay",
|
||||||
|
"Uzbekistán",
|
||||||
|
"Vanuatu",
|
||||||
|
"Venezuela",
|
||||||
|
"Vietnam",
|
||||||
|
"Timor Východní",
|
||||||
|
"Zambie",
|
||||||
|
"Zimbabwe"
|
||||||
|
]
|
||||||
1330
frontend/src/lib/assets/list/high_schools.json
Normal file
1330
frontend/src/lib/assets/list/high_schools.json
Normal file
File diff suppressed because it is too large
Load diff
1291
frontend/src/lib/assets/list/school.json
Normal file
1291
frontend/src/lib/assets/list/school.json
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -1,6 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { apiGetCandidatePortfolio, apiResetCandidatePassword } from '$lib/@api/admin';
|
import { apiGetCandidatePortfolio, apiResetCandidatePassword } from '$lib/@api/admin';
|
||||||
import type { CandidateData } from '$lib/stores/candidate';
|
import type { CandidateData } from '$lib/stores/candidate';
|
||||||
|
import { SvelteToast, toast } from '@zerodevx/svelte-toast';
|
||||||
|
|
||||||
export let id: number;
|
export let id: number;
|
||||||
export let candidateData: CandidateData;
|
export let candidateData: CandidateData;
|
||||||
|
|
@ -13,7 +14,13 @@
|
||||||
const res = await apiResetCandidatePassword(id);
|
const res = await apiResetCandidatePassword(id);
|
||||||
alert('Nove heslo: ' + res.password);
|
alert('Nove heslo: ' + res.password);
|
||||||
} catch {
|
} catch {
|
||||||
console.log('error');
|
toast.push('Rodné číslo neodpovídá oficiální specifikaci či datumu narození', {
|
||||||
|
theme: {
|
||||||
|
'--toastColor': 'mintcream',
|
||||||
|
'--toastBackground': '#b91c1c',
|
||||||
|
'--toastBarBackground': '#7f1d1d'
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,11 +34,18 @@
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
toast.push('Rodné číslo neodpovídá oficiální specifikaci či datumu narození', {
|
||||||
|
theme: {
|
||||||
|
'--toastColor': 'mintcream',
|
||||||
|
'--toastBackground': '#b91c1c',
|
||||||
|
'--toastBarBackground': '#7f1d1d'
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<SvelteToast />
|
||||||
<div class="flex h-screen w-full items-center justify-center">
|
<div class="flex h-screen w-full items-center justify-center">
|
||||||
<div class="mr-8 max-w-sm">
|
<div class="mr-8 max-w-sm">
|
||||||
<div class="rounded-lg bg-white p-10 shadow-xl">
|
<div class="rounded-lg bg-white p-10 shadow-xl">
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
|
export let enterAllowed: boolean;
|
||||||
export let value: string;
|
export let value: string;
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
if (e.key === 'Enter') {
|
if (enterAllowed && e.key === 'Enter') {
|
||||||
dispatch('click');
|
dispatch('click');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
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';
|
||||||
|
import { pushErrorText } from '$lib/utils/toast';
|
||||||
|
|
||||||
export let title: string;
|
export let title: string;
|
||||||
export let status: Status;
|
export let status: Status;
|
||||||
|
|
@ -62,7 +63,7 @@
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
pushErrorText("Chyba při stahování portfolia");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,10 @@
|
||||||
|
|
||||||
$: if ($submissionProgress) {
|
$: if ($submissionProgress) {
|
||||||
status = getStatus();
|
status = getStatus();
|
||||||
// console.log('type' + fileType + ' status: ' + status);
|
|
||||||
fileDropped = status === 'uploaded' || status === 'submitted';
|
fileDropped = status === 'uploaded' || status === 'submitted';
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStatus = (): Status => {
|
const getStatus = (): Status => {
|
||||||
console.log($submissionProgress);
|
|
||||||
switch ($submissionProgress.status) {
|
switch ($submissionProgress.status) {
|
||||||
case UploadStatus.None:
|
case UploadStatus.None:
|
||||||
return 'missing';
|
return 'missing';
|
||||||
|
|
@ -71,7 +69,6 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFileDrop = (dropped: Files) => {
|
const onFileDrop = (dropped: Files) => {
|
||||||
console.log(dropped);
|
|
||||||
if (dropped.accepted.length > 0) {
|
if (dropped.accepted.length > 0) {
|
||||||
fileDropped = true;
|
fileDropped = true;
|
||||||
const file = dropped.accepted[0];
|
const file = dropped.accepted[0];
|
||||||
|
|
@ -79,7 +76,6 @@
|
||||||
dispatch('filedrop', {
|
dispatch('filedrop', {
|
||||||
file: file,
|
file: file,
|
||||||
callback: (progressEvent: AxiosProgressEvent) => {
|
callback: (progressEvent: AxiosProgressEvent) => {
|
||||||
console.log(progressEvent.bytes);
|
|
||||||
progress = progressEvent.progress!;
|
progress = progressEvent.progress!;
|
||||||
bytesTotal = progressEvent.total ?? 0;
|
bytesTotal = progressEvent.total ?? 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,15 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
export let grade: Grade;
|
export let grade: Grade;
|
||||||
const SEMESTERS: Semester[] = ['1/8', '2/8', '1/9', '2/9'];
|
const SEMESTERS: Semester[] = ['1/8', '2/8', '1/9', '2/9'];
|
||||||
|
|
||||||
|
const deleteRow = () => {
|
||||||
|
dispatch('delete');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
|
|
@ -25,6 +32,23 @@
|
||||||
<option value="5">5</option>
|
<option value="5">5</option>
|
||||||
</select>
|
</select>
|
||||||
{/each}
|
{/each}
|
||||||
|
<!-- delete button with 'x' icon -->
|
||||||
|
<button on:click={deleteRow} class="ml-0.5 h-6 w-6">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
class="h-6 w-6 stroke-red-700"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-width="2"
|
||||||
|
d="M6 18L18 6M6 6l12 12"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="mx-auto mt-8 flex text-gray-400 lg:w-4/5">
|
<div class="mx-auto mt-8 flex pr-6 text-gray-400 lg:w-4/5">
|
||||||
<span class="w-1/2 text-center">Známky</span>
|
<span class="w-1/2 text-center">Předmět</span>
|
||||||
<span class="ml-0.5 w-1/6 text-center">1/8</span>
|
<span class="ml-0.5 w-1/6 text-center">1/8</span>
|
||||||
<span class="ml-0.5 w-1/6 text-center">2/8</span>
|
<span class="ml-0.5 w-1/6 text-center">2/8</span>
|
||||||
<span class="ml-0.5 w-1/6 text-center">1/9</span>
|
<span class="ml-0.5 w-1/6 text-center">1/9</span>
|
||||||
|
|
@ -92,6 +92,10 @@
|
||||||
on:keyup={convertGradeToGradeBackend}
|
on:keyup={convertGradeToGradeBackend}
|
||||||
on:change={convertGradeToGradeBackend}
|
on:change={convertGradeToGradeBackend}
|
||||||
bind:grade={gradesLocal[i]}
|
bind:grade={gradesLocal[i]}
|
||||||
|
on:delete={() => {
|
||||||
|
grades = grades.filter((grade) => grade.subject !== gradesLocal[i].subject);
|
||||||
|
gradesLocal = gradesLocal.filter((_, index) => index !== i);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,33 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import LL from '$i18n/i18n-svelte';
|
import LL from '$i18n/i18n-svelte';
|
||||||
|
|
||||||
import schoollistString from '$lib/assets/schoollist.txt?raw';
|
|
||||||
import School from './School.svelte';
|
import School from './School.svelte';
|
||||||
import type { School as SchoolType } from '$lib/stores/candidate';
|
import type { School as SchoolType, SchoolJson } from '$lib/stores/candidate';
|
||||||
|
import SelectField from '../SelectField.svelte';
|
||||||
|
import TextField from '$lib/components/textfield/TextField.svelte';
|
||||||
|
|
||||||
const schoolList: Array<string> = schoollistString.split(';');
|
export let schoolNames: Array<string>;
|
||||||
|
export let schoolList: Array<SchoolJson>;
|
||||||
|
|
||||||
|
let fields: Array<string> = [];
|
||||||
let filteredSchools: Array<string> = [];
|
let filteredSchools: Array<string> = [];
|
||||||
|
|
||||||
const filterSchools = () => {
|
const filterSchools = () => {
|
||||||
let storageArr: Array<string> = [];
|
let storageArr: Array<string> = [];
|
||||||
if (schoolNameInputValue) {
|
if (schoolNameInputValue) {
|
||||||
schoolList.forEach((school) => {
|
schoolNames.forEach((school) => {
|
||||||
if (school.toLowerCase().startsWith(schoolNameInputValue.toLowerCase())) {
|
if (
|
||||||
|
school
|
||||||
|
.toLowerCase()
|
||||||
|
.normalize('NFD')
|
||||||
|
.replace(/[\u0300-\u036f]/g, '')
|
||||||
|
.includes(
|
||||||
|
schoolNameInputValue
|
||||||
|
.toLowerCase()
|
||||||
|
.normalize('NFD')
|
||||||
|
.replace(/[\u0300-\u036f]/g, '')
|
||||||
|
)
|
||||||
|
) {
|
||||||
storageArr = [...storageArr, makeMatchBold(school)];
|
storageArr = [...storageArr, makeMatchBold(school)];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -26,17 +40,30 @@
|
||||||
|
|
||||||
let schoolNameInputValue = '';
|
let schoolNameInputValue = '';
|
||||||
let schoolFieldInputValue = '';
|
let schoolFieldInputValue = '';
|
||||||
|
let fieldFocusInputValue = '';
|
||||||
|
|
||||||
$: if (!schoolNameInputValue) {
|
$: if (!schoolNameInputValue) {
|
||||||
filteredSchools = [];
|
filteredSchools = [];
|
||||||
hiLiteIndex = -1;
|
hiLiteIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setFields = (schoolName: string) => {
|
||||||
|
let school = schoolList.find((school) => school.n === schoolName);
|
||||||
|
if (school) {
|
||||||
|
fields = school.f;
|
||||||
|
} else {
|
||||||
|
fields = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$: setFields(schoolNameInputValue);
|
||||||
|
|
||||||
const setInputVal = (schoolName: string) => {
|
const setInputVal = (schoolName: string) => {
|
||||||
schoolNameInputValue = removeBold(schoolName);
|
schoolNameInputValue = removeBold(schoolName);
|
||||||
filteredSchools = [];
|
filteredSchools = [];
|
||||||
hiLiteIndex = -1;
|
hiLiteIndex = -1;
|
||||||
searchInput.focus();
|
searchInput.focus();
|
||||||
|
// setFields(schoolNameInputValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeMatchBold = (str: string) => {
|
const makeMatchBold = (str: string) => {
|
||||||
|
|
@ -76,33 +103,67 @@
|
||||||
export let selectedSchool: SchoolType;
|
export let selectedSchool: SchoolType;
|
||||||
export let error: string = '';
|
export let error: string = '';
|
||||||
|
|
||||||
schoolFieldInputValue = selectedSchool.field;
|
if (selectedSchool.field.split(';').length > 1) {
|
||||||
|
console.log(selectedSchool.field);
|
||||||
|
schoolFieldInputValue = selectedSchool.field.split(';')[0];
|
||||||
|
fieldFocusInputValue = selectedSchool.field.split(';')[1];
|
||||||
|
} else {
|
||||||
|
schoolFieldInputValue = selectedSchool.field;
|
||||||
|
}
|
||||||
schoolNameInputValue = selectedSchool.name;
|
schoolNameInputValue = selectedSchool.name;
|
||||||
|
|
||||||
$: selectedSchool.field = schoolFieldInputValue;
|
$: selectedSchool.field = schoolFieldInputValue + (fieldFocusInputValue ? `;${fieldFocusInputValue}` : '');
|
||||||
$: selectedSchool.name = schoolNameInputValue;
|
$: selectedSchool.name = schoolNameInputValue;
|
||||||
|
|
||||||
|
let isSSPS = false;
|
||||||
|
$: isSSPS = schoolNameInputValue === 'Smíchovská střední průmyslová škola a gymnázium';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window on:keydown={navigateList} />
|
<svelte:window on:keydown={navigateList} />
|
||||||
|
|
||||||
<div class="autocomplete">
|
<div class="autocomplete">
|
||||||
<div class="flex">
|
<div class="flex flex-col">
|
||||||
<input
|
<input
|
||||||
class:error
|
class:error
|
||||||
class="flex-1"
|
class=""
|
||||||
type="text"
|
type="text"
|
||||||
bind:this={searchInput}
|
bind:this={searchInput}
|
||||||
bind:value={schoolNameInputValue}
|
bind:value={schoolNameInputValue}
|
||||||
on:input={filterSchools}
|
on:input={filterSchools}
|
||||||
placeholder={$LL.input.schoolName()}
|
placeholder={$LL.input.schoolName()}
|
||||||
/>
|
/>
|
||||||
<input
|
<div class="flex mt-2">
|
||||||
|
<span class="w-1/2" class:w-full={isSSPS}>
|
||||||
|
<SelectField
|
||||||
|
on:focus={() => setFields(schoolNameInputValue)}
|
||||||
|
bind:value={schoolFieldInputValue}
|
||||||
|
options={fields}
|
||||||
|
placeholder={$LL.input.fieldOfStudy()}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span class="w-1/2 ml-2" class:hidden={isSSPS}>
|
||||||
|
<TextField
|
||||||
|
bind:value={fieldFocusInputValue}
|
||||||
|
placeholder="Zaměření (jen některé školy)"
|
||||||
|
helperText="Např. Kybernetická bezpečnost, protože obor nemá svůj vlastní kód"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<!-- <select
|
||||||
|
on:focus={() => setFields(schoolNameInputValue)}
|
||||||
|
>
|
||||||
|
{#each fields as field}
|
||||||
|
<option>{field}</option>
|
||||||
|
{/each}
|
||||||
|
</select> -->
|
||||||
|
<!-- <input
|
||||||
|
on:focus={() => setFields(schoolNameInputValue)}
|
||||||
class:error
|
class:error
|
||||||
class="ml-2 w-2/5"
|
class="mt-4"
|
||||||
type="text"
|
type="text"
|
||||||
bind:value={schoolFieldInputValue}
|
bind:value={schoolFieldInputValue}
|
||||||
placeholder={$LL.input.fieldOfStudy()}
|
placeholder={$LL.input.fieldOfStudy()}
|
||||||
/>
|
/> -->
|
||||||
</div>
|
</div>
|
||||||
{#if filteredSchools.length > 0}
|
{#if filteredSchools.length > 0}
|
||||||
<ul bind:this={optionsList} class="schoolAutocompleteList">
|
<ul bind:this={optionsList} class="schoolAutocompleteList">
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
if (number !== null && number !== undefined) {
|
if (number !== null && number !== undefined) {
|
||||||
country = number.country!;
|
country = number.country!;
|
||||||
}
|
}
|
||||||
// console.log(country);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validity
|
// Validity
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
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 SchoolJson {
|
||||||
|
n: string;
|
||||||
|
f: string[];
|
||||||
|
}
|
||||||
export interface School {
|
export interface School {
|
||||||
name: string;
|
name: string;
|
||||||
field: string;
|
field: string;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ export const isPersonalIdNumberValid = (personalIdNumber: string): boolean => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isPersonalIdNumberWithBirthdateValid = (
|
export const isPersonalIdMatchingBirthdate = (
|
||||||
personalIdNumber: string,
|
personalIdNumber: string,
|
||||||
birthdate: string
|
birthdate: string
|
||||||
): boolean => {
|
): boolean => {
|
||||||
|
|
@ -48,25 +48,26 @@ export const isPersonalIdNumberWithBirthdateValid = (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deriveBirthdateFromPersonalId = (
|
export const parseBirthdateSexFromPersonalId = (
|
||||||
personalIdNumber: string
|
personalIdNumber: string
|
||||||
): [birthdate: string, sex: 'MUŽ' | 'ŽENA'] => {
|
): [birthdate: string, sex: 'Muž' | 'Žena'] => {
|
||||||
const year = Number(personalIdNumber.slice(0, 2));
|
const yearPadded = Number(personalIdNumber.slice(0, 2));
|
||||||
|
const year = yearPadded < 24 ? yearPadded + 2000 : yearPadded + 1900;
|
||||||
const idMonth = Number(personalIdNumber.slice(2, 4));
|
const idMonth = Number(personalIdNumber.slice(2, 4));
|
||||||
let month;
|
let month;
|
||||||
let sex: 'MUŽ' | 'ŽENA';
|
let sex: 'Muž' | 'Žena';
|
||||||
if (idMonth > 12 && idMonth <= 32) {
|
if (idMonth > 12 && idMonth <= 32) {
|
||||||
month = idMonth - 20;
|
month = idMonth - 20;
|
||||||
sex = 'MUŽ';
|
sex = 'Muž';
|
||||||
} else if (idMonth > 50 && idMonth <= 52) {
|
} else if (idMonth > 50 && idMonth <= 52) {
|
||||||
month = idMonth - 50;
|
month = idMonth - 50;
|
||||||
sex = 'ŽENA';
|
sex = 'Žena';
|
||||||
} else if (idMonth > 70 && idMonth <= 82) {
|
} else if (idMonth > 70 && idMonth <= 82) {
|
||||||
month = idMonth - 70;
|
month = idMonth - 70;
|
||||||
sex = 'ŽENA';
|
sex = 'Žena';
|
||||||
} else {
|
} else {
|
||||||
month = idMonth;
|
month = idMonth;
|
||||||
sex = 'MUŽ';
|
sex = 'Muž';
|
||||||
}
|
}
|
||||||
const day = Number(personalIdNumber.slice(4, 6));
|
const day = Number(personalIdNumber.slice(4, 6));
|
||||||
|
|
||||||
|
|
|
||||||
21
frontend/src/lib/utils/toast.ts
Normal file
21
frontend/src/lib/utils/toast.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { toast } from "@zerodevx/svelte-toast";
|
||||||
|
|
||||||
|
export const pushErrorText = (text: string) => {
|
||||||
|
toast.push(text, {
|
||||||
|
theme: {
|
||||||
|
'--toastColor': 'mintcream',
|
||||||
|
'--toastBackground': '#b91c1c',
|
||||||
|
'--toastBarBackground': '#7f1d1d'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const pushSuccessText = (text: string) => {
|
||||||
|
toast.push(text, {
|
||||||
|
theme: {
|
||||||
|
'--toastColor': 'mintcream',
|
||||||
|
'--toastBackground': '#047857',
|
||||||
|
'--toastBarBackground': '#064e3b'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
import bacgkround from '$lib/assets/background.jpg';
|
import bacgkround from '$lib/assets/background.jpg';
|
||||||
import Logout from '$lib/components/icons/Logout.svelte';
|
import Logout from '$lib/components/icons/Logout.svelte';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
import { pushErrorText } from '$lib/utils/toast';
|
||||||
|
import { SvelteToast } from '@zerodevx/svelte-toast';
|
||||||
|
|
||||||
export let data: PageServerData;
|
export let data: PageServerData;
|
||||||
|
|
||||||
|
|
@ -20,7 +22,7 @@
|
||||||
try {
|
try {
|
||||||
candidates = await apiListCandidates(undefined, activeFilter.filter);
|
candidates = await apiListCandidates(undefined, activeFilter.filter);
|
||||||
} catch {
|
} catch {
|
||||||
console.log('error');
|
pushErrorText('Nepodařilo se načíst uchazeče');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -93,7 +95,7 @@
|
||||||
link.setAttribute('download', 'UCHAZECI' + '.csv');
|
link.setAttribute('download', 'UCHAZECI' + '.csv');
|
||||||
link.click();
|
link.click();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
pushErrorText('Nepodařilo se stáhnout CSV');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -110,6 +112,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
<SvelteToast />
|
||||||
<header class="absolute 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" />
|
<img class="h-12 w-full object-cover blur-sm filter" src={bacgkround} alt="Background" />
|
||||||
</header>
|
</header>
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import Submit from '$lib/components/button/Submit.svelte';
|
import Submit from '$lib/components/button/Submit.svelte';
|
||||||
import PasswordField from '$lib/components/textfield/PasswordField.svelte';
|
import PasswordField from '$lib/components/textfield/PasswordField.svelte';
|
||||||
|
import { SvelteToast } from '@zerodevx/svelte-toast';
|
||||||
|
import { pushErrorText } from '$lib/utils/toast';
|
||||||
|
|
||||||
let adminIdValue = '';
|
let adminIdValue = '';
|
||||||
let adminPasswordValue = '';
|
let adminPasswordValue = '';
|
||||||
|
|
@ -19,11 +21,12 @@
|
||||||
await apiLogin({ adminId: Number(adminIdValue), password: adminPasswordValue });
|
await apiLogin({ adminId: Number(adminIdValue), password: adminPasswordValue });
|
||||||
goto('/admin/dashboard');
|
goto('/admin/dashboard');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
pushErrorText('Neplatné heslo nebo ID!');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<SvelteToast />
|
||||||
<SplitLayout backgroundImage={background} backgroundPosition="30%">
|
<SplitLayout backgroundImage={background} backgroundPosition="30%">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<div
|
<div
|
||||||
|
|
@ -44,7 +47,7 @@
|
||||||
</span>
|
</span>
|
||||||
</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 value={$LL.input.submit()} on:click={login} />
|
<Submit enterAllowed={true} value={$LL.input.submit()} on:click={login} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SplitLayout>
|
</SplitLayout>
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,26 @@
|
||||||
import parsePhoneNumber from 'libphonenumber-js';
|
import parsePhoneNumber from 'libphonenumber-js';
|
||||||
import { createForm } from 'svelte-forms-lib';
|
import { createForm } from 'svelte-forms-lib';
|
||||||
import * as yup from 'yup';
|
import * as yup from 'yup';
|
||||||
import type { CandidateData } from '$lib/stores/candidate';
|
import type { CandidateData, SchoolJson } from '$lib/stores/candidate';
|
||||||
import AccountLinkCheckBox from '$lib/components/checkbox/AccountLinkCheckBox.svelte';
|
import AccountLinkCheckBox from '$lib/components/checkbox/AccountLinkCheckBox.svelte';
|
||||||
import GradesTable from '$lib/components/grades/GradesTable.svelte';
|
import GradesTable from '$lib/components/grades/GradesTable.svelte';
|
||||||
import SchoolSelect from '$lib/components/select/SchoolSelect/SchoolSelect.svelte';
|
import SchoolSelect from '$lib/components/select/SchoolSelect/SchoolSelect.svelte';
|
||||||
import PersonalIdConfirmCheckBox from '$lib/components/checkbox/PersonalIdConfirmCheckBox.svelte';
|
import PersonalIdConfirmCheckBox from '$lib/components/checkbox/PersonalIdConfirmCheckBox.svelte';
|
||||||
import { isPersonalIdNumberWithBirthdateValid } from '$lib/utils/personalIdFormat';
|
import {
|
||||||
|
parseBirthdateSexFromPersonalId,
|
||||||
|
isPersonalIdMatchingBirthdate
|
||||||
|
} from '$lib/utils/personalIdFormat';
|
||||||
import PersonalIdErrorModal from '$lib/components/modal/PersonalIdErrorModal.svelte';
|
import PersonalIdErrorModal from '$lib/components/modal/PersonalIdErrorModal.svelte';
|
||||||
import LinkErrorModal from '$lib/components/modal/LinkErrorModal.svelte';
|
import LinkErrorModal from '$lib/components/modal/LinkErrorModal.svelte';
|
||||||
import type { Writable } from 'svelte/store';
|
import type { Writable } from 'svelte/store';
|
||||||
|
import { pushErrorText, pushSuccessText } from '$lib/utils/toast';
|
||||||
|
|
||||||
|
// import schoolList from '$lib/assets/list/school.json';
|
||||||
|
import schoolList from '$lib/assets/list/high_schools.json';
|
||||||
|
import countriesList from '$lib/assets/list/countries.json';
|
||||||
|
|
||||||
|
// const schoolList = highSchoolList.map((school) => school['n']);
|
||||||
|
const schoolNames = schoolList.map((school: SchoolJson) => school['n']);
|
||||||
|
|
||||||
let pageIndex = 0;
|
let pageIndex = 0;
|
||||||
let pagesFilled = [false, false, false, false, false, false, false, false];
|
let pagesFilled = [false, false, false, false, false, false, false, false];
|
||||||
|
|
@ -69,7 +80,7 @@
|
||||||
city: '',
|
city: '',
|
||||||
zip: '',
|
zip: '',
|
||||||
citizenship: '',
|
citizenship: '',
|
||||||
personalIdNumber: '',
|
personalIdNumber: 'TODO: remove this',
|
||||||
schoolName: '',
|
schoolName: '',
|
||||||
healthInsurance: '',
|
healthInsurance: '',
|
||||||
grades: [],
|
grades: [],
|
||||||
|
|
@ -116,8 +127,21 @@
|
||||||
birthdate: yup
|
birthdate: yup
|
||||||
.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(),
|
.test((_val) => {
|
||||||
|
if ($form.candidate.citizenship !== 'Česká republika') return true;
|
||||||
|
if (!_val) return false;
|
||||||
|
if (isPersonalIdMatchingBirthdate(
|
||||||
|
$form.candidate.personalIdNumber,
|
||||||
|
_val
|
||||||
|
)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
pushErrorText("Datum narození a rodné číslo se neshodují.")
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
birthSurname: yup.string(),
|
||||||
sex: yup.string(),
|
sex: yup.string(),
|
||||||
address: yup.string(),
|
address: yup.string(),
|
||||||
street: yup.string().required(),
|
street: yup.string().required(),
|
||||||
|
|
@ -128,7 +152,7 @@
|
||||||
city: yup.string().required(),
|
city: yup.string().required(),
|
||||||
zip: yup.string().required(),
|
zip: yup.string().required(),
|
||||||
citizenship: yup.string().required(),
|
citizenship: yup.string().required(),
|
||||||
personalIdNumber: yup.string().required(),
|
personalIdNumber: yup.string(),
|
||||||
schoolName: yup.string().required(),
|
schoolName: yup.string().required(),
|
||||||
healthInsurance: yup.number().required(),
|
healthInsurance: yup.number().required(),
|
||||||
grades: yup
|
grades: yup
|
||||||
|
|
@ -146,11 +170,34 @@
|
||||||
)
|
)
|
||||||
.required(),
|
.required(),
|
||||||
firstSchool: yup.object().shape({
|
firstSchool: yup.object().shape({
|
||||||
name: yup.string().required(),
|
name: yup
|
||||||
|
.string()
|
||||||
|
.required()
|
||||||
|
.test((_val) => {
|
||||||
|
if (!_val) return false;
|
||||||
|
if (schoolNames.includes(_val)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
pushErrorText('Vyberte prosím školu ze seznamu.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}),
|
||||||
field: yup.string().required()
|
field: yup.string().required()
|
||||||
}),
|
}),
|
||||||
secondSchool: yup.object().shape({
|
secondSchool: yup.object().shape({
|
||||||
name: yup.string().required(),
|
name: yup
|
||||||
|
.string()
|
||||||
|
.required()
|
||||||
|
.test((_val) => {
|
||||||
|
if (!_val) return false;
|
||||||
|
if (!_val) return false;
|
||||||
|
if (schoolNames.includes(_val)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
pushErrorText('Vyberte prosím školu ze seznamu.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}),
|
||||||
field: yup.string().required()
|
field: yup.string().required()
|
||||||
}),
|
}),
|
||||||
testLanguage: yup.string().required()
|
testLanguage: yup.string().required()
|
||||||
|
|
@ -216,32 +263,9 @@
|
||||||
personalIdModal: false,
|
personalIdModal: false,
|
||||||
linkErrorModal: false
|
linkErrorModal: false
|
||||||
};
|
};
|
||||||
const validatePersonalId = () => {
|
|
||||||
if ($form.candidate.citizenship === 'Česká republika') {
|
|
||||||
if (
|
|
||||||
!isPersonalIdNumberWithBirthdateValid(
|
|
||||||
$form.candidate.personalIdNumber,
|
|
||||||
$form.candidate.birthdate
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
toast.push('Rodné číslo neodpovídá oficiální specifikaci či datumu narození', {
|
|
||||||
theme: {
|
|
||||||
'--toastColor': 'mintcream',
|
|
||||||
'--toastBackground': '#b91c1c',
|
|
||||||
'--toastBarBackground': '#7f1d1d'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
throw new Error('Rodné číslo neodpovídá datumu narození');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onSubmit = async (values: CandidateData) => {
|
const onSubmit = async (values: CandidateData) => {
|
||||||
console.log('submit button clicked');
|
|
||||||
console.log(pagesFilled.map((_, i) => !isPageInvalid(i)));
|
|
||||||
|
|
||||||
if (pageIndex === pageCount) {
|
if (pageIndex === pageCount) {
|
||||||
console.log('submitting');
|
|
||||||
// clone values to oldValues
|
// clone values to oldValues
|
||||||
let oldValues = JSON.parse(JSON.stringify(values));
|
let oldValues = JSON.parse(JSON.stringify(values));
|
||||||
try {
|
try {
|
||||||
|
|
@ -336,7 +360,7 @@
|
||||||
$typedErrors['candidate']['healthInsurance'] ||
|
$typedErrors['candidate']['healthInsurance'] ||
|
||||||
$typedErrors['candidate']['birthdate'] ||
|
$typedErrors['candidate']['birthdate'] ||
|
||||||
$typedErrors['candidate']['birthplace'] ||
|
$typedErrors['candidate']['birthplace'] ||
|
||||||
$typedErrors['candidate']['personalIdNumber'] ||
|
$typedErrors['candidate']['birthSurname'] ||
|
||||||
$typedErrors['candidate']['testLanguage']
|
$typedErrors['candidate']['testLanguage']
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -386,11 +410,23 @@
|
||||||
return '+' + telephone.match(/[0-9]{1,3}/g)!.join(' ');
|
return '+' + telephone.match(/[0-9]{1,3}/g)!.join(' ');
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO
|
let lastCitizenshipSelected = $form.candidate.citizenship;
|
||||||
/* $form.candidate.personalIdNumber = data.whoami.personalIdNumber;
|
$: if ($form.candidate.citizenship !== lastCitizenshipSelected) {
|
||||||
const [birthdate, sex] = deriveBirthdateFromPersonalId(data.whoami.personalIdNumber);
|
lastCitizenshipSelected = $form.candidate.citizenship;
|
||||||
$form.candidate.birthdate = birthdate;
|
$form.candidate.birthdate = '';
|
||||||
$form.candidate.sex = sex; */
|
$form.candidate.sex = '';
|
||||||
|
|
||||||
|
if ($form.candidate.citizenship === 'Česká republika') {
|
||||||
|
let [birthdate, sex] = parseBirthdateSexFromPersonalId(data.whoami.personalIdNumber);
|
||||||
|
$form.candidate.birthdate = birthdate;
|
||||||
|
$form.candidate.sex = sex;
|
||||||
|
if (pageIndex === 4) {
|
||||||
|
pushSuccessText(
|
||||||
|
`Datum narození a pohlaví bylo vyplněno automaticky podle Vašeho rodného čísla (${data.whoami.personalIdNumber}).`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (details !== undefined) {
|
if (details !== undefined) {
|
||||||
details.candidate.birthdate = details.candidate.birthdate.split('-').reverse().join('.');
|
details.candidate.birthdate = details.candidate.birthdate.split('-').reverse().join('.');
|
||||||
|
|
@ -442,7 +478,10 @@
|
||||||
personalIdNumber={baseCandidateDetails.personalIdNumber}
|
personalIdNumber={baseCandidateDetails.personalIdNumber}
|
||||||
/>
|
/>
|
||||||
{:else if visibleModals.linkErrorModal}
|
{:else if visibleModals.linkErrorModal}
|
||||||
<LinkErrorModal applications={baseCandidateDetails.applications} on:close={(_) => (visibleModals.linkErrorModal = false)} />
|
<LinkErrorModal
|
||||||
|
applications={baseCandidateDetails.applications}
|
||||||
|
on:close={(_) => (visibleModals.linkErrorModal = false)}
|
||||||
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
<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">
|
||||||
|
|
@ -499,24 +538,14 @@
|
||||||
</p>
|
</p>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<div class="field flex">
|
<span class="field">
|
||||||
<span class="w-[50%]">
|
<NameField
|
||||||
<NameField
|
error={$typedErrors['candidate']['name'] || $typedErrors['candidate']['surname']}
|
||||||
error={$typedErrors['candidate']['name'] ||
|
bind:valueName={$form.candidate.name}
|
||||||
$typedErrors['candidate']['surname']}
|
bind:valueSurname={$form.candidate.surname}
|
||||||
bind:valueName={$form.candidate.name}
|
placeholder={$LL.input.nameSurname()}
|
||||||
bind:valueSurname={$form.candidate.surname}
|
/>
|
||||||
placeholder={$LL.input.nameSurname()}
|
</span>
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span class="ml-2 w-[50%]">
|
|
||||||
<TextField
|
|
||||||
error={$typedErrors['candidate']['birthSurname']}
|
|
||||||
bind:value={$form.candidate.birthSurname}
|
|
||||||
placeholder={$LL.input.birthSurname()}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span class="field ml-2">
|
<span class="field ml-2">
|
||||||
<TelephoneField
|
<TelephoneField
|
||||||
bind:error={$typedErrors['candidate']['telephone']}
|
bind:error={$typedErrors['candidate']['telephone']}
|
||||||
|
|
@ -539,7 +568,7 @@
|
||||||
bind:value={$form.candidate.city}
|
bind:value={$form.candidate.city}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={$LL.input.city()}
|
placeholder={$LL.input.city()}
|
||||||
helperText="Uveďte poštovní směrovací číslo. (např. 602 00)"
|
helperText="Uveďte okres / MČ Prahy (např. Liberec nebo Praha 5)"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -553,16 +582,16 @@
|
||||||
bind:valueName={$form.candidate.street}
|
bind:valueName={$form.candidate.street}
|
||||||
bind:valueSurname={$form.candidate.houseNumber}
|
bind:valueSurname={$form.candidate.houseNumber}
|
||||||
placeholder={$LL.input.address()}
|
placeholder={$LL.input.address()}
|
||||||
helperText="Uveďte ulici a číslo popisné (např. Preslova 72)."
|
helperText="Uveďte ulici a číslo popisné (např. Preslova 72/25)."
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="ml-2 w-[33%]">
|
<span class="ml-2 w-[33%]">
|
||||||
<TextField
|
<TextField
|
||||||
error={$typedErrors['candidate']['zip']}
|
error={$typedErrors['candidate']['zip']}
|
||||||
bind:value={$form.candidate.zip}
|
bind:value={$form.candidate.zip}
|
||||||
type="number"
|
type="text"
|
||||||
placeholder={$LL.input.zipCode()}
|
placeholder={$LL.input.zipCode()}
|
||||||
helperText="Uveďte poštovní směrovací číslo. (např. 602 00)"
|
helperText="Uveďte poštovní směrovací číslo. (např. 150 21)"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -579,7 +608,7 @@
|
||||||
error={$typedErrors['candidate']['citizenship']}
|
error={$typedErrors['candidate']['citizenship']}
|
||||||
bind:value={$form.candidate.citizenship}
|
bind:value={$form.candidate.citizenship}
|
||||||
placeholder={$LL.input.citizenship()}
|
placeholder={$LL.input.citizenship()}
|
||||||
options={['Česká republika', 'Slovenská republika', 'Ukrajina', 'Jiné']}
|
options={countriesList}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span class="ml-2 w-[50%]">
|
<span class="ml-2 w-[50%]">
|
||||||
|
|
@ -597,7 +626,7 @@
|
||||||
bind:value={$form.candidate.birthdate}
|
bind:value={$form.candidate.birthdate}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={$LL.input.birthDate()}
|
placeholder={$LL.input.birthDate()}
|
||||||
helperText="TODO: (Uveďte ve formátu DD.MM.RRRR)"
|
helperText="Uveďte datum narození (např. 1. 1. 1970)"
|
||||||
/>
|
/>
|
||||||
<div class="ml-2">
|
<div class="ml-2">
|
||||||
<TextField
|
<TextField
|
||||||
|
|
@ -605,24 +634,16 @@
|
||||||
bind:value={$form.candidate.birthplace}
|
bind:value={$form.candidate.birthplace}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={$LL.input.birthPlace()}
|
placeholder={$LL.input.birthPlace()}
|
||||||
helperText="TODO: (Místo narození)"
|
helperText="Uveďte místo narození (např. Liberec nebo Praha 5)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</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}
|
<TextField
|
||||||
<IdField
|
error={$typedErrors['candidate']['birthSurname']}
|
||||||
error={$typedErrors['candidate']['personalIdNumber']}
|
bind:value={$form.candidate.birthSurname}
|
||||||
bind:value={$form.candidate.personalIdNumber}
|
placeholder={`${$LL.input.birthSurname()} (${$LL.input.optional()})`}
|
||||||
placeholder={$LL.input.personalIdentificationNumber()}
|
/>
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<TextField
|
|
||||||
error={$typedErrors['candidate']['personalIdNumber']}
|
|
||||||
bind:value={$form.candidate.personalIdNumber}
|
|
||||||
placeholder={$LL.input.personalIdentificationNumber()}
|
|
||||||
/>
|
|
||||||
{/if}
|
|
||||||
<div class="ml-2">
|
<div class="ml-2">
|
||||||
<SelectField
|
<SelectField
|
||||||
error={$typedErrors['candidate']['sex']}
|
error={$typedErrors['candidate']['sex']}
|
||||||
|
|
@ -640,6 +661,7 @@
|
||||||
type="number"
|
type="number"
|
||||||
bind:value={$form.candidate.schoolName}
|
bind:value={$form.candidate.schoolName}
|
||||||
placeholder={$LL.input.schoolIzo()}
|
placeholder={$LL.input.schoolIzo()}
|
||||||
|
helperText="Uveďte IZO základní školy (např. 47608579)"
|
||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<TextField
|
<TextField
|
||||||
|
|
@ -647,6 +669,7 @@
|
||||||
type="text"
|
type="text"
|
||||||
bind:value={$form.candidate.schoolName}
|
bind:value={$form.candidate.schoolName}
|
||||||
placeholder={$LL.input.schoolName()}
|
placeholder={$LL.input.schoolName()}
|
||||||
|
helperText="Uveďte název základní školy (např. Masarykova základní škola, Praha 9 - Újezd nad Lesy, Polesná 1690)"
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -657,6 +680,7 @@
|
||||||
type="text"
|
type="text"
|
||||||
bind:value={$form.candidate.healthInsurance}
|
bind:value={$form.candidate.healthInsurance}
|
||||||
placeholder={$LL.input.insuranceNumber()}
|
placeholder={$LL.input.insuranceNumber()}
|
||||||
|
helperText="Uveďte číslo zdravotní pojišťovny (např. 111)"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -719,20 +743,43 @@
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{:else if pageIndex === 7}
|
{:else if pageIndex === 7}
|
||||||
<h1 class="title mt-8">{pageTexts[5]}</h1>
|
<!-- <h1 class="title mt-8">{pageTexts[5]}</h1> -->
|
||||||
<p class="description my-8 block text-center">
|
<!-- <p class="description mt-8 block text-center">
|
||||||
{$LL.candidate.register.seventh.description()}
|
{$LL.candidate.register.seventh.description()}
|
||||||
</p>
|
</p> -->
|
||||||
<div class="flex h-full flex-col justify-between">
|
<div class="flex h-full flex-col justify-between">
|
||||||
<span class="field">
|
<span class="field">
|
||||||
|
<h2 class="text-sspsBlueDark mb-6 text-3xl font-bold">
|
||||||
|
První škola - termín JPZ: <span class="underline">13. 4. 2023</span>
|
||||||
|
</h2>
|
||||||
<SchoolSelect
|
<SchoolSelect
|
||||||
|
{schoolNames}
|
||||||
|
{schoolList}
|
||||||
error={$typedErrors['candidate']['firstSchool']['name'] ||
|
error={$typedErrors['candidate']['firstSchool']['name'] ||
|
||||||
$typedErrors['candidate']['firstSchool']['field']}
|
$typedErrors['candidate']['firstSchool']['field']}
|
||||||
bind:selectedSchool={$form.candidate.firstSchool}
|
bind:selectedSchool={$form.candidate.firstSchool}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
<!--dotted line -->
|
||||||
|
<svg class="mt-12 h-[10px] w-full" viewBox="0 0 800 5">
|
||||||
|
<line
|
||||||
|
x1="0"
|
||||||
|
y1="0"
|
||||||
|
x2="100%"
|
||||||
|
y2="0"
|
||||||
|
stroke="black"
|
||||||
|
stroke-width="3"
|
||||||
|
stroke-dasharray="10"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
<span class="field mt-10">
|
<span class="field mt-10">
|
||||||
|
<h2 class="text-sspsBlueDark mb-6 text-3xl font-bold">
|
||||||
|
Druhá škola - termín JPZ: <span class="underline">14. 4. 2023</span>
|
||||||
|
</h2>
|
||||||
<SchoolSelect
|
<SchoolSelect
|
||||||
|
{schoolNames}
|
||||||
|
{schoolList}
|
||||||
error={$typedErrors['candidate']['secondSchool']['name'] ||
|
error={$typedErrors['candidate']['secondSchool']['name'] ||
|
||||||
$typedErrors['candidate']['secondSchool']['field']}
|
$typedErrors['candidate']['secondSchool']['field']}
|
||||||
bind:selectedSchool={$form.candidate.secondSchool}
|
bind:selectedSchool={$form.candidate.secondSchool}
|
||||||
|
|
@ -753,13 +800,9 @@
|
||||||
<div class="bottom-1/24 absolute w-full">
|
<div class="bottom-1/24 absolute w-full">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<Submit
|
<Submit
|
||||||
|
enterAllowed={pageIndex !== 7}
|
||||||
on:click={async (e) => {
|
on:click={async (e) => {
|
||||||
if (pageIndex === 4) {
|
|
||||||
console.log('validating personal id');
|
|
||||||
validatePersonalId();
|
|
||||||
}
|
|
||||||
await handleSubmit(e);
|
await handleSubmit(e);
|
||||||
console.log(pagesFilled.map((_, i) => !isPageInvalid(i)));
|
|
||||||
if (isPageInvalid(pageIndex)) return;
|
if (isPageInvalid(pageIndex)) return;
|
||||||
if (pageIndex !== pageCount) {
|
if (pageIndex !== pageCount) {
|
||||||
pagesFilled[pageIndex] = true;
|
pagesFilled[pageIndex] = true;
|
||||||
|
|
@ -777,9 +820,6 @@
|
||||||
<button
|
<button
|
||||||
class:dotActive={i === pageIndex}
|
class:dotActive={i === pageIndex}
|
||||||
on:click={async (e) => {
|
on:click={async (e) => {
|
||||||
if (pageIndex === 4 && i > pageIndex) {
|
|
||||||
validatePersonalId();
|
|
||||||
}
|
|
||||||
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));
|
||||||
|
|
@ -799,7 +839,7 @@
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
.field {
|
.field {
|
||||||
@apply mt-4 w-full md:mt-8 lg:mx-auto lg:w-4/5;
|
@apply lg:w-9/10 mt-4 w-full md:mt-8 lg:mx-auto 2xl:w-4/5;
|
||||||
}
|
}
|
||||||
.form {
|
.form {
|
||||||
@apply flex flex-col;
|
@apply flex flex-col;
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
/>
|
/>
|
||||||
</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 enterAllowed={true} on:click={redirectToCode} value={$LL.input.submit()} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SplitLayout>
|
</SplitLayout>
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
console.log('submitting: ', codeValueArray);
|
|
||||||
try {
|
try {
|
||||||
await apiLogin({ applicationId, password: codeValueMobile });
|
await apiLogin({ applicationId, password: codeValueMobile });
|
||||||
goto('/dashboard');
|
goto('/dashboard');
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ const cs: BaseTranslation = {
|
||||||
},
|
},
|
||||||
eighth: {
|
eighth: {
|
||||||
title: 'Poslední krok',
|
title: 'Poslední krok',
|
||||||
description: 'Přidejte prosím přepis Vaších známek z posledních dvou let studia'
|
description: 'Přidejte prosím přepis Vaších známek z posledních dvou let studia. Známky z druhého pololetí 9. třídy nevyplňujte, pokud vysvědčení ještě nemáte.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -140,7 +140,7 @@ const cs: BaseTranslation = {
|
||||||
fullAddress: 'Adresa',
|
fullAddress: 'Adresa',
|
||||||
address: 'Ulice a č. p.',
|
address: 'Ulice a č. p.',
|
||||||
zipCode: 'PSČ',
|
zipCode: 'PSČ',
|
||||||
city: 'Město',
|
city: 'Okres',
|
||||||
birthPlace: 'Místo narození',
|
birthPlace: 'Místo narození',
|
||||||
birthDate: 'Datum narození',
|
birthDate: 'Datum narození',
|
||||||
sex: 'Pohlaví',
|
sex: 'Pohlaví',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue