mirror of
https://github.com/danbulant/Portfolio
synced 2026-07-07 12:00:43 +00:00
Merge pull request #188 from EETagent/tel_input_all_countries
(frontend) Telephone input for all countries
This commit is contained in:
commit
6ee371b288
5 changed files with 201 additions and 87 deletions
|
|
@ -43,7 +43,9 @@
|
||||||
"fuse.js": "^6.6.2",
|
"fuse.js": "^6.6.2",
|
||||||
"isomorphic-dompurify": "^0.26.0",
|
"isomorphic-dompurify": "^0.26.0",
|
||||||
"just-debounce-it": "^3.2.0",
|
"just-debounce-it": "^3.2.0",
|
||||||
|
"libphonenumber-js": "^1.10.19",
|
||||||
"svelte-forms-lib": "^2.0.1",
|
"svelte-forms-lib": "^2.0.1",
|
||||||
|
"svelte-tel-input": "^1.1.2",
|
||||||
"svelte-tippy": "^1.3.2",
|
"svelte-tippy": "^1.3.2",
|
||||||
"swiper": "^8.4.6",
|
"swiper": "^8.4.6",
|
||||||
"tippy.js": "^6.3.7",
|
"tippy.js": "^6.3.7",
|
||||||
|
|
|
||||||
|
|
@ -22,9 +22,15 @@ dependencies:
|
||||||
just-debounce-it:
|
just-debounce-it:
|
||||||
specifier: ^3.2.0
|
specifier: ^3.2.0
|
||||||
version: 3.2.0
|
version: 3.2.0
|
||||||
|
libphonenumber-js:
|
||||||
|
specifier: ^1.10.19
|
||||||
|
version: 1.10.19
|
||||||
svelte-forms-lib:
|
svelte-forms-lib:
|
||||||
specifier: ^2.0.1
|
specifier: ^2.0.1
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
|
svelte-tel-input:
|
||||||
|
specifier: ^1.1.2
|
||||||
|
version: 1.1.2
|
||||||
svelte-tippy:
|
svelte-tippy:
|
||||||
specifier: ^1.3.2
|
specifier: ^1.3.2
|
||||||
version: 1.3.2
|
version: 1.3.2
|
||||||
|
|
@ -1677,6 +1683,10 @@ packages:
|
||||||
type-check: 0.4.0
|
type-check: 0.4.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/libphonenumber-js@1.10.19:
|
||||||
|
resolution: {integrity: sha512-MDZ1zLIkfSDZV5xBta3nuvbEOlsnKCPe4z5r3hyup/AXveevkl9A1eSWmLhd2FX4k7pJDe4MrLeQsux0HI/VWg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/locate-path@6.0.0:
|
/locate-path@6.0.0:
|
||||||
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
@ -2307,6 +2317,14 @@ packages:
|
||||||
typescript: 4.9.4
|
typescript: 4.9.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/svelte-tel-input@1.1.2:
|
||||||
|
resolution: {integrity: sha512-KJxV/4h2JJ6b2Gh6WfXwfukXcW02SHai65jZAfV6DuT3Mu0zhfZ7Lu4iyi9PAOaLQzEVQ3UpwBEBXH3B7YCIog==}
|
||||||
|
engines: {node: '>= 16', npm: '>= 7', pnpm: '>= 7', yarn: '>=2'}
|
||||||
|
dependencies:
|
||||||
|
libphonenumber-js: 1.10.19
|
||||||
|
svelte: 3.55.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/svelte-tippy@1.3.2:
|
/svelte-tippy@1.3.2:
|
||||||
resolution: {integrity: sha512-41f+85hwhKBRqX0UNYrgFsi34Kk/KDvUkIZXYANxkWoA2NTVTCZbUC2J8hRNZ4TRVxObTshoZRjK2co5+i6LMw==}
|
resolution: {integrity: sha512-41f+85hwhKBRqX0UNYrgFsi34Kk/KDvUkIZXYANxkWoA2NTVTCZbUC2J8hRNZ4TRVxObTshoZRjK2co5+i6LMw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -2326,7 +2344,6 @@ packages:
|
||||||
/svelte@3.55.1:
|
/svelte@3.55.1:
|
||||||
resolution: {integrity: sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==}
|
resolution: {integrity: sha512-S+87/P0Ve67HxKkEV23iCdAh/SX1xiSfjF1HOglno/YTbSTW7RniICMCofWGdJJbdjw3S+0PfFb1JtGfTXE0oQ==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/swiper@8.4.6:
|
/swiper@8.4.6:
|
||||||
resolution: {integrity: sha512-HACW035vBz2T6Kfut23EAzXhcDpgR8doX+wjq0ZUvJgS5SQApGrV885DAPLBFnmPUISsAhNSVxPKDxqroFvXvQ==}
|
resolution: {integrity: sha512-HACW035vBz2T6Kfut23EAzXhcDpgR8doX+wjq0ZUvJgS5SQApGrV885DAPLBFnmPUISsAhNSVxPKDxqroFvXvQ==}
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,119 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Telephone from '../icons/Telephone.svelte';
|
import Telephone from '../icons/Telephone.svelte';
|
||||||
import TextField from './TextField.svelte';
|
import { tippy } from 'svelte-tippy';
|
||||||
|
import 'tippy.js/dist/tippy.css';
|
||||||
|
|
||||||
let helperText: string = 'Zadejte platný telefon s předvolbou. Například +420 123 456 789';
|
const helperText: string = 'Zadejte platný telefon s předvolbou. Například +420 123 456 789';
|
||||||
export let placeholder: string = '';
|
export let placeholder: string = ''; // TODO
|
||||||
|
|
||||||
export let value: string = '';
|
import TelInput, { normalizedCountries } from 'svelte-tel-input';
|
||||||
export let error: string = '';
|
import type { NormalizedTelNumber, CountryCode, E164Number } from 'svelte-tel-input/types';
|
||||||
|
import { parsePhoneNumber } from 'libphonenumber-js';
|
||||||
|
|
||||||
// Phone Number formatting
|
// Any Country Code Alpha-2 (ISO 3166)
|
||||||
$: {
|
let country: CountryCode | null = 'CZ';
|
||||||
let x = value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,3})(\d{0,3})/)!;
|
|
||||||
value =
|
// You must use E164 number format. It's guarantee the parsing and storing consistency.
|
||||||
(x[1] ? '+' + x[1] : '') +
|
export let value: E164Number | null;
|
||||||
(x[2] ? ' ' + x[2] : '') +
|
if (value !== null && value !== "" ) {
|
||||||
(x[3] ? ' ' + x[3] : '') +
|
let number = parsePhoneNumber(value);
|
||||||
(x[4] ? ' ' + x[4] : '');
|
if (number !== null && number !== undefined) {
|
||||||
|
country = number.country!;
|
||||||
|
}
|
||||||
|
// console.log(country);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validity
|
||||||
|
let valid = true;
|
||||||
|
export let error: string = '';
|
||||||
|
$: error = valid ? '' : 'Zadejte platný telefon s předvolbou. Například +420 123 456 789';
|
||||||
|
|
||||||
|
// Optional - Extended details about the parsed phone number
|
||||||
|
let parsedTelInput: NormalizedTelNumber | null = null;
|
||||||
|
|
||||||
|
let selectedCountry: string | null = country;
|
||||||
|
|
||||||
|
const countrySelect = (e: any) => {
|
||||||
|
selectedCountry = e.target.value;
|
||||||
|
// @ts-ignore
|
||||||
|
country = selectedCountry;
|
||||||
|
value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isTooltip = helperText ? tippy : () => {};
|
||||||
|
$: tooltipDelay = error ? 0 : 1000;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<TextField
|
<div
|
||||||
bind:error
|
class="wrapper flex h-full w-full"
|
||||||
bind:value
|
use:isTooltip={{
|
||||||
on:keydown
|
content: helperText,
|
||||||
on:keyup
|
placement: 'top',
|
||||||
on:change
|
showOnCreate: false,
|
||||||
type="tel"
|
delay: tooltipDelay
|
||||||
{placeholder}
|
}}
|
||||||
{helperText}
|
|
||||||
icon
|
|
||||||
>
|
>
|
||||||
<div slot="icon" class="flex items-center justify-center">
|
<select
|
||||||
<Telephone />
|
class="countrySelect"
|
||||||
|
class:invalid={error}
|
||||||
|
aria-label="Default select example"
|
||||||
|
name="Country"
|
||||||
|
bind:value={selectedCountry}
|
||||||
|
on:input={countrySelect}
|
||||||
|
>
|
||||||
|
<option value={null} hidden={selectedCountry !== null}>Země</option>
|
||||||
|
{#each normalizedCountries as country (country.id)}
|
||||||
|
<option
|
||||||
|
value={country.iso2}
|
||||||
|
selected={country.iso2 === selectedCountry}
|
||||||
|
aria-selected={country.iso2 === selectedCountry}
|
||||||
|
>
|
||||||
|
{country.name.split('(').length > 1
|
||||||
|
? country.name.split('(')[1].replace(')', '')
|
||||||
|
: country.name} (+{country.dialCode})
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
<div class="inputWrapper ml-2">
|
||||||
|
<TelInput
|
||||||
|
bind:country
|
||||||
|
bind:value
|
||||||
|
bind:valid
|
||||||
|
bind:parsedTelInput
|
||||||
|
class="basic-tel-input {error ? 'invalid' : ''}"
|
||||||
|
{placeholder}
|
||||||
|
/>
|
||||||
|
<span class="tel-icon">
|
||||||
|
<Telephone />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</TextField>
|
</div>
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
|
select {
|
||||||
|
@apply border-1 h-full w-2/5 rounded pl-3 pr-3;
|
||||||
|
@apply hover:border-sspsBlue rounded-lg border border-2 bg-[#f8fafb] p-3 text-xl shadow-lg outline-none transition-colors duration-300;
|
||||||
|
}
|
||||||
|
.inputWrapper {
|
||||||
|
@apply relative w-full;
|
||||||
|
}
|
||||||
|
.tel-icon {
|
||||||
|
@apply absolute right-0 top-1 bottom-0 my-auto flex bg-transparent p-3;
|
||||||
|
}
|
||||||
|
.wrapper :global(.basic-tel-input) {
|
||||||
|
/* height: 32px;
|
||||||
|
padding-left: 12px;
|
||||||
|
padding-right: 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid;
|
||||||
|
outline: none;
|
||||||
|
width: 100%; */
|
||||||
|
/* @apply h-full pl-3 pr-3 border-1 w-full rounded; */
|
||||||
|
@apply hover:border-sspsBlue w-full rounded-lg border border-2 bg-[#f8fafb] p-3 text-xl shadow-lg outline-none transition-colors duration-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper :global(.invalid) {
|
||||||
|
/* border-color: red; */
|
||||||
|
@apply border-red-700;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
import { apiFillDetails } from '$lib/@api/candidate';
|
import { apiFillDetails } from '$lib/@api/candidate';
|
||||||
import Submit from '$lib/components/button/Submit.svelte';
|
import Submit from '$lib/components/button/Submit.svelte';
|
||||||
import GdprCheckBox from '$lib/components/checkbox/GdprCheckBox.svelte';
|
import GdprCheckBox from '$lib/components/checkbox/GdprCheckBox.svelte';
|
||||||
|
|
||||||
import SchoolBadge from '$lib/components/icons/SchoolBadge.svelte';
|
import SchoolBadge from '$lib/components/icons/SchoolBadge.svelte';
|
||||||
import SplitLayout from '$lib/components/layout/SplitLayout.svelte';
|
import SplitLayout from '$lib/components/layout/SplitLayout.svelte';
|
||||||
import SelectField from '$lib/components/select/SelectField.svelte';
|
import SelectField from '$lib/components/select/SelectField.svelte';
|
||||||
|
|
@ -16,9 +15,8 @@
|
||||||
import TextField from '$lib/components/textfield/TextField.svelte';
|
import TextField from '$lib/components/textfield/TextField.svelte';
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { SvelteToast, toast } from '@zerodevx/svelte-toast';
|
import { SvelteToast, toast } from '@zerodevx/svelte-toast';
|
||||||
|
import parsePhoneNumber from 'libphonenumber-js';
|
||||||
import { createForm } from 'svelte-forms-lib';
|
import { createForm } from 'svelte-forms-lib';
|
||||||
import type { Writable } from 'svelte/store';
|
|
||||||
import * as yup from 'yup';
|
import * as yup from 'yup';
|
||||||
import type { CandidateData } from '$lib/stores/candidate';
|
import type { CandidateData } from '$lib/stores/candidate';
|
||||||
import AccountLinkCheckBox from '$lib/components/checkbox/AccountLinkCheckBox.svelte';
|
import AccountLinkCheckBox from '$lib/components/checkbox/AccountLinkCheckBox.svelte';
|
||||||
|
|
@ -28,11 +26,13 @@
|
||||||
import { isPersonalIdNumberWithBirthdateValid } from '$lib/utils/personalIdFormat';
|
import { isPersonalIdNumberWithBirthdateValid } 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';
|
||||||
|
|
||||||
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];
|
||||||
let editModePageIndex = 3;
|
const editModePageIndex = 3;
|
||||||
const pageCount = pagesFilled.length;
|
const pageCount = pagesFilled.length;
|
||||||
|
|
||||||
let pageTexts = [
|
let pageTexts = [
|
||||||
$LL.candidate.register.second.title(),
|
$LL.candidate.register.second.title(),
|
||||||
$LL.candidate.register.third.title(),
|
$LL.candidate.register.third.title(),
|
||||||
|
|
@ -47,7 +47,6 @@
|
||||||
let details = data.candidate;
|
let details = data.candidate;
|
||||||
let baseCandidateDetails = data.whoami;
|
let baseCandidateDetails = data.whoami;
|
||||||
|
|
||||||
let personalIdBirthdateMatch = true;
|
|
||||||
const formInitialValues = {
|
const formInitialValues = {
|
||||||
gdpr: false,
|
gdpr: false,
|
||||||
personalIdOk: false,
|
personalIdOk: false,
|
||||||
|
|
@ -107,7 +106,12 @@
|
||||||
telephone: yup
|
telephone: yup
|
||||||
.string()
|
.string()
|
||||||
.required()
|
.required()
|
||||||
.matches(/^\+\d{1,3} \d{3} \d{3} \d{3}$/),
|
.test((_val) => {
|
||||||
|
if (!_val) return false;
|
||||||
|
const number = parsePhoneNumber(_val);
|
||||||
|
if (!number) return false;
|
||||||
|
return number.isValid();
|
||||||
|
}), // already validated by the 'TelephoneField' component
|
||||||
birthplace: yup.string().required(),
|
birthplace: yup.string().required(),
|
||||||
birthdate: yup
|
birthdate: yup
|
||||||
.string()
|
.string()
|
||||||
|
|
@ -175,10 +179,13 @@
|
||||||
return _val !== '';
|
return _val !== '';
|
||||||
}),
|
}),
|
||||||
telephone: yup.string().test((_val, context) => {
|
telephone: yup.string().test((_val, context) => {
|
||||||
if (context.path.includes('parents[1]') && _val === '') {
|
if (context.path.includes('parents[1]')) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return _val?.match(/^\+\d{1,3} \d{3} \d{3} \d{3}$/) !== null;
|
if (!_val) return false;
|
||||||
|
const number = parsePhoneNumber(_val);
|
||||||
|
if (!number) return false;
|
||||||
|
return number.isValid();
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
@ -209,29 +216,30 @@
|
||||||
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) => {
|
||||||
if (pageIndex === 3) {
|
console.log('submit button clicked');
|
||||||
if (values.candidate.citizenship === 'Česká republika') {
|
console.log(pagesFilled.map((_, i) => !isPageInvalid(i)));
|
||||||
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) {
|
if (pageIndex === pageCount) {
|
||||||
console.log('submitting');
|
console.log('submitting');
|
||||||
// clone values to oldValues
|
// clone values to oldValues
|
||||||
|
|
@ -286,7 +294,6 @@
|
||||||
|
|
||||||
onSubmit: async (values: CandidateData) => onSubmit(values)
|
onSubmit: async (values: CandidateData) => onSubmit(values)
|
||||||
});
|
});
|
||||||
|
|
||||||
const isPageInvalid = (index: number): boolean => {
|
const isPageInvalid = (index: number): boolean => {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|
@ -330,8 +337,7 @@
|
||||||
$typedErrors['candidate']['birthdate'] ||
|
$typedErrors['candidate']['birthdate'] ||
|
||||||
$typedErrors['candidate']['birthplace'] ||
|
$typedErrors['candidate']['birthplace'] ||
|
||||||
$typedErrors['candidate']['personalIdNumber'] ||
|
$typedErrors['candidate']['personalIdNumber'] ||
|
||||||
$typedErrors['candidate']['testLanguage'] ||
|
$typedErrors['candidate']['testLanguage']
|
||||||
!personalIdBirthdateMatch
|
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -511,31 +517,33 @@
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="field flex">
|
<span class="field ml-2">
|
||||||
<span class="w-[50%]">
|
<TelephoneField
|
||||||
<EmailField
|
bind:error={$typedErrors['candidate']['telephone']}
|
||||||
error={$typedErrors['candidate']['email']}
|
bind:value={$form.candidate.telephone}
|
||||||
bind:value={$form.candidate.email}
|
placeholder={$LL.input.telephone()}
|
||||||
placeholder={$LL.input.email()}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<span class="ml-2 w-[50%]">
|
|
||||||
<TelephoneField
|
|
||||||
error={$typedErrors['candidate']['telephone']}
|
|
||||||
bind:value={$form.candidate.telephone}
|
|
||||||
placeholder={$LL.input.telephone()}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<span class="field">
|
|
||||||
<TextField
|
|
||||||
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)"
|
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
<div>
|
||||||
|
<div class="field flex">
|
||||||
|
<span class="w-[50%]">
|
||||||
|
<EmailField
|
||||||
|
error={$typedErrors['candidate']['email']}
|
||||||
|
bind:value={$form.candidate.email}
|
||||||
|
placeholder={$LL.input.email()}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span class="ml-2 w-[50%]">
|
||||||
|
<TextField
|
||||||
|
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)"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field flex">
|
<div class="field flex">
|
||||||
<span class="w-[66%]">
|
<span class="w-[66%]">
|
||||||
|
|
@ -675,7 +683,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="field">
|
<span class="field">
|
||||||
<TelephoneField
|
<TelephoneField
|
||||||
error={$typedErrors['parents'][0]['telephone']}
|
bind:error={$typedErrors['parents'][0]['telephone']}
|
||||||
bind:value={$form.parents[0].telephone}
|
bind:value={$form.parents[0].telephone}
|
||||||
placeholder={$LL.input.parent.telephone()}
|
placeholder={$LL.input.parent.telephone()}
|
||||||
/>
|
/>
|
||||||
|
|
@ -704,7 +712,7 @@
|
||||||
</span>
|
</span>
|
||||||
<span class="field">
|
<span class="field">
|
||||||
<TelephoneField
|
<TelephoneField
|
||||||
error={$typedErrors['parents'][1]['telephone']}
|
bind:error={$typedErrors['parents'][1]['telephone']}
|
||||||
bind:value={$form.parents[1].telephone}
|
bind:value={$form.parents[1].telephone}
|
||||||
placeholder={`${$LL.input.parent.telephone()} (${$LL.input.optional()})`}
|
placeholder={`${$LL.input.parent.telephone()} (${$LL.input.optional()})`}
|
||||||
/>
|
/>
|
||||||
|
|
@ -746,10 +754,14 @@
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<Submit
|
<Submit
|
||||||
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) {
|
||||||
} else {
|
|
||||||
pagesFilled[pageIndex] = true;
|
pagesFilled[pageIndex] = true;
|
||||||
pageIndex++;
|
pageIndex++;
|
||||||
}
|
}
|
||||||
|
|
@ -765,6 +777,9 @@
|
||||||
<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));
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<SchoolBadge />
|
<SchoolBadge />
|
||||||
<h1 class="text-sspsBlue mt-8 text-4xl font-semibold">{$LL.candidate.auth.login.title()}</h1>
|
<h1 class="text-sspsBlue mt-8 text-4xl font-semibold">{$LL.candidate.auth.login.title()}</h1>
|
||||||
<p class="text-sspsGray my-8 text-center font-light">
|
<p class="text-gray-700 my-8 text-center">
|
||||||
{$LL.candidate.auth.login.description()}
|
{$LL.candidate.auth.login.description()}
|
||||||
</p>
|
</p>
|
||||||
<div class="w-4/5 lg:w-3/5">
|
<div class="w-4/5 lg:w-3/5">
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue