feat: changed form behavior
This commit is contained in:
parent
f1dea1016a
commit
7321d48266
4 changed files with 156 additions and 148 deletions
|
@ -1,36 +1,39 @@
|
|||
import { redirect, type Actions, fail } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { API_URL } from '$env/static/private';
|
||||
|
||||
import { z } from 'zod';
|
||||
import { redirect, type Actions, fail } from '@sveltejs/kit';
|
||||
|
||||
export const load = (async ({ locals: { user } }) => {
|
||||
if (user) throw redirect(303, '/dashboard');
|
||||
}) satisfies PageServerLoad;
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
import { superValidate } from 'sveltekit-superforms/server';
|
||||
import { z } from 'zod';
|
||||
|
||||
const schema = z.object({
|
||||
pseudo: z.string().trim(),
|
||||
passwd: z.string()
|
||||
});
|
||||
|
||||
export const load = (async ({ locals: { user } }) => {
|
||||
if (user) throw redirect(303, '/dashboard');
|
||||
|
||||
const form = await superValidate(schema);
|
||||
|
||||
return {
|
||||
form
|
||||
};
|
||||
}) satisfies PageServerLoad;
|
||||
|
||||
export const actions = {
|
||||
default: async (event) => {
|
||||
const data = await event.request.formData();
|
||||
default: async ({ request, cookies }) => {
|
||||
const form = await superValidate(request, schema);
|
||||
|
||||
const parse = schema.safeParse(Object.fromEntries(data.entries()));
|
||||
|
||||
if (!parse.success) {
|
||||
const errors = parse.error.errors.map((error) => {
|
||||
const { path, message } = error;
|
||||
return { field: path[0], message };
|
||||
});
|
||||
return fail(400, { errors });
|
||||
if (!form.valid) {
|
||||
return fail(400, { form });
|
||||
}
|
||||
|
||||
const res = await fetch(`${API_URL}/login`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
...parse.data
|
||||
...form.data
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -39,15 +42,17 @@ export const actions = {
|
|||
|
||||
if (!token) throw new Error('No token found');
|
||||
|
||||
event.cookies.set('session', token, {
|
||||
cookies.set('session', token, {
|
||||
path: '/'
|
||||
});
|
||||
|
||||
throw redirect(303, '/dashboard');
|
||||
}
|
||||
|
||||
form.errors.passwd = ["Nom d'utilisateur ou mot de passe incorrect"];
|
||||
|
||||
return fail(400, {
|
||||
errors: [{ field: 'passwd', message: "Nom d'utilisateur ou mot de passe incorrect" }]
|
||||
form
|
||||
});
|
||||
}
|
||||
} satisfies Actions;
|
||||
|
|
|
@ -1,12 +1,26 @@
|
|||
<script lang="ts">
|
||||
import { enhance } from '$app/forms';
|
||||
import type { PageData } from './$types';
|
||||
|
||||
import type { ActionData } from './$types';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
import { superForm } from 'sveltekit-superforms/client';
|
||||
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Input from '$lib/components/ui/Input.svelte';
|
||||
|
||||
export let form: ActionData;
|
||||
export let data: PageData;
|
||||
|
||||
const { form, errors, enhance } = superForm(data.form, {
|
||||
onResult({ result }) {
|
||||
switch (result.type) {
|
||||
case 'redirect':
|
||||
goto(result.location, {
|
||||
replaceState: true
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="flex h-screen w-full">
|
||||
|
@ -15,20 +29,18 @@
|
|||
<h1 class="mx-auto text-xl font-bold">Connexion</h1>
|
||||
<form class="flex flex-col justify-center gap-2" method="POST" use:enhance>
|
||||
<label for="pseudo"> Nom d'utilisateur </label>
|
||||
<Input name="pseudo" placeholder="Barlow" type="text" required />
|
||||
{#if form?.errors.find((error) => error.field === 'pseudo')}
|
||||
<p class="text-sm text-red-500">
|
||||
{form?.errors.find((error) => error.field === 'pseudo')?.message}
|
||||
</p>
|
||||
{/if}
|
||||
<Input name="pseudo" placeholder="Barlow" type="text" required bind:value={$form.pseudo} />
|
||||
{#if $errors.pseudo}<span class="text-sm text-red-500">{$errors.pseudo}</span>{/if}
|
||||
|
||||
<label for="passwd"> Mot de passe </label>
|
||||
<Input name="passwd" placeholder="************" type="password" required />
|
||||
{#if form?.errors.find((error) => error.field === 'passwd')}
|
||||
<p class="text-sm text-red-500">
|
||||
{form?.errors.find((error) => error.field === 'passwd')?.message}
|
||||
</p>
|
||||
{/if}
|
||||
<Input
|
||||
name="passwd"
|
||||
placeholder="************"
|
||||
type="password"
|
||||
required
|
||||
bind:value={$form.passwd}
|
||||
/>
|
||||
{#if $errors.passwd}<span class="text-sm text-red-500">{$errors.passwd}</span>{/if}
|
||||
|
||||
<Button class="mt-2" variant="brand">
|
||||
<!-- {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} -->
|
||||
|
@ -39,11 +51,11 @@
|
|||
<li>
|
||||
<a class="text-highlight-secondary hover:text-brand" href="/sign-up">S'inscrire</a>
|
||||
</li>
|
||||
<!-- <li>
|
||||
<li>
|
||||
<a class="text-highlight-secondary hover:text-brand" href="/forgot-password"
|
||||
>Mot de passe oublié</a
|
||||
>
|
||||
</li> -->
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -4,12 +4,9 @@ import { fail, redirect, type Actions } from '@sveltejs/kit';
|
|||
|
||||
import type { PageServerLoad } from './$types';
|
||||
|
||||
import { superValidate } from 'sveltekit-superforms/server';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const load = (async ({ locals: { user } }) => {
|
||||
if (user) throw redirect(303, '/dashboard');
|
||||
}) satisfies PageServerLoad;
|
||||
|
||||
const registerSchema = z.object({
|
||||
email: z
|
||||
.string()
|
||||
|
@ -19,7 +16,17 @@ const registerSchema = z.object({
|
|||
.trim(),
|
||||
firstname: z.string().trim(),
|
||||
lastname: z.string().trim(),
|
||||
pseudo: z.string().trim()
|
||||
pseudo: z.string().trim(),
|
||||
code: z
|
||||
.string({
|
||||
required_error: 'Code manquant'
|
||||
})
|
||||
.length(4, {
|
||||
message: 'Code invalide, il doit contenir 4 chiffres'
|
||||
})
|
||||
.regex(/^[0-9]+$/)
|
||||
.optional(),
|
||||
passwd: z.string().optional()
|
||||
});
|
||||
|
||||
const confirmationSchema = z.object({
|
||||
|
@ -32,80 +39,80 @@ const confirmationSchema = z.object({
|
|||
firstname: z.string().trim(),
|
||||
lastname: z.string().trim(),
|
||||
pseudo: z.string().trim(),
|
||||
code: z.string(),
|
||||
code: z
|
||||
.string({
|
||||
required_error: 'Code manquant'
|
||||
})
|
||||
.regex(/^[0-9]{4}$/, {
|
||||
message: 'Code invalide, il doit contenir 4 chiffres'
|
||||
}),
|
||||
passwd: z.string()
|
||||
});
|
||||
|
||||
export const load = (async ({ locals: { user } }) => {
|
||||
if (user) throw redirect(303, '/dashboard');
|
||||
|
||||
const form = await superValidate(registerSchema);
|
||||
|
||||
return {
|
||||
form
|
||||
};
|
||||
}) satisfies PageServerLoad;
|
||||
|
||||
export const actions = {
|
||||
register: async (event) => {
|
||||
const data = await event.request.formData();
|
||||
register: async ({ request }) => {
|
||||
const form = await superValidate(request, registerSchema);
|
||||
|
||||
const parse = registerSchema.safeParse(Object.fromEntries(data.entries()));
|
||||
|
||||
if (!parse.success) {
|
||||
const errors = parse.error.errors.map((error) => {
|
||||
const { path, message } = error;
|
||||
return { field: path[0], message };
|
||||
});
|
||||
return fail(400, { errors });
|
||||
if (!form.valid) {
|
||||
return fail(400, { form });
|
||||
}
|
||||
|
||||
const res = await fetch(`${API_URL}/register`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
pseudo: parse.data.pseudo,
|
||||
firstname: parse.data.firstname,
|
||||
lastname: parse.data.lastname,
|
||||
email: parse.data.email
|
||||
pseudo: form.data.pseudo,
|
||||
firstname: form.data.firstname,
|
||||
lastname: form.data.lastname,
|
||||
email: form.data.email
|
||||
})
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
return {
|
||||
success: true
|
||||
form
|
||||
};
|
||||
}
|
||||
|
||||
if (res.status === 400) {
|
||||
const { email_valid } = await res.json();
|
||||
|
||||
const errors = [];
|
||||
if (!email_valid) form.errors.email = ['Un compte avec cette adresse email existe déjà'];
|
||||
|
||||
if (!email_valid)
|
||||
errors.push({
|
||||
field: 'email',
|
||||
message: 'Cet email est déjà utilisé'
|
||||
});
|
||||
|
||||
return fail(400, { errors });
|
||||
return fail(400, { form });
|
||||
}
|
||||
|
||||
form.errors.passwd = ["Une erreur s'est produite"];
|
||||
|
||||
return fail(400, {
|
||||
errors: [{ field: 'passwd', message: "Une erreur s'est produite" }]
|
||||
form
|
||||
});
|
||||
},
|
||||
confirmation: async (event) => {
|
||||
const data = await event.request.formData();
|
||||
confirmation: async ({ request, cookies }) => {
|
||||
const form = await superValidate(request, confirmationSchema);
|
||||
|
||||
const parse = confirmationSchema.safeParse(Object.fromEntries(data.entries()));
|
||||
|
||||
if (!parse.success) {
|
||||
const errors = parse.error.errors.map((error) => {
|
||||
const { path, message } = error;
|
||||
return { field: path[0], message };
|
||||
});
|
||||
return fail(400, { errors });
|
||||
if (!form.valid) {
|
||||
return fail(400, { form });
|
||||
}
|
||||
|
||||
const res = await fetch(`${API_URL}/confirmation`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
firstname: parse.data.firstname,
|
||||
lastname: parse.data.lastname,
|
||||
pseudo: parse.data.pseudo,
|
||||
email: parse.data.email,
|
||||
code: parseInt(parse.data.code),
|
||||
passwd: parse.data.passwd
|
||||
firstname: form.data.firstname,
|
||||
lastname: form.data.lastname,
|
||||
pseudo: form.data.pseudo,
|
||||
email: form.data.email,
|
||||
code: parseInt(form.data.code),
|
||||
passwd: form.data.passwd
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -114,15 +121,17 @@ export const actions = {
|
|||
|
||||
if (!token) throw new Error('No token');
|
||||
|
||||
event.cookies.set('token', token, {
|
||||
cookies.set('session', token, {
|
||||
path: '/'
|
||||
});
|
||||
|
||||
throw redirect(303, '/dashboard');
|
||||
}
|
||||
|
||||
form.errors.code = [`Une erreur s'est produite (${res.status} ${res.statusText})`];
|
||||
|
||||
return fail(400, {
|
||||
errors: [{ field: 'passwd', message: "Une erreur s'est produite" }]
|
||||
form
|
||||
});
|
||||
}
|
||||
} satisfies Actions;
|
||||
|
|
|
@ -1,25 +1,39 @@
|
|||
<script lang="ts">
|
||||
import { enhance } from '$app/forms';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
import type { ActionData, Snapshot } from './$types';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
import { superForm } from 'sveltekit-superforms/client';
|
||||
import type { PageData, Snapshot } from './$types';
|
||||
|
||||
import Button from '$lib/components/ui/Button.svelte';
|
||||
import Input from '$lib/components/ui/Input.svelte';
|
||||
import { fade } from 'svelte/transition';
|
||||
|
||||
export let form: ActionData;
|
||||
export let data: PageData;
|
||||
|
||||
let data = {
|
||||
email: '',
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
pseudo: '',
|
||||
confirmation: false
|
||||
};
|
||||
const { form, errors, enhance } = superForm(data.form, {
|
||||
onResult({ result }) {
|
||||
switch (result.type) {
|
||||
case 'success':
|
||||
confirmation = true;
|
||||
break;
|
||||
case 'error':
|
||||
confirmation = false;
|
||||
break;
|
||||
case 'redirect':
|
||||
goto(result.location, {
|
||||
replaceState: true
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let confirmation = false;
|
||||
|
||||
export const snapshot: Snapshot = {
|
||||
capture: () => data,
|
||||
restore: (value) => (data = value)
|
||||
capture: () => confirmation,
|
||||
restore: (value) => (confirmation = value)
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -27,83 +41,59 @@
|
|||
<div class="flex w-full flex-col items-center justify-center">
|
||||
<div class="flex w-full max-w-xs flex-col gap-4">
|
||||
<h2 class="mx-auto text-xl font-bold">
|
||||
{data.confirmation ? 'Confirmation' : 'Inscription'}
|
||||
{confirmation ? 'Confirmation' : 'Inscription'}
|
||||
</h2>
|
||||
<form
|
||||
class="flex flex-col justify-center gap-2"
|
||||
method="POST"
|
||||
use:enhance={({}) => {
|
||||
return async ({ result }) => {
|
||||
switch (result.type) {
|
||||
case 'success':
|
||||
data.confirmation = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}}
|
||||
action={data.confirmation ? '/sign-up?/confirmation' : '/sign-up?/register'}
|
||||
action={confirmation ? '?/confirmation' : '?/register'}
|
||||
use:enhance
|
||||
>
|
||||
<label for="email">Email</label>
|
||||
<Input
|
||||
bind:value={data.email}
|
||||
bind:value={$form.email}
|
||||
name="email"
|
||||
type="email"
|
||||
placeholder="philipzcwbarlow@peerat.dev"
|
||||
autocomplete="off"
|
||||
required
|
||||
/>
|
||||
{#if form?.errors?.find((error) => error.field === 'email')}
|
||||
<p class="text-sm text-red-500">
|
||||
{form?.errors.find((error) => error.field === 'email')?.message}
|
||||
</p>
|
||||
{/if}
|
||||
{#if $errors.email}<span class="text-sm text-red-500">{$errors.email}</span>{/if}
|
||||
|
||||
<label for="firstname">Prénom</label>
|
||||
<Input
|
||||
bind:value={data.firstname}
|
||||
bind:value={$form.firstname}
|
||||
name="firstname"
|
||||
type="text"
|
||||
placeholder="Philip"
|
||||
autocomplete="off"
|
||||
required
|
||||
/>
|
||||
{#if form?.errors?.find((error) => error.field === 'firstname')}
|
||||
<p class="text-sm text-red-500">
|
||||
{form?.errors?.find((error) => error.field === 'firstname')?.message}
|
||||
</p>
|
||||
{/if}
|
||||
{#if $errors.firstname}<span class="text-sm text-red-500">{$errors.firstname}</span>{/if}
|
||||
|
||||
<label for="lastname">Nom</label>
|
||||
<Input
|
||||
bind:value={data.lastname}
|
||||
bind:value={$form.lastname}
|
||||
name="lastname"
|
||||
type="text"
|
||||
placeholder="Barlow"
|
||||
autocomplete="off"
|
||||
required
|
||||
/>
|
||||
{#if form?.errors?.find((error) => error.field === 'lastname')}
|
||||
<p class="text-sm text-red-500">
|
||||
{form?.errors?.find((error) => error.field === 'lastname')?.message}
|
||||
</p>
|
||||
{/if}
|
||||
{#if $errors.lastname}<span class="text-sm text-red-500">{$errors.lastname}</span>{/if}
|
||||
|
||||
<label for="pseudo"> Nom d'utilisateur </label>
|
||||
<Input
|
||||
bind:value={data.pseudo}
|
||||
bind:value={$form.pseudo}
|
||||
name="pseudo"
|
||||
type="text"
|
||||
placeholder="Cypher Wolf"
|
||||
autocomplete="off"
|
||||
required
|
||||
/>
|
||||
{#if form?.errors?.find((error) => error.field === 'pseudo')}
|
||||
<p class="text-sm text-red-500">
|
||||
{form?.errors?.find((error) => error.field === 'pseudo')?.message}
|
||||
</p>
|
||||
{/if}
|
||||
{#if $errors.pseudo}<span class="text-sm text-red-500">{$errors.pseudo}</span>{/if}
|
||||
|
||||
{#if data.confirmation}
|
||||
{#if confirmation}
|
||||
<div
|
||||
class="flex flex-col gap-2"
|
||||
transition:fade={{
|
||||
|
@ -112,35 +102,27 @@
|
|||
>
|
||||
<label for="passwd"> Mot de passe </label>
|
||||
<Input name="passwd" placeholder="************" type="password" />
|
||||
{#if form?.errors?.find((error) => error.field === 'passwd')}
|
||||
<p class="text-sm text-red-500">
|
||||
{form?.errors?.find((error) => error.field === 'passwd')?.message}
|
||||
</p>
|
||||
{/if}
|
||||
{#if $errors.passwd}<span class="text-sm text-red-500">{$errors.passwd}</span>{/if}
|
||||
|
||||
<label for="code"> Code </label>
|
||||
<Input name="code" placeholder="1234" type="text" />
|
||||
{#if form?.errors?.find((error) => error.field === 'code')}
|
||||
<p class="text-sm text-red-500">
|
||||
{form?.errors?.find((error) => error.field === 'code')?.message}
|
||||
</p>
|
||||
{/if}
|
||||
{#if $errors.code}<span class="text-sm text-red-500">{$errors.code}</span>{/if}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<Button class="mt-2" variant="brand">
|
||||
<!-- {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} -->
|
||||
{data.confirmation ? "S'inscrire" : 'Continuer'}
|
||||
{confirmation ? "S'inscrire" : 'Continuer'}
|
||||
</Button>
|
||||
|
||||
<ul class="flex justify-between">
|
||||
<li>
|
||||
<a class="text-highlight-secondary hover:text-brand" href="/sign-in">Se connecter</a>
|
||||
</li>
|
||||
{#if data.confirmation}
|
||||
{#if confirmation}
|
||||
<li>
|
||||
<button
|
||||
formaction="/sign-up?/confirmation"
|
||||
class="text-highlight-secondary hover:text-brand">Pas reçu ?</button
|
||||
<button formaction="?/register" class="text-highlight-secondary hover:text-brand"
|
||||
>Pas reçu ?</button
|
||||
>
|
||||
</li>
|
||||
{/if}
|
||||
|
|
Loading…
Add table
Reference in a new issue