diff --git a/frontend/src/lib/@api/candidate.ts b/frontend/src/lib/@api/candidate.ts index fcd82b9..251a64e 100644 --- a/frontend/src/lib/@api/candidate.ts +++ b/frontend/src/lib/@api/candidate.ts @@ -79,11 +79,22 @@ export const apiLogin = async (data: CandidateLogin): Promise => { }; export const apiFillDetails = async (data: CandidateData): Promise => { - Object.keys(data).forEach((key) => { + // Sanitize candidate data + Object.keys(data.candidate).forEach((key) => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - data[key] = DOMPurify.sanitize(data[key]); + data.candidate[key] = DOMPurify.sanitize(data.candidate[key]); }); + // Sanitize parents data + for (let index = 0; index < data.parents.length; index++) { + Object.keys(data.parents[index]).forEach((key) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + data.parents[index][key] = DOMPurify.sanitize(data.parents[index][key]); + }); + } + + console.log(data); try { const res = await axios.post(API_URL + '/candidate/details', data, { withCredentials: true }); return res.data; diff --git a/frontend/src/lib/stores/candidate.ts b/frontend/src/lib/stores/candidate.ts index 0d152af..e0ba7ee 100644 --- a/frontend/src/lib/stores/candidate.ts +++ b/frontend/src/lib/stores/candidate.ts @@ -1,21 +1,25 @@ import { writable } from 'svelte/store'; export interface CandidateData { - name?: string; - surname?: string; - birthplace?: string; - birthdate?: string; - address?: string; - telephone?: string; - citizenship?: string; - email?: string; - sex?: string; - study?: string; - personalIdNumber?: string; - parentName?: string; - parentSurname?: string; - parentTelephone?: string; - parentEmail?: string; + candidate: { + name?: string; + surname?: string; + birthplace?: string; + birthdate?: string; + address?: string; + telephone?: string; + citizenship?: string; + email?: string; + sex?: string; + study?: string; + personalIdNumber?: string; + }; + parents: Array<{ + name?: string; + surname?: string; + telephone?: string; + email?: string; + }>; } export interface CandidatePreview { diff --git a/frontend/src/routes/(candidate)/(authenticated)/dashboard/+page.svelte b/frontend/src/routes/(candidate)/(authenticated)/dashboard/+page.svelte index 0fd5d9d..50fbfe3 100644 --- a/frontend/src/routes/(candidate)/(authenticated)/dashboard/+page.svelte +++ b/frontend/src/routes/(candidate)/(authenticated)/dashboard/+page.svelte @@ -34,8 +34,8 @@
- - {$candidateData.email} + + {$candidateData.candidate.email} Uchazeč na SSPŠ
@@ -51,8 +51,8 @@
- - {$candidateData.email} + + {$candidateData.candidate.email} Uchazeč na SSPŠ
diff --git a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte index 107bdc6..7d1d74d 100644 --- a/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte +++ b/frontend/src/routes/(candidate)/(authenticated)/register/+page.svelte @@ -12,8 +12,10 @@ import NameField from '$lib/components/textfield/NameField.svelte'; import TelephoneField from '$lib/components/textfield/TelephoneField.svelte'; import TextField from '$lib/components/textfield/TextField.svelte'; + import type { CandidateData } from '$lib/stores/candidate'; import { createForm } from 'svelte-forms-lib'; + import type { Writable } from 'svelte/store'; import * as yup from 'yup'; const pageCount = 3; @@ -21,26 +23,31 @@ let pagesFilled = 0; const formInitialValues = { - name: '', - surname: '', - email: '', - telephone: '', - birthplace: '', - birthdate: '', - sex: '', - address: '', - citizenship: '', - personalIdNumber: '', - study: '', - parentName: '', - parentSurname: '', - parentTelephone: '', - parentEmail: '' + candidate: { + name: '', + surname: '', + email: '', + telephone: '', + birthplace: '', + birthdate: '', + sex: '', + address: '', + citizenship: '', + personalIdNumber: '', + study: '', + }, + parents: [ + { + name: '', + surname: '', + email: '', + telephone: '' + } + ] }; - const { form, errors, handleSubmit, handleChange } = createForm({ - initialValues: formInitialValues, - validationSchema: yup.object().shape({ + const formValidationSchema = yup.object().shape({ + candidate: yup.object().shape({ name: yup.string().required(), surname: yup.string(), email: yup.string().email().required(), @@ -49,28 +56,55 @@ .required() .matches(/^\+\d{1,3} \d{3} \d{3} \d{3}$/), birthplace: yup.string().required(), - birthdate: yup.string().required(), + birthdate: yup + .string() + .required() + .matches(/^([0-3]?[0-9])\.([1-9]|1[0-2])\.[0-9]{4}$/), sex: yup.string(), address: yup.string().required(), citizenship: yup.string().required(), personalIdNumber: yup.string().required(), - study: yup.string().required(), - parentName: yup.string(), - parentSurname: yup.string(), - parentTelephone: yup - .string() - .required() - .matches(/^\+\d{1,3} \d{3} \d{3} \d{3}$/), - parentEmail: yup.string().email().required() + study: yup.string().required() }), + parents: yup + .array() + .of( + yup.object().shape({ + name: yup.string().required(), + surname: yup.string().required(), + email: yup.string().email().required(), + telephone: yup + .string() + .required() + .matches(/^\+\d{1,3} \d{3} \d{3} \d{3}$/) + }) + ) + .required() + }); - onSubmit: async (values) => { + const { form, errors, handleSubmit, handleChange } = createForm({ + initialValues: formInitialValues, + validationSchema: formValidationSchema, + + onSubmit: async (values: CandidateData) => { + console.log('page count: ' + pageIndex); + console.log(values.candidate); + console.log(values.parents); + console.log(values); if (pageIndex === pageCount) { try { console.log('submit'); // @ts-ignore // love javascript delete values.undefined; - values.birthdate = '2000-01-01'; // TODO: reformat user typed date + // convert birthdate from dd.mm.yyyy to yyyy-mm-dd + let birthdate_formttted = values.candidate + .birthdate!.split('.') + .map((x) => x.padStart(2, '0')) + .reverse() + .join('-'); + + values.candidate.birthdate = birthdate_formttted; + await apiFillDetails(values); goto('/dashboard'); } catch (e) { @@ -80,35 +114,57 @@ } }); - $: console.log($errors); + type FormErrorType = { + [K in keyof typeof formInitialValues]: typeof formInitialValues[K] extends Record< + string, + unknown + > + ? { + [K2 in keyof typeof formInitialValues[K]]: string; + } + : typeof formInitialValues[K] extends Array> + ? Array<{ [K3 in keyof typeof formInitialValues[K][number]]: string }> + : string; + }; + + // TODO: https://github.com/tjinauyeung/svelte-forms-lib/issues/171!! (Zatím tenhle mega typ) + $: typedErrors = errors as unknown as Writable; const isPageInvalid = (): boolean => { switch (pageIndex) { case 0: - if ($errors.name || $errors.email || $errors.telephone) { + if ( + $typedErrors['candidate']['name'] || + $typedErrors['candidate']['email'] || + $typedErrors['candidate']['telephone'] + ) { return true; } break; case 1: if ( - /* $errors.birthdurname || */ $errors.birthplace || - $errors.birthdate /* || $errors.sex */ + /* $typedErrors.birthdurname || */ $typedErrors['candidate']['birthplace'] || + $typedErrors['candidate']['birthdate'] /* || $typedErrors.sex */ ) { return true; } break; case 2: - if ($errors.address || $errors.parentEmail || $errors.parentTelephone) { + if ( + $typedErrors['candidate']['address'] || + $typedErrors['parents'][0]['email'] || + $typedErrors['parents'][0]['telephone'] + ) { return true; } break; case 3: if ( - $errors.citizenship || - $errors.personalIdNumber || - $errors.study //|| - // $errors.applicationId + $typedErrors['candidate']['citizenship'] || + $typedErrors['candidate']['personalIdNumber'] || + $typedErrors['candidate']['study'] //|| + // $typedErrors.applicationId ) { return true; } @@ -135,27 +191,27 @@
@@ -169,23 +225,23 @@
-
+
@@ -194,17 +250,17 @@
@@ -219,9 +275,9 @@
@@ -229,17 +285,17 @@
@@ -254,9 +310,9 @@
@@ -267,16 +323,16 @@
@@ -295,6 +351,7 @@ pagesFilled++; pageIndex++; } + // @ts-ignore errors.set(formInitialValues); }} value={pageIndex === pageCount ? 'Odeslat' : 'Pokračovat'} @@ -315,6 +372,7 @@ if (isPageInvalid()) return; pagesFilled++; pageIndex++; + // @ts-ignore errors.set(formInitialValues); } }}