Squashed commit of the following:

commit ec8ff2c03bd94b1bf5a8055a385bccb14ba48e76
Author: Sebastian Pravda <sebastian.pravda@gmail.com>
Date:   Fri Nov 25 18:44:16 2022 +0100

    fix: remove some ui elements

commit 091c4fa63e1e2c374e449624dd5a384e4ad48532
Author: Sebastian Pravda <sebastian.pravda@gmail.com>
Date:   Fri Nov 25 18:38:50 2022 +0100

    feat: use yup for input validation

commit abd0ba7ddcc938a680d71cc7a41d89f74915b5b9
Author: Sebastian Pravda <sebastian.pravda@gmail.com>
Date:   Fri Nov 25 18:23:48 2022 +0100

    fix: delete input.ts

commit c305b330e5211b1d0a68f0d975e36b930a4ddb52
Author: Sebastian Pravda <sebastian.pravda@gmail.com>
Date:   Fri Nov 25 18:12:16 2022 +0100

    feat: api integration

commit e1fd8c0fc4327020abcb0d8979d2353a8cd1f2af
Author: Sebastian Pravda <sebastian.pravda@gmail.com>
Date:   Fri Nov 25 18:02:27 2022 +0100

    feat: dot navigation

commit 90bd277474493ed7d3e3cea2a7bd359f13374334
Author: Sebastian Pravda <sebastian.pravda@gmail.com>
Date:   Fri Nov 25 17:38:31 2022 +0100

    feat: input formatting

commit 32a7901d6bf059b0b7818a81c577f5508af262ce
Author: Sebastian Pravda <sebastian.pravda@gmail.com>
Date:   Fri Nov 25 17:35:04 2022 +0100

    fix: remove unused validate method

commit 7013a21be86ca8ffb04339a84c567937cf773895
Author: Sebastian Pravda <sebastian.pravda@gmail.com>
Date:   Fri Nov 25 17:31:16 2022 +0100

    refactor: rename format variable

commit e86c997ea73ea67406e87687efa660f1bce9a0ff
Author: Sebastian Pravda <sebastian.pravda@gmail.com>
Date:   Fri Nov 25 15:10:11 2022 +0100

    feat: fill candidate details

commit af28099a6a905d2729aaba12b628e5416d06c3d6
Author: Sebastian Pravda <sebastian.pravda@gmail.com>
Date:   Fri Nov 25 17:15:45 2022 +0100

    feat: use yup for validation
This commit is contained in:
Sebastian Pravda 2022-11-25 18:46:04 +01:00 committed by EETagent
parent 616ad75cbd
commit 2fad0a4203
3 changed files with 99 additions and 58 deletions

View file

@ -1,11 +1,27 @@
<script lang="ts"> <script lang="ts">
export let type: 'text' | 'number' | 'tel' | 'e-mail' | "password" = 'text'; export let type: 'text' | 'number' | 'tel' | 'e-mail' | "password" = 'text';
export let format: 'default' | 'email' | 'tel' | 'name' | 'number' | 'birthdate' | 'personalIdNumber' = 'default';
const typeAction = (node: HTMLInputElement) => { const typeAction = (node: HTMLInputElement) => {
node.type = type; node.type = type;
}; };
export let placeholder: string = ''; export let placeholder: string = '';
export let value: string = ''; export let value: string = '';
$: {
if (format === 'tel') {
let x = value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,3})(\d{0,3})/)!;
value = '+' + x[1] + (x[2] ? ' ' + x[2] : '') + (x[3] ? ' ' + x[3] : '') + (x[4] ? ' ' + x[4] : '');
} else if (format === 'number') {
value = value.replace(/[^0-9]/g, '');
} else if (format === 'birthdate') { // TODO: more intuitive date input
let x = value.replace(/\D/g, '').match(/(\d{0,2})(\d{0,2})(\d{0,4})/)!;
value = x[1] + (x[2] ? '.' + x[2] : '') + (x[3] ? '.' + x[3] : '');
} else if (format === 'personalIdNumber') {
let x = value.replace(/\D/g, '').match(/(\d{0,6})(\d{0,4})/)!;
value = x[1] + (x[2] ? '/' + x[2] : '');
}
}
export let icon: boolean = false; export let icon: boolean = false;
export let error: string = ""; export let error: string = "";
</script> </script>

View file

