mirror of
https://github.com/danbulant/Portfolio
synced 2026-07-06 19:40:49 +00:00
feat: tel input refactor
This commit is contained in:
parent
915708f2e8
commit
5eb27733f1
2 changed files with 69 additions and 79 deletions
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue