feat: forgor 💀

This commit is contained in:
Théo 2023-09-17 23:04:10 +02:00
parent 7321d48266
commit 2291e12b3a
2 changed files with 232 additions and 0 deletions

View file

@ -0,0 +1,137 @@
import { API_URL } from '$env/static/private';
import { fail, redirect, type Actions } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
import { superValidate } from 'sveltekit-superforms/server';
import { z } from 'zod';
const forgotSchema = z.object({
email: z
.string()
.email({
message: 'Email invalide'
})
.trim(),
code: z
.string({
required_error: 'Code manquant'
})
.regex(/^[0-9]{4}$/, {
message: 'Code invalide, il doit contenir 4 chiffres'
})
.optional(),
passwd: z.string().optional()
});
const confirmationSchema = z.object({
email: z
.string()
.email({
message: 'Email invalide'
})
.trim(),
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(forgotSchema);
return {
form
};
}) satisfies PageServerLoad;
export const actions = {
forgot: async ({ request, cookies }) => {
const form = await superValidate(request, forgotSchema);
if (!form.valid) {
return fail(400, { form });
}
const data = {
email: form.data.email
} as Record<string, unknown>;
if (form.data.code) {
data.code = parseInt(form.data.code);
}
if (form.data.passwd) {
data.password = form.data.passwd;
}
const res = await fetch(`${API_URL}/user/fpw`, {
method: 'POST',
body: JSON.stringify(data)
});
console.log(res);
if (res.ok) {
const token = res.headers.get('Authorization')?.split('Bearer ')[1];
if (token) {
cookies.set('session', token, {
path: '/'
});
throw redirect(303, '/dashboard');
}
return {
form
};
}
form.errors.passwd = ['Code invalide ou expiré'];
return fail(400, {
form
});
},
confirmation: async ({ request, cookies }) => {
const form = await superValidate(request, confirmationSchema);
if (!form.valid) {
return fail(400, { form });
}
const res = await fetch(`${API_URL}/confirmation`, {
method: 'POST',
body: JSON.stringify({
email: form.data.email,
passwd: form.data.passwd,
code: parseInt(form.data.code)
})
});
if (res.ok) {
const token = res.headers.get('Authorization')?.split('Bearer ')[1];
if (!token) throw new Error('No 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, {
form
});
}
} satisfies Actions;

View file

@ -0,0 +1,95 @@
<script lang="ts">
import { goto } from '$app/navigation';
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';
export let data: PageData;
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: () => confirmation,
restore: (value) => (confirmation = value)
};
</script>
<div class="flex h-screen w-full">
<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">
{confirmation ? 'Changer le mot de passe' : 'Mot de passe oublié'}
</h2>
<form class="flex flex-col justify-center gap-2" method="POST" action="?/forgot" use:enhance>
<label for="email">Email</label>
<Input
bind:value={$form.email}
name="email"
type="email"
placeholder="philipzcwbarlow@peerat.dev"
autocomplete="off"
required
/>
{#if $errors.email}<span class="text-sm text-red-500">{$errors.email}</span>{/if}
{#if confirmation}
<div
class="flex flex-col gap-2"
transition:fade={{
duration: 300
}}
>
<label for="passwd"> Mot de passe </label>
<Input name="passwd" placeholder="************" type="password" />
{#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 $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" />} -->
{confirmation ? 'Modifier' : 'Envoyer le mail'}
</Button>
<ul class="flex justify-between">
<li>
<a class="text-highlight-secondary hover:text-brand" href="/sign-in">Se connecter</a>
</li>
{#if confirmation}
<li>
<button formaction="?/register" class="text-highlight-secondary hover:text-brand"
>Pas reçu ?</button
>
</li>
{/if}
</ul>
</form>
</div>
</div>
</div>