@ -3,21 +3,20 @@
import woman from '$lib/assets/woman.png'; import woman from '$lib/assets/woman.png';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { page } from '$app/stores';
let applicationId = Number($page.params.code);
let codeValueMobile: string = ''; let codeValueMobile: string = '';
let codeValueArray: Array<string> = []; let codeValueArray: Array<string> = [];
let codeElementArray: Array<HTMLInputElement> = []; let codeElementArray: Array<HTMLInputElement> = [];
const inputMobileOnKeyUp = (event: KeyboardEvent) => {
let input = event.target as HTMLInputElement;
if (input.value.length > 8) {
input.value = input.value.slice(0, 8);
}
let splittedInput = input.value.split(''); $: {
codeValueMobile = codeValueMobile.toUpperCase();
codeValueArray = splittedInput; codeValueArray = codeValueMobile.split('');
}; console.log(codeValueArray);
}
const inputDesktopOnKeyDown = (index: number, e: KeyboardEvent) => { const inputDesktopOnKeyDown = (index: number, e: KeyboardEvent) => {
if (e.key === 'Backspace') { if (e.key === 'Backspace') {
@ -29,12 +28,16 @@
if (e.key.length > 1) { if (e.key.length > 1) {
return; return;
} }
codeValueArray[index] = e.key; codeValueArray[index] = e.key.toUpperCase();
if (codeElementArray[index + 1]) { if (codeElementArray[index + 1]) {
codeElementArray[index + 1].focus(); codeElementArray[index + 1].focus();
} }
} }
codeValueMobile = codeValueArray.join(''); codeValueMobile = codeValueArray.join('')
};
$: if (codeValueArray.length === 8) {
alert('ApplicationId: ' + applicationId + '; Password: ' + codeValueMobile);
}; };
onMount(() => { onMount(() => {
@ -50,7 +53,7 @@
bind:value={codeValueMobile} bind:value={codeValueMobile}
type="text" type="text"
class="codeInputMobile" class="codeInputMobile"
on:keyup={inputMobileOnKeyUp}
/> />
{#each [1, 2, 3, 4] as value} {#each [1, 2, 3, 4] as value}
<input <input

View file

@ -13,15 +13,9 @@
let applicationValue = ''; let applicationValue = '';
const redirectToCode = () => {
// TODO: Validation
if (applicationValue) {
goto(`/login/${applicationValue}`);
}
};
const pageCount = 3; const pageCount = 3;
let pageIndex = 0; let pageIndex = 0;
let pagesFilled = 0;
const formInitialValues = { const formInitialValues = {
name: '', name: '',
@ -31,7 +25,7 @@
birthPlace: '', birthPlace: '',
birthDate: '', birthDate: '',
sex: '', sex: '',
home: '', address: '',
parentEmail: '', parentEmail: '',
parentTelephone: '', parentTelephone: '',
citizenship: '', citizenship: '',
@ -45,12 +39,12 @@
validationSchema: yup.object().shape({ validationSchema: yup.object().shape({
name: yup.string().required(), name: yup.string().required(),
email: yup.string().email().required(), email: yup.string().email().required(),
telephone: yup.string().required(), telephone: yup.string().required().matches(/^\+\d{1,3} \d{3} \d{3} \d{3}$/),
birthSurname: yup.string().required(), birthSurname: yup.string().required(),
birthPlace: yup.string().required(), birthPlace: yup.string().required(),
birthDate: yup.string().required(), birthDate: yup.string().required(),
sex: yup.string().required(), sex: yup.string().required(),
home: yup.string().required(), address: yup.string().required(),
parentEmail: yup.string().email().required(), parentEmail: yup.string().email().required(),
parentTelephone: yup.string().required(), parentTelephone: yup.string().required(),
citizenship: yup.string().required(), citizenship: yup.string().required(),
@ -62,6 +56,40 @@
alert(JSON.stringify(values)); alert(JSON.stringify(values));
} }
}); });
const isPageInvalid = (): boolean => {
switch (pageIndex) {
case 0:
if ($errors.name || $errors.email || $errors.telephone) {
return true;
}
break;
case 1:
if ($errors.birthSurname || $errors.birthPlace || $errors.birthDate || $errors.sex) {
return true;
}
break;
case 2:
if ($errors.address || $errors.parentEmail || $errors.parentTelephone) {
return true;
}
break;
case 3:
if (
$errors.citizenship ||
$errors.personalId ||
$errors.study ||
$errors.applicationId
) {
return true;
}
break;
default:
return false;
}
return false;
}
</script> </script>
<SplitLayout> <SplitLayout>
@ -109,6 +137,7 @@
on:change={handleChange} on:change={handleChange}
bind:value={$form.telephone} bind:value={$form.telephone}
type="tel" type="tel"
format="tel"
placeholder="Telefon" placeholder="Telefon"
icon icon
> >
@ -156,6 +185,7 @@
on:change={handleChange} on:change={handleChange}
bind:value={$form.birthDate} bind:value={$form.birthDate}
type="text" type="text"
format="birthdate"
placeholder="Datum narození" placeholder="Datum narození"
/> />
<TextField <TextField
@ -175,9 +205,9 @@
<div class="flex flex-col w-full md:w-3/5"> <div class="flex flex-col w-full md:w-3/5">
<span class="w-full mt-8"> <span class="w-full mt-8">
<TextField <TextField
error={$errors.home} error={$errors.address}
on:change={handleChange} on:change={handleChange}
bind:value={$form.home} bind:value={$form.address}
type="text" type="text"
placeholder="Adresa trvalého bydliště" placeholder="Adresa trvalého bydliště"
/> />
@ -224,6 +254,7 @@
on:change={handleChange} on:change={handleChange}
bind:value={$form.personalId} bind:value={$form.personalId}
type="text" type="text"
format="personalIdNumber"
placeholder="Rodné číslo" placeholder="Rodné číslo"
/> />
<TextField <TextField
@ -247,48 +278,34 @@
<input <input
on:click={async (e) => { on:click={async (e) => {
await handleSubmit(e); await handleSubmit(e);
switch (pageIndex) { if (isPageInvalid()) return;
case 0: if (pageIndex === pageCount) {
if ($errors.name || $errors.email || $errors.telephone) { alert('should submit');
return; } else {
} pagesFilled++;
break; pageIndex++;
case 1:
if ($errors.birthSurname || $errors.birthPlace || $errors.birthDate || $errors.sex) {
return;
}
break;
case 2:
if ($errors.home || $errors.parentEmail || $errors.parentTelephone) {
return;
}
break;
case 3:
if (
$errors.citizenship ||
$errors.personalId ||
$errors.study ||
$errors.applicationId
) {
return;
}
break;
default:
break;
} }
pageIndex++;
errors.set(formInitialValues); errors.set(formInitialValues);
}} }}
class="w-full mt-8 md:w-3/5 p-3 rounded-lg font-semibold text-xl transition-colors duration-300 bg-sspsBlue hover:bg-sspsBlueDark text-white" class="w-full mt-8 md:w-3/5 p-3 rounded-lg font-semibold text-xl transition-colors duration-300 bg-sspsBlue hover:bg-sspsBlueDark text-white hover:cursor-pointer"
type="submit" type="submit"
value={pageIndex === pageCount ? 'Odeslat' : 'Pokračovat'} value={pageIndex === pageCount ? 'Odeslat' : 'Pokračovat'}
/> />
<div class="mt-8 flex flex-row justify-center"> <div class="mt-8 flex flex-row justify-center">
{#each Array(pageCount + 1) as _, i} {#each Array(pageCount + 1) as _, i}
<span class:dotActive={i === pageIndex} class="ml-2 w-3 h-3 rounded-full bg-sspsGray" /> <button class:dotActive={i === pageIndex} on:click={async (e) => {
if (i <= pagesFilled) { // never skip unfilled or invalid pages
pageIndex = i;
} else if (i == pagesFilled + 1) { // if next page is clicked, validate current page
await handleSubmit(e);
if (isPageInvalid()) return;
pagesFilled++;
pageIndex++;
errors.set(formInitialValues);
}
}
} class="dot" />
{/each} {/each}
</div> </div>
</div> </div>
@ -305,6 +322,11 @@
@apply w-full; @apply w-full;
@apply items-center justify-center; @apply items-center justify-center;
} }
.dot {
@apply ml-2 w-4 h-4
@apply hover:cursor-pointer hover:bg-sspsBlue
@apply rounded-full bg-sspsGray;
}
.dotActive { .dotActive {
@apply bg-sspsBlue; @apply bg-sspsBlue;
} }