mirror of
https://github.com/danbulant/Portfolio
synced 2026-05-27 14:02:14 +00:00
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:
parent
616ad75cbd
commit
2fad0a4203
3 changed files with 99 additions and 58 deletions
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue