feat: settings user

This commit is contained in:
Théo 2023-09-22 14:27:20 +02:00
parent 9e43d220d7
commit 3c538499c8
7 changed files with 156 additions and 74 deletions

View file

@ -1,26 +1,10 @@
import { API_URL } from '$env/static/private'; import { API_URL } from '$env/static/private';
import { error, redirect, type Actions, fail } from '@sveltejs/kit'; import { error, redirect, type Actions } from '@sveltejs/kit';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
import type Puzzle from '$lib/components/Puzzle.svelte'; import type Puzzle from '$lib/components/Puzzle.svelte';
import type { Chapter } from '$lib/types'; import type { Chapter } from '$lib/types';
import { superValidate } from 'sveltekit-superforms/server';
import { z } from 'zod';
const puzzleSchema = z.object({
// answer: z.string().trim(),
// answer need to be filled
answer: z
.string({
required_error: 'Réponse manquante'
})
.refine((val) => val.trim() !== '', {
message: 'Réponse manquante'
}),
file: z.any().optional()
});
export const load = (async ({ parent, fetch, cookies, params: { chapterId, puzzleId } }) => { export const load = (async ({ parent, fetch, cookies, params: { chapterId, puzzleId } }) => {
await parent(); await parent();

View file

@ -5,9 +5,10 @@
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { Loader2 } from 'lucide-svelte';
import { marked, type MarkedOptions } from 'marked'; import { marked, type MarkedOptions } from 'marked';
import { cn } from '$lib';
import { addToast } from '$lib/components/Toaster.svelte'; import { addToast } from '$lib/components/Toaster.svelte';
import Button from '$lib/components/ui/Button.svelte'; import Button from '$lib/components/ui/Button.svelte';
import Input from '$lib/components/ui/Input.svelte'; import Input from '$lib/components/ui/Input.svelte';
@ -17,6 +18,8 @@
$: puzzle = data.puzzle; $: puzzle = data.puzzle;
$: chapterId = $page.params.chapterId; $: chapterId = $page.params.chapterId;
let submitting = false;
const renderer = new marked.Renderer(); const renderer = new marked.Renderer();
renderer.link = (href, title, text) => { renderer.link = (href, title, text) => {
@ -56,6 +59,8 @@
method="POST" method="POST"
enctype="multipart/form-data" enctype="multipart/form-data"
use:enhance={async ({ formData, cancel }) => { use:enhance={async ({ formData, cancel }) => {
submitting = true;
if (formData.get('answer') === '') { if (formData.get('answer') === '') {
addToast({ addToast({
data: { data: {
@ -112,6 +117,8 @@
}); });
} }
submitting = false;
return async ({ result }) => { return async ({ result }) => {
if (result.type === 'redirect') { if (result.type === 'redirect') {
goto(result.location, { goto(result.location, {
@ -125,19 +132,22 @@
<div class="flex flex-col gap-y-2"> <div class="flex flex-col gap-y-2">
<label for="answer">Réponse</label> <label for="answer">Réponse</label>
<textarea <textarea
class={cn( class="flex h-10 w-full rounded-md border border-primary-600 bg-highlight-primary px-3 py-2 text-sm ring-offset-highlight-primary file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted focus:bg-primary-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
'flex h-10 w-full rounded-md border border-primary-600 bg-highlight-primary px-3 py-2 text-sm ring-offset-highlight-primary file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted focus:bg-primary-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50'
)}
name="answer" name="answer"
placeholder="CAPTAIN, LOOK !" placeholder="CAPTAIN, LOOK !"
/> />
</div> </div>
<div class="flex flex-col gap-y-2"> <div class="flex flex-col gap-y-2">
<label for="code_file">Fichier</label> <label for="code_file">Fichier</label>
<Input name="code_file" type="file" accept=".py,.js,.ts,.java,.rs,.c" disabled /> <Input name="code_file" type="file" accept=".py,.js,.ts,.java,.rs,.c" disabled />
</div> </div>
</div> </div>
<Button class="w-full sm:w-44" variant="brand">Valider</Button> <Button class="w-full sm:w-44" variant="brand" disabled={submitting}>
{#if submitting}
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
{/if}
Valider
</Button>
</form> </form>
{:else} {:else}
<div class="flex flex-col items-center justify-between gap-2 sm:flex-row"> <div class="flex flex-col items-center justify-between gap-2 sm:flex-row">

View file

@ -1,31 +1,62 @@
import type { Actions } from '@sveltejs/kit'; import { fail, type Actions } from '@sveltejs/kit';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
import { z } from 'zod';
import { superValidate } from 'sveltekit-superforms/server';
import { API_URL } from '$env/static/private';
export const load = (async ({ parent }) => { const settingSchema = z.object({
firstname: z.string({
required_error: 'Prénom manquant'
}),
lastname: z.string({
required_error: 'Nom manquant'
}),
pseudo: z.string({
required_error: 'Pseudo manquant'
})
});
export const load = (async ({ parent, locals: { user } }) => {
await parent(); await parent();
const form = await superValidate(user, settingSchema);
return {
form
};
}) satisfies PageServerLoad; }) satisfies PageServerLoad;
export const actions = { export const actions = {
default: async (event) => { default: async ({ request, cookies }) => {
return { const session = cookies.get('session');
success: true
};
// throw redirect(303, `/dashboard/puzzles/${id}`); const form = await superValidate(request, settingSchema);
// if (res.ok) { if (!form.valid) {
// const token = res.headers.get('Authorization')?.split(' ')[1]; return fail(400, { form });
}
// if (!token) throw new Error('No token found'); const res = await fetch(`${API_URL}/user/settings`, {
method: 'POST',
headers: {
Authorization: `Bearer ${session}`
},
body: JSON.stringify(form.data)
});
// event.cookies.set('session', token, { if (res.ok) {
// path: '/' return {
// }); form
};
}
// throw redirect(303, '/dashboard'); if (res.status === 400) {
// } form.errors.pseudo = ['Le pseudo est déjà utilisé'];
// throw redirect(303, '/sign-in'); return fail(400, { form });
}
return fail(500, { form });
} }
} satisfies Actions; } satisfies Actions;

View file

@ -1,17 +1,26 @@
<script lang="ts"> <script lang="ts">
import { enhance } from '$app/forms'; import type { PageData } from './$types';
import { page } from '$app/stores';
import type { ActionData } from './$types'; import { Loader2 } from 'lucide-svelte';
import { superForm } from 'sveltekit-superforms/client';
import Button from '$lib/components/ui/Button.svelte'; import Button from '$lib/components/ui/Button.svelte';
import Input from '$lib/components/ui/Input.svelte'; import Input from '$lib/components/ui/Input.svelte';
import plausible from '$lib/stores/Plausible'; import plausible from '$lib/stores/Plausible';
$: user = $page.data.user; export let data: PageData;
export let form: ActionData; let submitting = false;
const { form, errors, enhance } = superForm(data.form, {
onSubmit() {
submitting = true;
},
onResult() {
submitting = false;
}
});
$: optedOut = $plausible; $: optedOut = $plausible;
</script> </script>
@ -22,28 +31,45 @@
name="email" name="email"
type="email" type="email"
placeholder="philipzcwbarlow@peerat.dev" placeholder="philipzcwbarlow@peerat.dev"
value={user?.email} value={data.user?.email}
disabled disabled
/> />
<label for="firstname">Prénom</label> <label for="firstname">Prénom</label>
<Input name="firstname" type="text" placeholder="Philip" value={user?.firstname} /> <Input
name="firstname"
type="text"
placeholder="Philip"
aria-invalid={$errors.firstname ? 'true' : undefined}
bind:value={$form.firstname}
/>
{#if $errors.firstname}
<span class="text-sm text-red-500">{$errors.firstname}</span>
{/if}
<label for="lastname">Nom</label> <label for="lastname">Nom</label>
<Input name="lastname" type="text" placeholder="Barlow" value={user?.lastname} /> <Input
name="lastname"
type="text"
placeholder="Barlow"
aria-invalid={$errors.lastname ? 'true' : undefined}
bind:value={$form.lastname}
/>
{#if $errors.lastname}
<span class="text-sm text-red-500">{$errors.lastname}</span>
{/if}
<label for="pseudo"> Nom d'utilisateur </label> <label for="pseudo"> Nom d'utilisateur </label>
<Input name="pseudo" type="text" placeholder="Cypher Wolf" value={user?.pseudo} />
<label for="description"> Description </label>
<Input <Input
name="description" name="pseudo"
placeholder="Je serai le plus grand pirate de l'espace"
type="text" type="text"
value={user?.description} placeholder="Cypher Wolf"
aria-invalid={$errors.pseudo ? 'true' : undefined}
bind:value={$form.pseudo}
/> />
{#if $errors.pseudo}
<!-- TODO --> <span class="text-sm text-red-500">{$errors.pseudo}</span>
{/if}
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<label for="optout"> Ne pas me tracer de manière anonyme </label> <label for="optout"> Ne pas me tracer de manière anonyme </label>
@ -51,17 +77,20 @@
class="h-4 w-4" class="h-4 w-4"
name="optout" name="optout"
type="checkbox" type="checkbox"
value={optedOut} bind:value={optedOut}
on:change={() => plausible.set(!optedOut)} on:change={() => plausible.set(!optedOut)}
checked={optedOut} checked={optedOut}
/> />
</div> </div>
<p class="text-sm text-highlight-secondary"> <p class="text-sm text-highlight-secondary">
Nous utilisons Plausible pour analyser l'utilisation de notre site web de manière anonyme. Nous utilisons Plausible pour analyser l'utilisation de notre site web de manière anonyme.
</p> </p>
<Button variant="brand"> <Button variant="brand" disabled={submitting}>
<!-- {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} --> {#if submitting}
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
{/if}
Modifier Modifier
</Button> </Button>
</form> </form>

View file

@ -8,10 +8,14 @@
import Button from '$lib/components/ui/Button.svelte'; import Button from '$lib/components/ui/Button.svelte';
import Input from '$lib/components/ui/Input.svelte'; import Input from '$lib/components/ui/Input.svelte';
import { Loader2 } from 'lucide-svelte';
export let data: PageData; export let data: PageData;
const { form, errors, enhance } = superForm(data.form, { const { form, errors, enhance } = superForm(data.form, {
onSubmit() {
submitting = true;
},
onResult({ result }) { onResult({ result }) {
switch (result.type) { switch (result.type) {
case 'success': case 'success':
@ -26,9 +30,12 @@
}); });
break; break;
} }
submitting = false;
} }
}); });
let submitting = false;
let confirmation = false; let confirmation = false;
export const snapshot: Snapshot = { export const snapshot: Snapshot = {
@ -72,8 +79,10 @@
</div> </div>
{/if} {/if}
<Button class="mt-2" variant="brand"> <Button class="mt-2" variant="brand" disabled={submitting}>
<!-- {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} --> {#if submitting}
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
{/if}
{confirmation ? 'Modifier' : 'Envoyer le mail'} {confirmation ? 'Modifier' : 'Envoyer le mail'}
</Button> </Button>

View file

@ -1,8 +1,7 @@
<script lang="ts"> <script lang="ts">
import type { PageData } from './$types'; import type { PageData } from './$types';
import { goto } from '$app/navigation'; import { Loader2 } from 'lucide-svelte';
import { superForm } from 'sveltekit-superforms/client'; import { superForm } from 'sveltekit-superforms/client';
import Button from '$lib/components/ui/Button.svelte'; import Button from '$lib/components/ui/Button.svelte';
@ -10,7 +9,16 @@
export let data: PageData; export let data: PageData;
const { form, errors, enhance } = superForm(data.form); const { form, errors, enhance } = superForm(data.form, {
onSubmit() {
submitting = true;
},
onResult() {
submitting = false;
}
});
let submitting = false;
</script> </script>
<div class="flex h-screen w-full"> <div class="flex h-screen w-full">
@ -32,19 +40,21 @@
/> />
{#if $errors.passwd}<span class="text-sm text-red-500">{$errors.passwd}</span>{/if} {#if $errors.passwd}<span class="text-sm text-red-500">{$errors.passwd}</span>{/if}
<Button class="mt-2" variant="brand"> <Button class="mt-2" variant="brand" disabled={submitting}>
<!-- {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} --> {#if submitting}
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
{/if}
Se connecter Se connecter
</Button> </Button>
<ul class="flex justify-between"> <ul class="flex justify-between">
<li> <li>
<a class="text-highlight-secondary hover:text-brand" href="/sign-up">S'inscrire</a> <a class="text-highlight-secondary hover:text-brand" href="/sign-up"> S'inscrire </a>
</li> </li>
<li> <li>
<a class="text-highlight-secondary hover:text-brand" href="/forgot-password" <a class="text-highlight-secondary hover:text-brand" href="/forgot-password">
>Mot de passe oublié</a Mot de passe oublié
> </a>
</li> </li>
</ul> </ul>
</form> </form>

View file

@ -6,10 +6,14 @@
import Button from '$lib/components/ui/Button.svelte'; import Button from '$lib/components/ui/Button.svelte';
import Input from '$lib/components/ui/Input.svelte'; import Input from '$lib/components/ui/Input.svelte';
import { Loader2 } from 'lucide-svelte';
export let data: PageData; export let data: PageData;
const { form, errors, enhance } = superForm(data.form, { const { form, errors, enhance } = superForm(data.form, {
onSubmit() {
submitting = true;
},
onResult({ result }) { onResult({ result }) {
switch (result.type) { switch (result.type) {
case 'success': case 'success':
@ -19,9 +23,12 @@
confirmation = false; confirmation = false;
break; break;
} }
submitting = false;
} }
}); });
let submitting = false;
let confirmation = false; let confirmation = false;
export const snapshot: Snapshot = { export const snapshot: Snapshot = {
@ -103,8 +110,10 @@
</div> </div>
{/if} {/if}
<Button class="mt-2" variant="brand"> <Button class="mt-2" variant="brand" disabled={submitting}>
<!-- {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} --> {#if submitting}
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{/if}
{confirmation ? "S'inscrire" : 'Continuer'} {confirmation ? "S'inscrire" : 'Continuer'}
</Button> </Button>
@ -114,9 +123,9 @@
</li> </li>
{#if confirmation} {#if confirmation}
<li> <li>
<button formaction="?/register" class="text-highlight-secondary hover:text-brand" <button formaction="?/register" class="text-highlight-secondary hover:text-brand">
>Pas reçu ?</button Pas reçu ?
> </button>
</li> </li>
{/if} {/if}
</ul> </ul>