mirror of
https://github.com/danbulant/Portfolio
synced 2026-06-16 13:01:13 +00:00
feat: autofill birthdate and sex from CZ personalIdNumber
This commit is contained in:
parent
7d7a2b5faa
commit
1370881eee
4 changed files with 56 additions and 77 deletions
|
|
@ -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 = 'MUŽ';
|
||||
sex = 'Muž';
|
||||
} 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 = 'MUŽ';
|
||||
sex = 'Muž';
|
||||
}
|
||||
const day = Number(personalIdNumber.slice(4, 6));
|
||||
|
||||
|
|
|
|||
|
|
@ -8,4 +8,14 @@ export const pushErrorText = (text: string) => {
|
|||
'--toastBarBackground': '#7f1d1d'
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export const pushSuccessText = (text: string) => {
|
||||
toast.push(text, {
|
||||
theme: {
|
||||
'--toastColor': 'mintcream',
|
||||
'--toastBackground': '#047857',
|
||||
'--toastBarBackground': '#064e3b'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -23,11 +23,14 @@
|
|||
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,
|
||||
isPersonalIdNumberWithBirthdateValid
|
||||
} 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 } from '$lib/utils/toast';
|
||||
import { pushErrorText, pushSuccessText } from '$lib/utils/toast';
|
||||
|
||||
import schoolList from '$lib/assets/list/school.json';
|
||||
import countriesList from '$lib/assets/list/countries.json';
|
||||
|
|
@ -73,7 +76,7 @@
|
|||
city: '',
|
||||
zip: '',
|
||||
citizenship: '',
|
||||
personalIdNumber: '',
|
||||
personalIdNumber: 'TODO: remove this',
|
||||
schoolName: '',
|
||||
healthInsurance: '',
|
||||
grades: [],
|
||||
|
|
@ -132,7 +135,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
|
||||
|
|
@ -243,25 +246,6 @@
|
|||
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) => {
|
||||
if (pageIndex === pageCount) {
|
||||
|
|
@ -359,7 +343,7 @@
|
|||
$typedErrors['candidate']['healthInsurance'] ||
|
||||
$typedErrors['candidate']['birthdate'] ||
|
||||
$typedErrors['candidate']['birthplace'] ||
|
||||
$typedErrors['candidate']['personalIdNumber'] ||
|
||||
$typedErrors['candidate']['birthSurname'] ||
|
||||
$typedErrors['candidate']['testLanguage']
|
||||
) {
|
||||
return true;
|
||||
|
|
@ -409,11 +393,19 @@
|
|||
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; */
|
||||
$: if ($form.candidate.citizenship === 'Česká republika') {
|
||||
if ($form.candidate.birthdate === '' && $form.candidate.sex === '') {
|
||||
let [birthdate, sex] = parseBirthdateSexFromPersonalId(data.whoami.personalIdNumber);
|
||||
$form.candidate.birthdate = birthdate;
|
||||
$form.candidate.sex = sex;
|
||||
pushSuccessText(
|
||||
`Datum narození a pohlaví bylo vyplněno automaticky podle Vašeho rodného čísla (${data.whoami.personalIdNumber}).`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$form.candidate.birthdate = '';
|
||||
$form.candidate.sex = '';
|
||||
}
|
||||
|
||||
if (details !== undefined) {
|
||||
details.candidate.birthdate = details.candidate.birthdate.split('-').reverse().join('.');
|
||||
|
|
@ -525,24 +517,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()} (${$LL.input.optional()})`}
|
||||
/>
|
||||
</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']}
|
||||
|
|
@ -636,19 +618,11 @@
|
|||
</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']}
|
||||
|
|
@ -805,9 +779,6 @@
|
|||
<Submit
|
||||
enterAllowed={pageIndex !== 7}
|
||||
on:click={async (e) => {
|
||||
if (pageIndex === 4) {
|
||||
validatePersonalId();
|
||||
}
|
||||
await handleSubmit(e);
|
||||
if (isPageInvalid(pageIndex)) return;
|
||||
if (pageIndex !== pageCount) {
|
||||
|
|
@ -826,9 +797,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));
|
||||
|
|
|
|||
|
|
@ -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í',
|
||||
|
|
|
|||
Loading…
Reference in a new issue