From 50ac874f8130e68fc6eca1e0ab9dadc7aa340371 Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sat, 21 Jan 2023 18:21:24 +0100 Subject: [PATCH 01/21] feat: bigger register views --- .../lib/components/layout/SplitLayout.svelte | 4 +- frontend/src/lib/stores/candidate.ts | 8 + .../[code=application]/+page.server.ts | 4 + .../(authenticated)/register/+page.svelte | 355 +++++++++--------- 4 files changed, 192 insertions(+), 179 deletions(-) diff --git a/frontend/src/lib/components/layout/SplitLayout.svelte b/frontend/src/lib/components/layout/SplitLayout.svelte index eeb618b..5726f5c 100644 --- a/frontend/src/lib/components/layout/SplitLayout.svelte +++ b/frontend/src/lib/components/layout/SplitLayout.svelte @@ -49,8 +49,8 @@ } .view { @apply z-10; - @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-[50vw]; + @apply absolute top-0 right-0 bottom-0 m-auto md:top-auto md:bottom-auto md:left-auto md:m-0; + @apply md:h-screen md:w-[75vw]; @apply md:my-auto; @apply bg-white; } diff --git a/frontend/src/lib/stores/candidate.ts b/frontend/src/lib/stores/candidate.ts index 9b94cf8..7b22dc7 100644 --- a/frontend/src/lib/stores/candidate.ts +++ b/frontend/src/lib/stores/candidate.ts @@ -5,9 +5,11 @@ export interface CandidateData { candidate: { name: string; surname: string; + birthSurname: string; birthplace: string; birthdate: string; address: string; + letterAddress: string; telephone: string; citizenship: string; email: string; @@ -16,6 +18,8 @@ export interface CandidateData { schoolName: string; healthInsurance: string; grades: Array; + firstSchool: string; + secondSchool: string; testLanguage: string; }; parents: Array<{ @@ -66,9 +70,11 @@ export const candidateData = writable({ candidate: { name: '', surname: '', + birthSurname: '', birthplace: '', birthdate: '', address: '', + letterAddress: '', telephone: '', citizenship: '', email: '', @@ -77,6 +83,8 @@ export const candidateData = writable({ schoolName: '', healthInsurance: '', grades: [], + firstSchool: '', + secondSchool: '', testLanguage: '' }, parents: [] diff --git a/frontend/src/routes/(admin)/admin/(authenticated)/candidate/[code=application]/+page.server.ts b/frontend/src/routes/(admin)/admin/(authenticated)/candidate/[code=application]/+page.server.ts index 5088c69..ad436d9 100644 --- a/frontend/src/routes/(admin)/admin/(authenticated)/candidate/[code=application]/+page.server.ts +++ b/frontend/src/routes/(admin)/admin/(authenticated)/candidate/[code=application]/+page.server.ts @@ -10,9 +10,11 @@ export const load: PageServerLoad = async ({ fetch, params }) => { candidate: { name: '', surname: '', + birthSurname: '', birthplace: '', birthdate: '', address: '', + letterAddress: '', telephone: '', citizenship: '', email: '', @@ -21,6 +23,8 @@ export const load: PageServerLoad = async ({ fetch, params }) => { schoolName: '', healthInsurance: '', grades: [], + firstSchool: '', + secondSchool: '', testLanguage: '' }, parents: [] diff --git a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte index 492a3fa..69c961a 100644 --- a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte +++ b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte @@ -25,9 +25,9 @@ import AccountLinkCheckBox from '$lib/components/checkbox/AccountLinkCheckBox.svelte'; import GradesTable from '$lib/components/grades/GradesTable.svelte'; - const pageCount = 7; let pageIndex = 0; - let pagesFilled = [false, false, false, false, false, false, false]; + let pagesFilled = [false, false, false, false, false, false]; + const pageCount = pagesFilled.length; let pageTexts = [ $LL.candidate.register.second.title(), $LL.candidate.register.third.title(), @@ -42,6 +42,7 @@ let details = data.candidate; let baseCandidateDetails = data.whoami; + let personalIdBirthdateMatch = true; const formInitialValues = { gdpr: false, linkOk: false, @@ -49,12 +50,14 @@ candidate: { name: '', surname: '', + birthSurname: '', email: '', telephone: '', birthplace: '', birthdate: '', sex: '', address: '', + letterAddress: '', street: '', houseNumber: '', city: '', @@ -64,7 +67,9 @@ schoolName: '', healthInsurance: '', grades: [], - testLanguage: '' + firstSchool: '', + secondSchool: '', + testLanguage: '', }, parents: [ { @@ -229,28 +234,31 @@ }; const onSubmit = async (values: CandidateData) => { + if (pageIndex === 3) { + if (values.candidate.citizenship === 'Česká republika') { + if ( + !isPersonalIdNumberWithBirthdateValid( + values.candidate.personalIdNumber, + values.candidate.birthdate + ) + ) { + toast.push('Rodné číslo neodpovídá oficiální specifikaci či datumu narození', { + theme: { + '--toastColor': 'mintcream', + '--toastBackground': '#b91c1c', + '--toastBarBackground': '#7f1d1d' + } + }); + personalIdBirthdateMatch = false; + throw new Error('Rodné číslo neodpovídá datumu narození'); + } + } + personalIdBirthdateMatch = true; + } if (pageIndex === pageCount) { // clone values to oldValues let oldValues = JSON.parse(JSON.stringify(values)); try { - if (values.candidate.citizenship === 'Česká republika') { - if ( - !isPersonalIdNumberWithBirthdateValid( - values.candidate.personalIdNumber, - values.candidate.birthdate - ) - ) { - // alert('Rodné číslo neodpovídá oficiální specifikaci či datumu narození'); // TODO: alerts - 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í'); - } - } // @ts-ignore // love javascript delete values.undefined; // convert birthdate from dd.mm.yyyy to yyyy-mm-dd @@ -318,7 +326,11 @@ $typedErrors['candidate']['name'] || $typedErrors['candidate']['surname'] || $typedErrors['candidate']['email'] || - $typedErrors['candidate']['telephone'] + $typedErrors['candidate']['telephone'] || + $typedErrors['candidate']['city'] || + $typedErrors['candidate']['street'] || + $typedErrors['candidate']['houseNumber'] || + $typedErrors['candidate']['zip'] ) { return true; } @@ -326,13 +338,15 @@ case 3: if ( - $typedErrors['candidate']['birthplace'] || + $typedErrors['candidate']['citizenship'] || + $typedErrors['candidate']['personalIdNumber'] || + $typedErrors['candidate']['schoolName'] || + $typedErrors['candidate']['healthInsurance'] || $typedErrors['candidate']['birthdate'] || - $typedErrors['candidate']['street'] || - $typedErrors['candidate']['houseNumber'] || - $typedErrors['candidate']['city'] || - $typedErrors['candidate']['zip'] - // $typedErrors['candidate']['address'] + $typedErrors['candidate']['birthplace'] || + $typedErrors['candidate']['personalIdNumber'] || + $typedErrors['candidate']['testLanguage'] || + !personalIdBirthdateMatch ) { return true; } @@ -358,17 +372,7 @@ } break; case 6: - if ( - $typedErrors['candidate']['citizenship'] || - $typedErrors['candidate']['personalIdNumber'] || - $typedErrors['candidate']['schoolName'] || - $typedErrors['candidate']['healthInsurance'] - ) { - return true; - } - break; - case 7: - if ($typedErrors['candidate']['grades'].length > 0) return true; + if ($typedErrors["candidate"]["grades"].length > 0) return true; break; default: return false; @@ -421,11 +425,11 @@ -
-
+
+
{#if pageIndex !== 0 && pageIndex !== 7} -
+
{/if} @@ -462,29 +466,72 @@

{$LL.candidate.register.third.description()}

-
- - - - - - - - - +
+
+
+ + + + + + +
+
+ + + + + + +
+ + + +
+
+ + + + + + +
{:else if pageIndex === 3} @@ -492,53 +539,24 @@

{$LL.candidate.register.fourth.description()}

-
- - + + - - +
-
- - - - - -
- -
-
-
-
-
+ +
+
+ {#if $form.candidate.citizenship === 'Česká republika' || !$form.candidate.citizenship} + + {:else} + + {/if}
+
+ + {#if $form.candidate.citizenship === 'Česká republika' || !$form.candidate.citizenship} + + {:else} + + {/if} + + + + + +
+ {:else if pageIndex === 4}

{pageTexts[3]}

@@ -616,74 +685,6 @@

{:else if pageIndex === 6}

{pageTexts[5]}

-

- {$LL.candidate.register.seventh.description()} -

-
-
- - - - - - -
-
- - {#if $form.candidate.citizenship === 'Česká republika' || !$form.candidate.citizenship} - - {:else} - - {/if} - - - - - -
-
-
- {#if $form.candidate.citizenship === 'Česká republika' || !$form.candidate.citizenship} - - {:else} - - {/if} -
- {:else if pageIndex === 7} -

{pageTexts[6]}

{$LL.candidate.register.eighth.description()}

@@ -693,7 +694,7 @@ /> {/if}
-
+
{ @@ -711,7 +712,7 @@ />
-
+
{#each Array(pageCount + 1) as _, i}
{:else if pageIndex === 6} +

Přihlášky na školy

+
+ + + + + + +
+ {:else if pageIndex === 7}

{pageTexts[5]}

{$LL.candidate.register.eighth.description()} From 6da19fe492b2eb2a0f9c260c307bdca7463c41de Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Sun, 22 Jan 2023 19:24:56 +0100 Subject: [PATCH 04/21] fix: admin candidate view school type --- .../candidate/[code=application]/+page.server.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/routes/(admin)/admin/(authenticated)/candidate/[code=application]/+page.server.ts b/frontend/src/routes/(admin)/admin/(authenticated)/candidate/[code=application]/+page.server.ts index ad436d9..5bc7eea 100644 --- a/frontend/src/routes/(admin)/admin/(authenticated)/candidate/[code=application]/+page.server.ts +++ b/frontend/src/routes/(admin)/admin/(authenticated)/candidate/[code=application]/+page.server.ts @@ -23,8 +23,8 @@ export const load: PageServerLoad = async ({ fetch, params }) => { schoolName: '', healthInsurance: '', grades: [], - firstSchool: '', - secondSchool: '', + firstSchool: {name: '', field: ''}, + secondSchool: {name: '', field: ''}, testLanguage: '' }, parents: [] From 09ce40ec515fff6d13a54a3f55e4d50ece27579d Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Wed, 25 Jan 2023 10:42:25 +0100 Subject: [PATCH 05/21] feat: personalIdNumber confirmation --- .../checkbox/AccountLinkCheckBox.svelte | 7 +- .../checkbox/PersonalIdConfirmCheckBox.svelte | 80 +++++++++++ frontend/src/lib/utils/personalIdFormat.ts | 74 +++++++++++ .../(authenticated)/register/+page.svelte | 124 ++++++++---------- frontend/src/translations/cs/index.ts | 6 + frontend/src/translations/i18n-types.ts | 38 ++++++ 6 files changed, 254 insertions(+), 75 deletions(-) create mode 100644 frontend/src/lib/components/checkbox/PersonalIdConfirmCheckBox.svelte create mode 100644 frontend/src/lib/utils/personalIdFormat.ts diff --git a/frontend/src/lib/components/checkbox/AccountLinkCheckBox.svelte b/frontend/src/lib/components/checkbox/AccountLinkCheckBox.svelte index 55f1438..2009579 100644 --- a/frontend/src/lib/components/checkbox/AccountLinkCheckBox.svelte +++ b/frontend/src/lib/components/checkbox/AccountLinkCheckBox.svelte @@ -4,10 +4,9 @@ export let linkOk: boolean = false; export let linkError: boolean = false; export let applications: Array; - let title1 = $LL.components.checkbox.accountLinkCheckBox.multiple.title({ first: applications[0], - second: applications[1] + second: applications[1], }); let title2 = $LL.components.checkbox.accountLinkCheckBox.multiple.title2({ first: applications[0] @@ -15,13 +14,11 @@ if (applications.length === 1) { title1 = $LL.components.checkbox.accountLinkCheckBox.single.title({ - first: applications[0] + first: applications[0], }); title2 = $LL.components.checkbox.accountLinkCheckBox.single.title2(); } - $: console.log(linkOk, linkError); - export let error: string = ''; const switchSelection = (id: number) => { diff --git a/frontend/src/lib/components/checkbox/PersonalIdConfirmCheckBox.svelte b/frontend/src/lib/components/checkbox/PersonalIdConfirmCheckBox.svelte new file mode 100644 index 0000000..d0efed5 --- /dev/null +++ b/frontend/src/lib/components/checkbox/PersonalIdConfirmCheckBox.svelte @@ -0,0 +1,80 @@ + + +

+ switchSelection(0)} + class:error + on:change + type="checkbox" + id="linkOk" + checked={personalIdOk} + class="peer hidden" + /> + +
+
+ switchSelection(1)} + on:change + type="checkbox" + id="linkError" + checked={personalIdErr} + class="peer hidden" + /> + +
+ + diff --git a/frontend/src/lib/utils/personalIdFormat.ts b/frontend/src/lib/utils/personalIdFormat.ts new file mode 100644 index 0000000..2cb6282 --- /dev/null +++ b/frontend/src/lib/utils/personalIdFormat.ts @@ -0,0 +1,74 @@ +// TODO: nefunguje pro lidi nar. pred 1.1.1954 :D +export const isPersonalIdNumberValid = (personalIdNumber: string): boolean => { + const idFmt = personalIdNumber.split('/').join(''); + + const lastDigitCheck = + Number(idFmt.slice(0, 9)) % 11 === Number(idFmt.at(-1)) || + Number(idFmt.slice(0, 9)) % 11 === 10; // an edge case that could occur + const divisibleBy11 = Number(idFmt) % 11 === 0; + + if (lastDigitCheck && divisibleBy11) { + return true; + } else { + return false; + } +}; + +export const isPersonalIdNumberWithBirthdateValid = ( + personalIdNumber: string, + birthdate: string +): boolean => { + const dateFmt = birthdate + .split('.') + .map((x) => x.padStart(2, '0')) + .reverse() + .join('') + .slice(2); + const idFmt = personalIdNumber.split('/').join(''); + + const divisionValid = isPersonalIdNumberValid(personalIdNumber); + + const idMonth = Number(idFmt.slice(2, 4)); + const dateMonth = Number(dateFmt.slice(2, 4)); + const monthValid = + idMonth === dateMonth || + idMonth === dateMonth + 50 || + idMonth === dateMonth + 20 || + idMonth === dateMonth + 70; + + if ( + idFmt.slice(0, 2) === dateFmt.slice(0, 2) && + monthValid && + idFmt.slice(4, 6) === dateFmt.slice(4, 6) && + divisionValid + ) { + return true; + } else { + return false; + } +}; + +export const deriveBirthdateFromPersonalId = (personalIdNumber: string): + [birthdate: string, sex: 'MUŽ' | 'ŽENA'] => { + const year = Number(personalIdNumber.slice(0, 2)); + const idMonth = Number(personalIdNumber.slice(2, 4)); + let month; + let sex: 'MUŽ' | 'ŽENA'; + if (idMonth > 12 && idMonth <= 32) { + month = idMonth - 20; + sex = 'MUŽ'; + } else if (idMonth > 50 && idMonth <= 52) { + month = idMonth - 50; + sex = 'ŽENA'; + } else if (idMonth > 70 && idMonth <= 82) { + month = idMonth - 70; + sex = 'ŽENA'; + } else { + month = idMonth; + sex = 'MUŽ'; + }; + const day = Number(personalIdNumber.slice(4, 6)); + + const birthdate = `${day}.${month}.${year}`; + return [birthdate, sex]; +} \ No newline at end of file diff --git a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte index 0de206f..4f01808 100644 --- a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte +++ b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte @@ -6,7 +6,6 @@ import Submit from '$lib/components/button/Submit.svelte'; import GdprCheckBox from '$lib/components/checkbox/GdprCheckBox.svelte'; - import Home from '$lib/components/icons/Home.svelte'; import SchoolBadge from '$lib/components/icons/SchoolBadge.svelte'; import SplitLayout from '$lib/components/layout/SplitLayout.svelte'; import SelectField from '$lib/components/select/SelectField.svelte'; @@ -25,9 +24,12 @@ import AccountLinkCheckBox from '$lib/components/checkbox/AccountLinkCheckBox.svelte'; import GradesTable from '$lib/components/grades/GradesTable.svelte'; import SchoolSelect from '$lib/components/select/SchoolSelect.svelte'; + import PersonalIdConfirmCheckBox from '$lib/components/checkbox/PersonalIdConfirmCheckBox.svelte'; + import { deriveBirthdateFromPersonalId, isPersonalIdNumberWithBirthdateValid } from '$lib/utils/personalIdFormat'; let pageIndex = 0; - let pagesFilled = [false, false, false, false, false, false, false]; + let pagesFilled = [false, false, false, false, false, false, false, false]; + let editModePageIndex = 3; const pageCount = pagesFilled.length; let pageTexts = [ $LL.candidate.register.second.title(), @@ -46,6 +48,8 @@ let personalIdBirthdateMatch = true; const formInitialValues = { gdpr: false, + personalIdOk: false, + personalIdErr: false, linkOk: false, linkError: false, candidate: { @@ -90,6 +94,8 @@ const formValidationSchema = yup.object().shape({ gdpr: yup.boolean().oneOf([true]), + personalIdOk: yup.boolean().oneOf([true]), + personalIdErr: yup.boolean().oneOf([false]), linkOk: yup.boolean().oneOf([true]), linkError: yup.boolean().oneOf([false]), candidate: yup.object().shape({ @@ -190,56 +196,6 @@ // TODO: https://github.com/tjinauyeung/svelte-forms-lib/issues/171!! (Zatím tenhle mega typ) $: typedErrors = errors as unknown as Writable; - // TODO: validate on admin dashboard, move somewhere - // TODO: nefunguje pro lidi nar. pred 1.1.1954 :D - const isPersonalIdNumberValid = (personalIdNumber: string): boolean => { - const idFmt = personalIdNumber.split('/').join(''); - - const lastDigitCheck = - Number(idFmt.slice(0, 9)) % 11 === Number(idFmt.at(-1)) || - Number(idFmt.slice(0, 9)) % 11 === 10; // an edge case that could occur - const divisibleBy11 = Number(idFmt) % 11 === 0; - - if (lastDigitCheck && divisibleBy11) { - return true; - } else { - return false; - } - }; - - const isPersonalIdNumberWithBirthdateValid = ( - personalIdNumber: string, - birthdate: string - ): boolean => { - const dateFmt = birthdate - .split('.') - .map((x) => x.padStart(2, '0')) - .reverse() - .join('') - .slice(2); - const idFmt = personalIdNumber.split('/').join(''); - - const divisionValid = isPersonalIdNumberValid(personalIdNumber); - - const idMonth = Number(idFmt.slice(2, 4)); - const dateMonth = Number(dateFmt.slice(2, 4)); - const monthValid = - idMonth === dateMonth || - idMonth === dateMonth + 50 || - idMonth === dateMonth + 20 || - idMonth === dateMonth + 70; - - if ( - idFmt.slice(0, 2) === dateFmt.slice(0, 2) && - monthValid && - idFmt.slice(4, 6) === dateFmt.slice(4, 6) && - divisionValid - ) { - return true; - } else { - return false; - } - }; $: console.log($typedErrors); const onSubmit = async (values: CandidateData) => { if (pageIndex === 3) { @@ -320,17 +276,22 @@ const isPageInvalid = (index: number): boolean => { switch (index) { - case 0: - if ($typedErrors['linkOk'] || $typedErrors['linkError']) { + case 0: + if ($typedErrors['personalIdOk'] || $typedErrors['personalIdErr']) { return true; } break; case 1: - if ($typedErrors['gdpr']) { + if ($typedErrors['linkOk'] || $typedErrors['linkError']) { return true; } break; case 2: + if ($typedErrors['gdpr']) { + return true; + } + break; + case 3: if ( $typedErrors['candidate']['name'] || $typedErrors['candidate']['surname'] || @@ -345,7 +306,7 @@ } break; - case 3: + case 4: if ( $typedErrors['candidate']['citizenship'] || $typedErrors['candidate']['personalIdNumber'] || @@ -360,7 +321,7 @@ return true; } break; - case 4: + case 5: if ( $typedErrors['parents'][0]['name'] || $typedErrors['parents'][0]['surname'] || @@ -370,7 +331,7 @@ return true; } break; - case 5: + case 6: if ( $typedErrors['parents'][1]['name'] || $typedErrors['parents'][1]['surname'] || @@ -380,7 +341,7 @@ return true; } break; - case 6: + case 7: // @ts-ignore if ($typedErrors["candidate"]["firstSchool"].name || $typedErrors["candidate"]["firstSchool"].field || // @ts-ignore @@ -389,8 +350,8 @@ return true; } break; - case 7: - if ($typedErrors["candidate"]["grades"].length > 0) return true; + case 8: + if ($typedErrors['candidate']['grades'].length > 0) return true; break; default: return false; @@ -402,6 +363,12 @@ return '+' + telephone.match(/[0-9]{1,3}/g)!.join(' '); }; + + /* $form.candidate.personalIdNumber = data.whoami.personalIdNumber; + const [birthdate, sex] = deriveBirthdateFromPersonalId(data.whoami.personalIdNumber); + $form.candidate.birthdate = birthdate; + $form.candidate.sex = sex; */ + if (details !== undefined) { details.candidate.birthdate = details.candidate.birthdate.split('-').reverse().join('.'); @@ -413,6 +380,8 @@ gdpr: true, linkOk: true, linkError: false, + personalIdOk: true, + personalIdErr: false, candidate: { ...details.candidate, street: details.candidate.address.split(',')[0].split(' ')[0], @@ -436,7 +405,7 @@ } ] }); - pageIndex = 2; // skip gdpr page + pageIndex = editModePageIndex; // skip gdpr page pageTexts[2] = $LL.candidate.register.fourth.titleEdit(); } @@ -453,6 +422,21 @@ {/if} + {:else if pageIndex === 1}

{$LL.candidate.register.first.title()}

@@ -467,7 +451,7 @@ />

- {:else if pageIndex === 1} + {:else if pageIndex === 2}

{pageTexts[0]}

@@ -478,7 +462,7 @@

- {:else if pageIndex === 2} + {:else if pageIndex === 3}

{pageTexts[1]}

@@ -552,7 +536,7 @@

- {:else if pageIndex === 3} + {:else if pageIndex === 4}

{pageTexts[2]}

{$LL.candidate.register.fourth.description()} @@ -643,7 +627,7 @@

- {:else if pageIndex === 4} + {:else if pageIndex === 5}

{pageTexts[3]}

{$LL.candidate.register.fifth.description()} @@ -672,7 +656,7 @@ />

- {:else if pageIndex === 5} + {:else if pageIndex === 6}

{pageTexts[4]}

{$LL.candidate.register.sixth.description()} @@ -701,7 +685,7 @@ />

- {:else if pageIndex === 6} + {:else if pageIndex === 7}

Přihlášky na školy

@@ -711,8 +695,8 @@
- {:else if pageIndex === 7} -

{pageTexts[5]}

+ {:else if pageIndex === 8} +

{pageTexts[6]}

{$LL.candidate.register.eighth.description()}

diff --git a/frontend/src/translations/cs/index.ts b/frontend/src/translations/cs/index.ts index cc35d28..7e2e7c2 100644 --- a/frontend/src/translations/cs/index.ts +++ b/frontend/src/translations/cs/index.ts @@ -118,6 +118,12 @@ const cs: BaseTranslation = { title2: 'Ne, přihlášku na SSPŠaG jsem podával více přihlášek' } }, + personalIdConfirmCheckBox: { + ok: 'Vše je v pořádku', + whatHappened: 'Co se děje?', + titleOk: 'Potvrzuji, že moje rodné číslo je {personalId}', + titleErr: 'Ne, moje rodné číslo není {personalId}', + }, gdprCheckBox: { title: 'Souhlasím se zpracováním osobních údajů', description: 'Kliknutím vyjaďřujete souhlas se zpracováním osobních údajů', diff --git a/frontend/src/translations/i18n-types.ts b/frontend/src/translations/i18n-types.ts index b03dcbb..6af7424 100644 --- a/frontend/src/translations/i18n-types.ts +++ b/frontend/src/translations/i18n-types.ts @@ -272,6 +272,26 @@ type RootTranslation = { title2: string } } + personalIdConfirmCheckBox: { + /** + * V​š​e​ ​j​e​ ​v​ ​p​o​ř​á​d​k​u + */ + ok: string + /** + * C​o​ ​s​e​ ​d​ě​j​e​? + */ + whatHappened: string + /** + * P​o​t​v​r​z​u​j​i​,​ ​ž​e​ ​m​o​j​e​ ​r​o​d​n​é​ ​č​í​s​l​o​ ​j​e​ ​{​p​e​r​s​o​n​a​l​I​d​} + * @param {unknown} personalId + */ + titleOk: RequiredParams<'personalId'> + /** + * N​e​,​ ​m​o​j​e​ ​r​o​d​n​é​ ​č​í​s​l​o​ ​n​e​n​í​ ​{​p​e​r​s​o​n​a​l​I​d​} + * @param {unknown} personalId + */ + titleErr: RequiredParams<'personalId'> + } gdprCheckBox: { /** * S​o​u​h​l​a​s​í​m​ ​s​e​ ​z​p​r​a​c​o​v​á​n​í​m​ ​o​s​o​b​n​í​c​h​ ​ú​d​a​j​ů @@ -645,6 +665,24 @@ export type TranslationFunctions = { title2: () => LocalizedString } } + personalIdConfirmCheckBox: { + /** + * Vše je v pořádku + */ + ok: () => LocalizedString + /** + * Co se děje? + */ + whatHappened: () => LocalizedString + /** + * Potvrzuji, že moje rodné číslo je {personalId} + */ + titleOk: (arg: { personalId: unknown }) => LocalizedString + /** + * Ne, moje rodné číslo není {personalId} + */ + titleErr: (arg: { personalId: unknown }) => LocalizedString + } gdprCheckBox: { /** * Souhlasím se zpracováním osobních údajů From 7d16fe5b6ab29088ca6ffe8e1c5300cdd114ddfe Mon Sep 17 00:00:00 2001 From: Sebastian Pravda Date: Wed, 25 Jan 2023 22:48:16 +0100 Subject: [PATCH 06/21] fix: svelte check --- frontend/src/lib/components/select/SchoolSelect.svelte | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/components/select/SchoolSelect.svelte b/frontend/src/lib/components/select/SchoolSelect.svelte index a7edbc2..bbbe567 100644 --- a/frontend/src/lib/components/select/SchoolSelect.svelte +++ b/frontend/src/lib/components/select/SchoolSelect.svelte @@ -1,6 +1,7 @@ \ No newline at end of file From a87358a3b394c7acb832d2f5aaa5517141bc8c93 Mon Sep 17 00:00:00 2001 From: EETagent Date: Thu, 26 Jan 2023 21:15:44 +0100 Subject: [PATCH 09/21] feat: add more translations --- .../(authenticated)/register/+page.svelte | 82 ++++++++++--------- frontend/src/translations/cs/index.ts | 1 + frontend/src/translations/i18n-types.ts | 8 ++ 3 files changed, 53 insertions(+), 38 deletions(-) diff --git a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte index 4f01808..ca1f05f 100644 --- a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte +++ b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte @@ -25,7 +25,10 @@ import GradesTable from '$lib/components/grades/GradesTable.svelte'; import SchoolSelect from '$lib/components/select/SchoolSelect.svelte'; import PersonalIdConfirmCheckBox from '$lib/components/checkbox/PersonalIdConfirmCheckBox.svelte'; - import { deriveBirthdateFromPersonalId, isPersonalIdNumberWithBirthdateValid } from '$lib/utils/personalIdFormat'; + import { + deriveBirthdateFromPersonalId, + isPersonalIdNumberWithBirthdateValid + } from '$lib/utils/personalIdFormat'; let pageIndex = 0; let pagesFilled = [false, false, false, false, false, false, false, false]; @@ -72,9 +75,9 @@ schoolName: '', healthInsurance: '', grades: [], - firstSchool: {name: '', field: ''}, - secondSchool: {name: '', field: ''}, - testLanguage: '', + firstSchool: { name: '', field: '' }, + secondSchool: { name: '', field: '' }, + testLanguage: '' }, parents: [ { @@ -136,16 +139,17 @@ semester: yup.string().required() }) .required() - ).required(), + ) + .required(), firstSchool: yup.object().shape({ name: yup.string().required(), - field: yup.string().required(), + field: yup.string().required() }), secondSchool: yup.object().shape({ name: yup.string().required(), - field: yup.string().required(), + field: yup.string().required() }), - testLanguage: yup.string().required(), + testLanguage: yup.string().required() }), parents: yup.array().of( yup.object().shape({ @@ -276,8 +280,8 @@ const isPageInvalid = (index: number): boolean => { switch (index) { - case 0: - if ($typedErrors['personalIdOk'] || $typedErrors['personalIdErr']) { + case 0: + if ($typedErrors['personalIdOk'] || $typedErrors['personalIdErr']) { return true; } break; @@ -343,9 +347,12 @@ break; case 7: // @ts-ignore - if ($typedErrors["candidate"]["firstSchool"].name || $typedErrors["candidate"]["firstSchool"].field || + if ( + $typedErrors['candidate']['firstSchool'].name || + $typedErrors['candidate']['firstSchool'].field || // @ts-ignore - $typedErrors["candidate"]["secondSchool"].name || $typedErrors["candidate"]["secondSchool"].field + $typedErrors['candidate']['secondSchool'].name || + $typedErrors['candidate']['secondSchool'].field ) { return true; } @@ -363,7 +370,6 @@ return '+' + telephone.match(/[0-9]{1,3}/g)!.join(' '); }; - /* $form.candidate.personalIdNumber = data.whoami.personalIdNumber; const [birthdate, sex] = deriveBirthdateFromPersonalId(data.whoami.personalIdNumber); $form.candidate.birthdate = birthdate; @@ -473,17 +479,18 @@
+ /> - +
@@ -493,24 +500,24 @@ error={$typedErrors['candidate']['email']} bind:value={$form.candidate.email} placeholder={$LL.input.email()} - /> + /> - + + /> + error={$typedErrors['candidate']['city']} + bind:value={$form.candidate.city} + type="text" + placeholder={$LL.input.city()} + helperText="Uveďte poštovní směrovací číslo. (např. 602 00)" + />
@@ -550,7 +557,7 @@ options={['Česká republika', 'Slovenská republika', 'Ukrajina', 'Jiné']} /> - +
@@ -580,13 +587,13 @@ {:else} {/if}
@@ -605,14 +612,14 @@ error={$typedErrors['candidate']['schoolName']} type="number" bind:value={$form.candidate.schoolName} - placeholder="IZO školy" + placeholder={$LL.input.schoolIzo()} /> {:else} {/if} @@ -622,11 +629,10 @@ error={$typedErrors['candidate']['healthInsurance']} type="text" bind:value={$form.candidate.healthInsurance} - placeholder="Číslo zdravotní pojišťovny" - /> + placeholder={$LL.input.insuranceNumber()} + />
- {:else if pageIndex === 5}

{pageTexts[3]}

@@ -687,12 +693,12 @@ {:else if pageIndex === 7}

Přihlášky na školy

-
+
- + - +
{:else if pageIndex === 8} diff --git a/frontend/src/translations/cs/index.ts b/frontend/src/translations/cs/index.ts index 7e2e7c2..86c2888 100644 --- a/frontend/src/translations/cs/index.ts +++ b/frontend/src/translations/cs/index.ts @@ -134,6 +134,7 @@ const cs: BaseTranslation = { input: { optional: 'nepovinné', nameSurname: 'Jméno a příjmení', + birthSurname: "Rodné příjmení (pokud odlišné)", email: 'E-mail', telephone: 'Telefon', address: 'Ulice a č. p.', diff --git a/frontend/src/translations/i18n-types.ts b/frontend/src/translations/i18n-types.ts index 6af7424..41c923c 100644 --- a/frontend/src/translations/i18n-types.ts +++ b/frontend/src/translations/i18n-types.ts @@ -317,6 +317,10 @@ type RootTranslation = { * J​m​é​n​o​ ​a​ ​p​ř​í​j​m​e​n​í */ nameSurname: string + /** + * R​o​d​n​é​ ​p​ř​í​j​m​e​n​í​ ​(​p​o​k​u​d​ ​o​d​l​i​š​n​é​) + */ + birthSurname: string /** * E​-​m​a​i​l */ @@ -708,6 +712,10 @@ export type TranslationFunctions = { * Jméno a příjmení */ nameSurname: () => LocalizedString + /** + * Rodné příjmení (pokud odlišné) + */ + birthSurname: () => LocalizedString /** * E-mail */ From ece2d125552896cd7a0b309bd2ff726e8e303584 Mon Sep 17 00:00:00 2001 From: EETagent Date: Thu, 26 Jan 2023 21:17:07 +0100 Subject: [PATCH 10/21] feat: add school select translation --- .../lib/components/select/SchoolSelect.svelte | 6 ++++-- frontend/src/translations/cs/index.ts | 2 ++ frontend/src/translations/i18n-types.ts | 16 ++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/frontend/src/lib/components/select/SchoolSelect.svelte b/frontend/src/lib/components/select/SchoolSelect.svelte index 23b4aeb..5ee8daa 100644 --- a/frontend/src/lib/components/select/SchoolSelect.svelte +++ b/frontend/src/lib/components/select/SchoolSelect.svelte @@ -1,4 +1,6 @@
-
- - {$LL.input.selectedSchool()}: {selectedSchool.name} - - - - -
-
- {$LL.input.fieldOfStudy()}: - -
-
\ No newline at end of file +
+ + {$LL.input.selectedSchool()}: {selectedSchool.name} + + + + +
+
+ {$LL.input.fieldOfStudy()}: + +
+
From 0d013366de3450965ee5277ac2d46c5b42ba24e3 Mon Sep 17 00:00:00 2001 From: EETagent Date: Thu, 26 Jan 2023 21:19:17 +0100 Subject: [PATCH 12/21] fix: typescript errors --- .../(authenticated)/register/+page.svelte | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte index ca1f05f..94b6878 100644 --- a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte +++ b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte @@ -346,13 +346,16 @@ } break; case 7: - // @ts-ignore if ( - $typedErrors['candidate']['firstSchool'].name || - $typedErrors['candidate']['firstSchool'].field || + // TODO: Fix FormErrorType, make it recursive // @ts-ignore - $typedErrors['candidate']['secondSchool'].name || - $typedErrors['candidate']['secondSchool'].field + $typedErrors['candidate']['firstSchool']['name'] || + // @ts-ignore + $typedErrors['candidate']['firstSchool']['field'] || + // @ts-ignore + $typedErrors['candidate']['secondSchool']['name'] || + // @ts-ignore + $typedErrors['candidate']['secondSchool']['field'] ) { return true; } @@ -630,7 +633,7 @@ type="text" bind:value={$form.candidate.healthInsurance} placeholder={$LL.input.insuranceNumber()} - /> + />
{:else if pageIndex === 5} From 84b8e07e07edeb0bbac2beb602a5a8fdbbdf6782 Mon Sep 17 00:00:00 2001 From: EETagent Date: Thu, 26 Jan 2023 21:38:10 +0100 Subject: [PATCH 13/21] fix: frontend ui and mobile support --- .../lib/components/layout/SplitLayout.svelte | 4 +-- .../(authenticated)/register/+page.svelte | 30 ++++++++----------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/frontend/src/lib/components/layout/SplitLayout.svelte b/frontend/src/lib/components/layout/SplitLayout.svelte index 5726f5c..779d0b6 100644 --- a/frontend/src/lib/components/layout/SplitLayout.svelte +++ b/frontend/src/lib/components/layout/SplitLayout.svelte @@ -49,8 +49,8 @@ } .view { @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 md:h-screen md:w-[75vw]; + @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-[60vw]; @apply md:my-auto; @apply bg-white; } diff --git a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte index 94b6878..9d5c714 100644 --- a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte +++ b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte @@ -25,10 +25,7 @@ import GradesTable from '$lib/components/grades/GradesTable.svelte'; import SchoolSelect from '$lib/components/select/SchoolSelect.svelte'; import PersonalIdConfirmCheckBox from '$lib/components/checkbox/PersonalIdConfirmCheckBox.svelte'; - import { - deriveBirthdateFromPersonalId, - isPersonalIdNumberWithBirthdateValid - } from '$lib/utils/personalIdFormat'; + import { isPersonalIdNumberWithBirthdateValid } from '$lib/utils/personalIdFormat'; let pageIndex = 0; let pagesFilled = [false, false, false, false, false, false, false, false]; @@ -423,12 +420,9 @@
- - {#if pageIndex !== 0 && pageIndex !== 7} -
- -
- {/if} +
+ +
{#if $form.candidate.citizenship === 'Česká republika' || !$form.candidate.citizenship} From 8fbefbf9ced7322670299e536e6d94ade1bd1314 Mon Sep 17 00:00:00 2001 From: EETagent Date: Thu, 26 Jan 2023 22:19:04 +0100 Subject: [PATCH 14/21] feat: remove svelte autocomplete --- frontend/package.json | 1 - frontend/pnpm-lock.yaml | 7 ------- 2 files changed, 8 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index d07dad8..f10de62 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,7 +25,6 @@ "prettier": "^2.8.3", "prettier-plugin-svelte": "^2.9.0", "prettier-plugin-tailwindcss": "^0.2.1", - "simple-svelte-autocomplete": "^2.5.1", "svelte": "^3.55.1", "svelte-check": "^3.0.2", "svelte-preprocess": "^5.0.0", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index bb99b40..774c62b 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -75,9 +75,6 @@ devDependencies: prettier-plugin-tailwindcss: specifier: ^0.2.1 version: 0.2.1(prettier@2.8.3) - simple-svelte-autocomplete: - specifier: ^2.5.1 - version: 2.5.1 svelte: specifier: ^3.55.1 version: 3.55.1 @@ -2100,10 +2097,6 @@ packages: engines: {node: '>=8'} dev: true - /simple-svelte-autocomplete@2.5.1: - resolution: {integrity: sha512-wC0RzbmWhMMAqJ3PK+4sBSAHZl+Y/Qz7KDk1Wp5Fnxj+PJvOXWCIAOi5FLQZGrIMl82YKvFErzEtOCmfNOMUJg==} - dev: true - /sirv@2.0.2: resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==} engines: {node: '>= 10'} From 60323b9be5bb294067a6dd4db78365fcc6533b98 Mon Sep 17 00:00:00 2001 From: EETagent Date: Thu, 26 Jan 2023 22:20:13 +0100 Subject: [PATCH 15/21] feat: init school select component --- .../{static => src/lib/assets}/schoollist.txt | 0 .../lib/components/select/SchoolSelect.svelte | 36 ----- .../select/SchoolSelect/School.svelte | 41 ++++++ .../select/SchoolSelect/SchoolSelect.svelte | 136 ++++++++++++++++++ 4 files changed, 177 insertions(+), 36 deletions(-) rename frontend/{static => src/lib/assets}/schoollist.txt (100%) delete mode 100644 frontend/src/lib/components/select/SchoolSelect.svelte create mode 100644 frontend/src/lib/components/select/SchoolSelect/School.svelte create mode 100644 frontend/src/lib/components/select/SchoolSelect/SchoolSelect.svelte diff --git a/frontend/static/schoollist.txt b/frontend/src/lib/assets/schoollist.txt similarity index 100% rename from frontend/static/schoollist.txt rename to frontend/src/lib/assets/schoollist.txt diff --git a/frontend/src/lib/components/select/SchoolSelect.svelte b/frontend/src/lib/components/select/SchoolSelect.svelte deleted file mode 100644 index 93b31a7..0000000 --- a/frontend/src/lib/components/select/SchoolSelect.svelte +++ /dev/null @@ -1,36 +0,0 @@ - - -
-
- - {$LL.input.selectedSchool()}: {selectedSchool.name} - - - - -
-
- {$LL.input.fieldOfStudy()}: - -
-
diff --git a/frontend/src/lib/components/select/SchoolSelect/School.svelte b/frontend/src/lib/components/select/SchoolSelect/School.svelte new file mode 100644 index 0000000..2153e34 --- /dev/null +++ b/frontend/src/lib/components/select/SchoolSelect/School.svelte @@ -0,0 +1,41 @@ + + +
  • + {@html itemLabel} +
  • + + diff --git a/frontend/src/lib/components/select/SchoolSelect/SchoolSelect.svelte b/frontend/src/lib/components/select/SchoolSelect/SchoolSelect.svelte new file mode 100644 index 0000000..374a244 --- /dev/null +++ b/frontend/src/lib/components/select/SchoolSelect/SchoolSelect.svelte @@ -0,0 +1,136 @@ + + + + +
    +
    + + +
    + {#if filteredSchools.length > 0} +
      + {#each filteredSchools as country, i} + setInputVal(country)} + /> + {/each} +
    + {/if} +
    + + From 1b2125374d276cf75c92e3bfd1b16b4a54b83838 Mon Sep 17 00:00:00 2001 From: EETagent Date: Thu, 26 Jan 2023 22:41:58 +0100 Subject: [PATCH 16/21] feat: fix error type, add errors to school select, translated placeholders --- .../select/SchoolSelect/SchoolSelect.svelte | 20 +++++++++----- .../(authenticated)/register/+page.svelte | 26 ++++++++++++------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/frontend/src/lib/components/select/SchoolSelect/SchoolSelect.svelte b/frontend/src/lib/components/select/SchoolSelect/SchoolSelect.svelte index 374a244..cc77c2c 100644 --- a/frontend/src/lib/components/select/SchoolSelect/SchoolSelect.svelte +++ b/frontend/src/lib/components/select/SchoolSelect/SchoolSelect.svelte @@ -1,4 +1,6 @@ From 5be3c4cd21f18e1a39c70e4fab238641399f2160 Mon Sep 17 00:00:00 2001 From: EETagent Date: Thu, 26 Jan 2023 23:07:03 +0100 Subject: [PATCH 21/21] feat: require birthSurname --- .../routes/(candidate)/(authenticated)/register/+page.svelte | 4 +++- frontend/src/translations/cs/index.ts | 2 +- frontend/src/translations/i18n-types.ts | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte index 54e9fc4..d88e8f7 100644 --- a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte +++ b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte @@ -111,6 +111,7 @@ .string() .required() .matches(/^([0-3]?[0-9])\.(0?[1-9]|1[0-2])\.[0-9]{4}$/), + birthSurname: yup.string().required(), sex: yup.string(), address: yup.string(), street: yup.string().required(), @@ -382,6 +383,7 @@ details.parents.map( (x) => (x.telephone = x.telephone != '' ? formatTelephone(x.telephone) : '') ); + form.set({ gdpr: true, linkOk: true, @@ -703,7 +705,7 @@ bind:selectedSchool={$form.candidate.firstSchool} /> - + LocalizedString /** - * Rodné příjmení (pokud odlišné) + * Rodné příjmení */ birthSurname: () => LocalizedString /**