Merge pull request #193 from EETagent/frontend_prod_form

Frontend prod form
This commit is contained in:
Sebastian Pravda 2023-02-05 16:33:24 +01:00 committed by GitHub
commit dce07ce2cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 3115 additions and 131 deletions

View file

@ -54,7 +54,6 @@ export const apiFetchSubmissionProgress = async (fetchSsr?: Fetch): Promise<Subm
export const apiWhoami = async (fetchSsr?: Fetch): Promise<BaseCandidate> => {
const apiFetch = fetchSsr || fetch;
try {
console.log(API_URL + '/candidate/whoami');
const res = await apiFetch(API_URL + '/candidate/whoami', {
method: 'GET',
credentials: 'include'
@ -100,7 +99,6 @@ export const apiFillDetails = async (data: CandidateData): Promise<CandidateData
});
}
console.log(data);
try {
const res = await axios.post(API_URL + '/candidate/details', data, { withCredentials: true });
return res.data;

View 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"
]

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
<script lang="ts">
import { apiGetCandidatePortfolio, apiResetCandidatePassword } from '$lib/@api/admin';
import type { CandidateData } from '$lib/stores/candidate';
import { SvelteToast, toast } from '@zerodevx/svelte-toast';
export let id: number;
export let candidateData: CandidateData;
@ -13,7 +14,13 @@
const res = await apiResetCandidatePassword(id);
alert('Nove heslo: ' + res.password);
} 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);
link.click();
} 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>
<SvelteToast />
<div class="flex h-screen w-full items-center justify-center">
<div class="mr-8 max-w-sm">
<div class="rounded-lg bg-white p-10 shadow-xl">

View file

@ -1,12 +1,13 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
export let enterAllowed: boolean;
export let value: string;
const dispatch = createEventDispatcher();
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Enter') {
if (enterAllowed && e.key === 'Enter') {
dispatch('click');
}
};

View file

@ -15,6 +15,7 @@
import { baseCandidateData, candidateData } from '$lib/stores/candidate';
import tippy, { sticky } from 'tippy.js';
import { goto } from '$app/navigation';
import { pushErrorText } from '$lib/utils/toast';
export let title: string;
export let status: Status;
@ -62,7 +63,7 @@
document.body.appendChild(link);
link.click();
} catch (e) {
console.log(e);
pushErrorText("Chyba při stahování portfolia");
}
};

View file

@ -31,12 +31,10 @@
$: if ($submissionProgress) {
status = getStatus();
// console.log('type' + fileType + ' status: ' + status);
fileDropped = status === 'uploaded' || status === 'submitted';
}
const getStatus = (): Status => {
console.log($submissionProgress);
switch ($submissionProgress.status) {
case UploadStatus.None:
return 'missing';
@ -71,7 +69,6 @@
};
const onFileDrop = (dropped: Files) => {
console.log(dropped);
if (dropped.accepted.length > 0) {
fileDropped = true;
const file = dropped.accepted[0];
@ -79,7 +76,6 @@
dispatch('filedrop', {
file: file,
callback: (progressEvent: AxiosProgressEvent) => {
console.log(progressEvent.bytes);
progress = progressEvent.progress!;
bytesTotal = progressEvent.total ?? 0;
}

View file

@ -9,8 +9,15 @@
</script>
<script lang="ts">
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
export let grade: Grade;
const SEMESTERS: Semester[] = ['1/8', '2/8', '1/9', '2/9'];
const deleteRow = () => {
dispatch('delete');
}
</script>
<div class="flex">
@ -25,6 +32,23 @@
<option value="5">5</option>
</select>
{/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>
<style lang="postcss">

View file

@ -78,8 +78,8 @@
};
</script>
<div class="mx-auto mt-8 flex text-gray-400 lg:w-4/5">
<span class="w-1/2 text-center">Známky</span>
<div class="mx-auto mt-8 flex pr-6 text-gray-400 lg:w-4/5">
<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">2/8</span>
<span class="ml-0.5 w-1/6 text-center">1/9</span>
@ -92,6 +92,10 @@
on:keyup={convertGradeToGradeBackend}
on:change={convertGradeToGradeBackend}
bind:grade={gradesLocal[i]}
on:delete={() => {
grades = grades.filter((grade) => grade.subject !== gradesLocal[i].subject);
gradesLocal = gradesLocal.filter((_, index) => index !== i);
}}
/>
</div>
{/each}

View file

@ -1,19 +1,33 @@
<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';
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> = [];
const filterSchools = () => {
let storageArr: Array<string> = [];
if (schoolNameInputValue) {
schoolList.forEach((school) => {
if (school.toLowerCase().startsWith(schoolNameInputValue.toLowerCase())) {
schoolNames.forEach((school) => {
if (
school
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.includes(
schoolNameInputValue
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
)
) {
storageArr = [...storageArr, makeMatchBold(school)];
}
});
@ -26,17 +40,30 @@
let schoolNameInputValue = '';
let schoolFieldInputValue = '';
let fieldFocusInputValue = '';
$: if (!schoolNameInputValue) {
filteredSchools = [];
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) => {
schoolNameInputValue = removeBold(schoolName);
filteredSchools = [];
hiLiteIndex = -1;
searchInput.focus();
// setFields(schoolNameInputValue);
};
const makeMatchBold = (str: string) => {
@ -76,33 +103,67 @@
export let selectedSchool: SchoolType;
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;
$: selectedSchool.field = schoolFieldInputValue;
$: selectedSchool.field = schoolFieldInputValue + (fieldFocusInputValue ? `;${fieldFocusInputValue}` : '');
$: selectedSchool.name = schoolNameInputValue;
let isSSPS = false;
$: isSSPS = schoolNameInputValue === 'Smíchovská střední průmyslová škola a gymnázium';
</script>
<svelte:window on:keydown={navigateList} />
<div class="autocomplete">
<div class="flex">
<div class="flex flex-col">
<input
class:error
class="flex-1"
class=""
type="text"
bind:this={searchInput}
bind:value={schoolNameInputValue}
on:input={filterSchools}
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="ml-2 w-2/5"
class="mt-4"
type="text"
bind:value={schoolFieldInputValue}
placeholder={$LL.input.fieldOfStudy()}
/>
/> -->
</div>
{#if filteredSchools.length > 0}
<ul bind:this={optionsList} class="schoolAutocompleteList">

View file

@ -20,7 +20,6 @@
if (number !== null && number !== undefined) {
country = number.country!;
}
// console.log(country);
}
// Validity

View file

@ -1,6 +1,10 @@
import type { GradeBackend } from '$lib/components/grades/GradesTable.svelte';
import { writable } from 'svelte/store';
export interface SchoolJson {
n: string;
f: string[];
}
export interface School {
name: string;
field: string;

View file

@ -14,7 +14,7 @@ export const isPersonalIdNumberValid = (personalIdNumber: string): boolean => {
}
};
export const isPersonalIdNumberWithBirthdateValid = (
export const isPersonalIdMatchingBirthdate = (
personalIdNumber: string,
birthdate: string
): boolean => {
@ -48,25 +48,26 @@ export const isPersonalIdNumberWithBirthdateValid = (
}
};
export const deriveBirthdateFromPersonalId = (
export const parseBirthdateSexFromPersonalId = (
personalIdNumber: string
): [birthdate: string, sex: 'MUŽ' | 'ŽENA'] => {
const year = Number(personalIdNumber.slice(0, 2));
): [birthdate: string, sex: 'Muž' | 'Žena'] => {
const yearPadded = Number(personalIdNumber.slice(0, 2));
const year = yearPadded < 24 ? yearPadded + 2000 : yearPadded + 1900;
const idMonth = Number(personalIdNumber.slice(2, 4));
let month;
let sex: 'MUŽ' | 'ŽENA';
let sex: 'Muž' | 'Žena';
if (idMonth > 12 && idMonth <= 32) {
month = idMonth - 20;
sex = 'M';
sex = 'M';
} else if (idMonth > 50 && idMonth <= 52) {
month = idMonth - 50;
sex = ENA';
sex = ena';
} else if (idMonth > 70 && idMonth <= 82) {
month = idMonth - 70;
sex = ENA';
sex = ena';
} else {
month = idMonth;
sex = 'M';
sex = 'M';
}
const day = Number(personalIdNumber.slice(4, 6));

View 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'
}
});
}

View file

@ -11,6 +11,8 @@
import bacgkround from '$lib/assets/background.jpg';
import Logout from '$lib/components/icons/Logout.svelte';
import { goto } from '$app/navigation';
import { pushErrorText } from '$lib/utils/toast';
import { SvelteToast } from '@zerodevx/svelte-toast';
export let data: PageServerData;
@ -20,7 +22,7 @@
try {
candidates = await apiListCandidates(undefined, activeFilter.filter);
} catch {
console.log('error');
pushErrorText('Nepodařilo se načíst uchazeče');
}
};
@ -93,7 +95,7 @@
link.setAttribute('download', 'UCHAZECI' + '.csv');
link.click();
} catch (e) {
console.log(e);
pushErrorText('Nepodařilo se stáhnout CSV');
}
};
@ -110,6 +112,7 @@
{/if}
<div>
<SvelteToast />
<header class="absolute h-14 w-full">
<img class="h-12 w-full object-cover blur-sm filter" src={bacgkround} alt="Background" />
</header>

View file

@ -10,6 +10,8 @@
import { goto } from '$app/navigation';
import Submit from '$lib/components/button/Submit.svelte';
import PasswordField from '$lib/components/textfield/PasswordField.svelte';
import { SvelteToast } from '@zerodevx/svelte-toast';
import { pushErrorText } from '$lib/utils/toast';
let adminIdValue = '';
let adminPasswordValue = '';
@ -19,11 +21,12 @@
await apiLogin({ adminId: Number(adminIdValue), password: adminPasswordValue });
goto('/admin/dashboard');
} catch (e) {
console.log(e);
pushErrorText('Neplatné heslo nebo ID!');
}
};
</script>
<SvelteToast />
<SplitLayout backgroundImage={background} backgroundPosition="30%">
<div class="form">
<div
@ -44,7 +47,7 @@
</span>
</div>
<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>
</SplitLayout>

View file

@ -18,15 +18,26 @@
import parsePhoneNumber from 'libphonenumber-js';
import { createForm } from 'svelte-forms-lib';
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 GradesTable from '$lib/components/grades/GradesTable.svelte';
import SchoolSelect from '$lib/components/select/SchoolSelect/SchoolSelect.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 LinkErrorModal from '$lib/components/modal/LinkErrorModal.svelte';
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 pagesFilled = [false, false, false, false, false, false, false, false];
@ -69,7 +80,7 @@
city: '',
zip: '',
citizenship: '',
personalIdNumber: '',
personalIdNumber: 'TODO: remove this',
schoolName: '',
healthInsurance: '',
grades: [],
@ -116,8 +127,21 @@
birthdate: yup
.string()
.required()
.matches(/^([0-3]?[0-9])\.(0?[1-9]|1[0-2])\.[0-9]{4}$/),
birthSurname: yup.string().required(),
.matches(/^([0-3]?[0-9])\.(0?[1-9]|1[0-2])\.[0-9]{4}$/)
.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(),
address: yup.string(),
street: yup.string().required(),
@ -128,7 +152,7 @@
city: yup.string().required(),
zip: yup.string().required(),
citizenship: yup.string().required(),
personalIdNumber: yup.string().required(),
personalIdNumber: yup.string(),
schoolName: yup.string().required(),
healthInsurance: yup.number().required(),
grades: yup
@ -146,11 +170,34 @@
)
.required(),
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()
}),
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()
}),
testLanguage: yup.string().required()
@ -216,32 +263,9 @@
personalIdModal: 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) => {
console.log('submit button clicked');
console.log(pagesFilled.map((_, i) => !isPageInvalid(i)));
if (pageIndex === pageCount) {
console.log('submitting');
// clone values to oldValues
let oldValues = JSON.parse(JSON.stringify(values));
try {
@ -336,7 +360,7 @@
$typedErrors['candidate']['healthInsurance'] ||
$typedErrors['candidate']['birthdate'] ||
$typedErrors['candidate']['birthplace'] ||
$typedErrors['candidate']['personalIdNumber'] ||
$typedErrors['candidate']['birthSurname'] ||
$typedErrors['candidate']['testLanguage']
) {
return true;
@ -386,11 +410,23 @@
return '+' + telephone.match(/[0-9]{1,3}/g)!.join(' ');
};
// TODO
/* $form.candidate.personalIdNumber = data.whoami.personalIdNumber;
const [birthdate, sex] = deriveBirthdateFromPersonalId(data.whoami.personalIdNumber);
$form.candidate.birthdate = birthdate;
$form.candidate.sex = sex; */
let lastCitizenshipSelected = $form.candidate.citizenship;
$: if ($form.candidate.citizenship !== lastCitizenshipSelected) {
lastCitizenshipSelected = $form.candidate.citizenship;
$form.candidate.birthdate = '';
$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) {
details.candidate.birthdate = details.candidate.birthdate.split('-').reverse().join('.');
@ -442,7 +478,10 @@
personalIdNumber={baseCandidateDetails.personalIdNumber}
/>
{:else if visibleModals.linkErrorModal}
<LinkErrorModal applications={baseCandidateDetails.applications} on:close={(_) => (visibleModals.linkErrorModal = false)} />
<LinkErrorModal
applications={baseCandidateDetails.applications}
on:close={(_) => (visibleModals.linkErrorModal = false)}
/>
{/if}
<div class="form relative bg-center">
<div class="bottom-5/24 absolute flex w-full flex-col md:h-auto">
@ -499,24 +538,14 @@
</p>
<div class="w-full">
<div class="flex flex-col">
<div class="field flex">
<span class="w-[50%]">
<NameField
error={$typedErrors['candidate']['name'] ||
$typedErrors['candidate']['surname']}
bind:valueName={$form.candidate.name}
bind:valueSurname={$form.candidate.surname}
placeholder={$LL.input.nameSurname()}
/>
</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">
<NameField
error={$typedErrors['candidate']['name'] || $typedErrors['candidate']['surname']}
bind:valueName={$form.candidate.name}
bind:valueSurname={$form.candidate.surname}
placeholder={$LL.input.nameSurname()}
/>
</span>
<span class="field ml-2">
<TelephoneField
bind:error={$typedErrors['candidate']['telephone']}
@ -539,7 +568,7 @@
bind:value={$form.candidate.city}
type="text"
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>
</div>
@ -553,16 +582,16 @@
bind:valueName={$form.candidate.street}
bind:valueSurname={$form.candidate.houseNumber}
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 class="ml-2 w-[33%]">
<TextField
error={$typedErrors['candidate']['zip']}
bind:value={$form.candidate.zip}
type="number"
type="text"
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>
</div>
@ -579,7 +608,7 @@
error={$typedErrors['candidate']['citizenship']}
bind:value={$form.candidate.citizenship}
placeholder={$LL.input.citizenship()}
options={['Česká republika', 'Slovenská republika', 'Ukrajina', 'Jiné']}
options={countriesList}
/>
</span>
<span class="ml-2 w-[50%]">
@ -597,7 +626,7 @@
bind:value={$form.candidate.birthdate}
type="text"
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">
<TextField
@ -605,24 +634,16 @@
bind:value={$form.candidate.birthplace}
type="text"
placeholder={$LL.input.birthPlace()}
helperText="TODO: (Místo narození)"
helperText="Uveďte místo narození (např. Liberec nebo Praha 5)"
/>
</div>
</div>
<div class="field flex items-center justify-center">
{#if $form.candidate.citizenship === 'Česká republika' || !$form.candidate.citizenship}
<IdField
error={$typedErrors['candidate']['personalIdNumber']}
bind:value={$form.candidate.personalIdNumber}
placeholder={$LL.input.personalIdentificationNumber()}
/>
{:else}
<TextField
error={$typedErrors['candidate']['personalIdNumber']}
bind:value={$form.candidate.personalIdNumber}
placeholder={$LL.input.personalIdentificationNumber()}
/>
{/if}
<TextField
error={$typedErrors['candidate']['birthSurname']}
bind:value={$form.candidate.birthSurname}
placeholder={`${$LL.input.birthSurname()} (${$LL.input.optional()})`}
/>
<div class="ml-2">
<SelectField
error={$typedErrors['candidate']['sex']}
@ -640,6 +661,7 @@
type="number"
bind:value={$form.candidate.schoolName}
placeholder={$LL.input.schoolIzo()}
helperText="Uveďte IZO základní školy (např. 47608579)"
/>
{:else}
<TextField
@ -647,6 +669,7 @@
type="text"
bind:value={$form.candidate.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}
</span>
@ -657,6 +680,7 @@
type="text"
bind:value={$form.candidate.healthInsurance}
placeholder={$LL.input.insuranceNumber()}
helperText="Uveďte číslo zdravotní pojišťovny (např. 111)"
/>
</span>
</div>
@ -719,20 +743,43 @@
</span>
</div>
{:else if pageIndex === 7}
<h1 class="title mt-8">{pageTexts[5]}</h1>
<p class="description my-8 block text-center">
<!-- <h1 class="title mt-8">{pageTexts[5]}</h1> -->
<!-- <p class="description mt-8 block text-center">
{$LL.candidate.register.seventh.description()}
</p>
</p> -->
<div class="flex h-full flex-col justify-between">
<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
{schoolNames}
{schoolList}
error={$typedErrors['candidate']['firstSchool']['name'] ||
$typedErrors['candidate']['firstSchool']['field']}
bind:selectedSchool={$form.candidate.firstSchool}
/>
</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">
<h2 class="text-sspsBlueDark mb-6 text-3xl font-bold">
Druhá škola - termín JPZ: <span class="underline">14. 4. 2023</span>
</h2>
<SchoolSelect
{schoolNames}
{schoolList}
error={$typedErrors['candidate']['secondSchool']['name'] ||
$typedErrors['candidate']['secondSchool']['field']}
bind:selectedSchool={$form.candidate.secondSchool}
@ -753,13 +800,9 @@
<div class="bottom-1/24 absolute w-full">
<div class="field">
<Submit
enterAllowed={pageIndex !== 7}
on:click={async (e) => {
if (pageIndex === 4) {
console.log('validating personal id');
validatePersonalId();
}
await handleSubmit(e);
console.log(pagesFilled.map((_, i) => !isPageInvalid(i)));
if (isPageInvalid(pageIndex)) return;
if (pageIndex !== pageCount) {
pagesFilled[pageIndex] = true;
@ -777,9 +820,6 @@
<button
class:dotActive={i === pageIndex}
on:click={async (e) => {
if (pageIndex === 4 && i > pageIndex) {
validatePersonalId();
}
pageIndex -= pageIndex === pageCount ? 1 : 0;
await handleSubmit(e);
pagesFilled = pagesFilled.map((_, i) => !isPageInvalid(i));
@ -799,7 +839,7 @@
<style lang="postcss">
.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 {
@apply flex flex-col;

View file

@ -32,7 +32,7 @@
/>
</div>
<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>
</SplitLayout>

View file

@ -47,7 +47,6 @@
}
const submit = async () => {
console.log('submitting: ', codeValueArray);
try {
await apiLogin({ applicationId, password: codeValueMobile });
goto('/dashboard');

View file

@ -64,7 +64,7 @@ const cs: BaseTranslation = {
},
eighth: {
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',
address: 'Ulice a č. p.',
zipCode: 'PSČ',
city: 'Město',
city: 'Okres',
birthPlace: 'Místo narození',
birthDate: 'Datum narození',
sex: 'Pohlaví',