feat: forgor 💀
This commit is contained in:
parent
7321d48266
commit
2291e12b3a
2 changed files with 232 additions and 0 deletions
137
src/routes/forgot-password/+page.server.ts
Normal file
137
src/routes/forgot-password/+page.server.ts
Normal 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;
|
95
src/routes/forgot-password/+page.svelte
Normal file
95
src/routes/forgot-password/+page.svelte
Normal 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>
|
Loading…
Add table
Reference in a new issue