feat: tel input refactor

This commit is contained in:
EETagent 2023-02-03 16:14:41 +01:00
parent 915708f2e8
commit 5eb27733f1
2 changed files with 69 additions and 79 deletions

View file

@ -15,10 +15,10 @@
// You must use E164 number format. It's guarantee the parsing and storing consistency. // You must use E164 number format. It's guarantee the parsing and storing consistency.
export let value: E164Number | null = '+36301234567'; export let value: E164Number | null = '+36301234567';
// Validity // Validity
let valid = true; let valid = true;
export let invalid: boolean = false; export let error: string = '';
$: invalid = !valid; $: error = valid ? '' : 'Zadejte platný telefon s předvolbou. Například +420 123 456 789';
// Optional - Extended details about the parsed phone number // Optional - Extended details about the parsed phone number
let parsedTelInput: NormalizedTelNumber | null = null; let parsedTelInput: NormalizedTelNumber | null = null;
@ -33,10 +33,11 @@
}; };
const isTooltip = helperText ? tippy : () => {}; const isTooltip = helperText ? tippy : () => {};
$: tooltipDelay = invalid ? 0 : 1000; $: tooltipDelay = !valid ? 0 : 1000;
</script> </script>
<div class="wrapper w-full h-full flex" <div
class="wrapper flex h-full w-full"
use:isTooltip={{ use:isTooltip={{
content: helperText, content: helperText,
placement: 'top', placement: 'top',
@ -45,7 +46,8 @@
}} }}
> >
<select <select
class="countrySelect {!valid && 'invalid'}" class="countrySelect"
class:invalid={error}
aria-label="Default select example" aria-label="Default select example"
name="Country" name="Country"
bind:value={selectedCountry} bind:value={selectedCountry}
@ -62,11 +64,15 @@
</option> </option>
{/each} {/each}
</select> </select>
<div class="ml-2 inputWrapper"> <div class="inputWrapper ml-2">
<TelInput bind:country bind:value bind:valid bind:parsedTelInput <TelInput
class="basic-tel-input {!valid ? 'invalid' : '' }" bind:country
{placeholder} bind:value
/> bind:valid
bind:parsedTelInput
class="basic-tel-input {error ? 'invalid' : ''}"
{placeholder}
/>
<span class="tel-icon"> <span class="tel-icon">
<Telephone /> <Telephone />
</span> </span>
@ -75,29 +81,29 @@
<style lang="postcss"> <style lang="postcss">
select { select {
@apply h-full pl-3 pr-3 border-1 w-2/5 rounded; @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; @apply hover:border-sspsBlue rounded-lg border border-2 bg-[#f8fafb] p-3 text-xl shadow-lg outline-none transition-colors duration-300;
} }
.inputWrapper { .inputWrapper {
@apply w-full relative; @apply relative w-full;
} }
.tel-icon { .tel-icon {
@apply absolute right-0 top-1 bottom-0 my-auto flex bg-transparent p-3; @apply absolute right-0 top-1 bottom-0 my-auto flex bg-transparent p-3;
} }
.wrapper :global(.basic-tel-input) { .wrapper :global(.basic-tel-input) {
/* height: 32px; /* height: 32px;
padding-left: 12px; padding-left: 12px;
padding-right: 12px; padding-right: 12px;
border-radius: 6px; border-radius: 6px;
border: 1px solid; border: 1px solid;
outline: none; outline: none;
width: 100%; */ width: 100%; */
/* @apply h-full pl-3 pr-3 border-1 w-full rounded; */ /* @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; @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) { .wrapper :global(.invalid) {
/* border-color: red; */ /* border-color: red; */
@apply border-red-700; @apply border-red-700;
} }
</style> </style>

View file

@ -18,7 +18,6 @@
import { SvelteToast, toast } from '@zerodevx/svelte-toast'; import { SvelteToast, toast } from '@zerodevx/svelte-toast';
import { createForm } from 'svelte-forms-lib'; import { createForm } from 'svelte-forms-lib';
import { writable, 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 +27,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(),
@ -46,20 +47,6 @@
export let data: PageData; export let data: PageData;
let details = data.candidate; let details = data.candidate;
let baseCandidateDetails = data.whoami; let baseCandidateDetails = data.whoami;
let componentErrors = writable( {
candidate: {
telephone: false,
personalIdMatch: false,
},
parents: [
{
telephone: false,
},
{
telephone: false,
}
]
});
const formInitialValues = { const formInitialValues = {
gdpr: false, gdpr: false,
@ -117,9 +104,7 @@
name: yup.string().required(), name: yup.string().required(),
surname: yup.string().required(), surname: yup.string().required(),
email: yup.string().email().required(), email: yup.string().email().required(),
telephone: yup telephone: yup.string().required(), // already validated by the 'TelephoneField' component
.string()
.required(), // already validated by the 'TelephoneField' component
birthplace: yup.string().required(), birthplace: yup.string().required(),
birthdate: yup birthdate: yup
.string() .string()
@ -186,7 +171,12 @@
} }
return _val !== ''; return _val !== '';
}), }),
telephone: yup.string() telephone: yup.string().test((_val, context) => {
if (context.path.includes('parents[1]')) {
return true;
}
return _val !== '';
})
}) })
) )
}); });
@ -231,17 +221,15 @@
'--toastBarBackground': '#7f1d1d' '--toastBarBackground': '#7f1d1d'
} }
}); });
$componentErrors['candidate']['personalIdMatch'] = true;
throw new Error('Rodné číslo neodpovídá datumu narození'); throw new Error('Rodné číslo neodpovídá datumu narození');
} }
} }
$componentErrors['candidate']['personalIdMatch'] = false; };
}
const onSubmit = async (values: CandidateData) => { const onSubmit = async (values: CandidateData) => {
console.log("submit button clicked"); console.log('submit button clicked');
console.log(pagesFilled.map((_, i) => !isPageInvalid(i))); console.log(pagesFilled.map((_, i) => !isPageInvalid(i)));
if (pageIndex === pageCount) { if (pageIndex === pageCount) {
console.log('submitting'); console.log('submitting');
// clone values to oldValues // clone values to oldValues
@ -320,8 +308,7 @@
$typedErrors['candidate']['name'] || $typedErrors['candidate']['name'] ||
$typedErrors['candidate']['surname'] || $typedErrors['candidate']['surname'] ||
$typedErrors['candidate']['email'] || $typedErrors['candidate']['email'] ||
// $typedErrors['candidate']['telephone'] || $typedErrors['candidate']['telephone'] ||
$componentErrors['candidate']['telephone'] ||
$typedErrors['candidate']['city'] || $typedErrors['candidate']['city'] ||
$typedErrors['candidate']['street'] || $typedErrors['candidate']['street'] ||
$typedErrors['candidate']['houseNumber'] || $typedErrors['candidate']['houseNumber'] ||
@ -340,8 +327,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']
$componentErrors['candidate']['personalIdMatch']
) { ) {
return true; return true;
} }
@ -351,8 +337,7 @@
$typedErrors['parents'][0]['name'] || $typedErrors['parents'][0]['name'] ||
$typedErrors['parents'][0]['surname'] || $typedErrors['parents'][0]['surname'] ||
$typedErrors['parents'][0]['email'] || $typedErrors['parents'][0]['email'] ||
// $typedErrors['parents'][0]['telephone'] $typedErrors['parents'][0]['telephone']
$componentErrors['parents'][0]['telephone']
) { ) {
return true; return true;
} }
@ -362,8 +347,7 @@
$typedErrors['parents'][1]['name'] || $typedErrors['parents'][1]['name'] ||
$typedErrors['parents'][1]['surname'] || $typedErrors['parents'][1]['surname'] ||
$typedErrors['parents'][1]['email'] || $typedErrors['parents'][1]['email'] ||
// $typedErrors['parents'][1]['telephone'] $typedErrors['parents'][1]['telephone']
$componentErrors['parents'][1]['telephone']
) { ) {
return true; return true;
} }
@ -525,32 +509,32 @@
</div> </div>
<span class="field ml-2"> <span class="field ml-2">
<TelephoneField <TelephoneField
bind:invalid={$componentErrors['candidate']['telephone']} bind:error={$typedErrors['candidate']['telephone']}
bind:value={$form.candidate.telephone} bind:value={$form.candidate.telephone}
placeholder={$LL.input.telephone()} placeholder={$LL.input.telephone()}
/> />
</span> </span>
<div> <div>
<div class="field flex"> <div class="field flex">
<span class="w-[50%]"> <span class="w-[50%]">
<EmailField <EmailField
error={$typedErrors['candidate']['email']} error={$typedErrors['candidate']['email']}
bind:value={$form.candidate.email} bind:value={$form.candidate.email}
placeholder={$LL.input.email()} placeholder={$LL.input.email()}
/> />
</span> </span>
<span class="w-[50%] ml-2"> <span class="ml-2 w-[50%]">
<TextField <TextField
error={$typedErrors['candidate']['city']} error={$typedErrors['candidate']['city']}
bind:value={$form.candidate.city} bind:value={$form.candidate.city}
type="text" type="text"
placeholder={$LL.input.city()} placeholder={$LL.input.city()}
helperText="Uveďte poštovní směrovací číslo. (např. 602 00)" helperText="Uveďte poštovní směrovací číslo. (např. 602 00)"
/> />
</span> </span>
</div>
</div> </div>
</div> </div>
</div>
<div class="field flex"> <div class="field flex">
<span class="w-[66%]"> <span class="w-[66%]">
<NameField <NameField
@ -689,7 +673,7 @@
</span> </span>
<span class="field"> <span class="field">
<TelephoneField <TelephoneField
bind:invalid={$componentErrors['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()}
/> />
@ -718,7 +702,7 @@
</span> </span>
<span class="field"> <span class="field">
<TelephoneField <TelephoneField
bind:invalid={$componentErrors['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()})`}
/> />
@ -767,7 +751,7 @@
await handleSubmit(e); await handleSubmit(e);
console.log(pagesFilled.map((_, i) => !isPageInvalid(i))); console.log(pagesFilled.map((_, i) => !isPageInvalid(i)));
if (isPageInvalid(pageIndex)) return; if (isPageInvalid(pageIndex)) return;
if (pageIndex !== pageCount) { if (pageIndex !== pageCount) {
pagesFilled[pageIndex] = true; pagesFilled[pageIndex] = true;
pageIndex++; pageIndex++;
} }