diff --git a/src/lib/components/breadcrumb.svelte b/src/lib/components/breadcrumb.svelte index c43233b..a0cd369 100644 --- a/src/lib/components/breadcrumb.svelte +++ b/src/lib/components/breadcrumb.svelte @@ -3,13 +3,17 @@ import * as Breadcrumb from '$lib/components/ui/breadcrumb'; - $: segments = $page.url.pathname.slice(1).split('/'); - $: breadcrumb = segments.map((segment, index) => { - return { - name: segment.charAt(0).toUpperCase() + segment.slice(1), - href: '/' + segments.slice(0, index + 1).join('/') - }; - }) as { name: string; href: string }[]; + export let breadcrumb: { name: string; href: string }[] = []; + + $: page.subscribe(({ url: { pathname } }) => { + breadcrumb = pathname + .split('/') + .slice(1) + .map((segment, index, segments) => ({ + name: segment.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()), + href: '/' + segments.slice(0, index + 1).join('/') + })); + }); diff --git a/src/lib/components/layout/navbar/navbar-user.svelte b/src/lib/components/layout/navbar/navbar-user.svelte index 1222150..cbe9865 100644 --- a/src/lib/components/layout/navbar/navbar-user.svelte +++ b/src/lib/components/layout/navbar/navbar-user.svelte @@ -30,6 +30,7 @@ + Menu utilisateur diff --git a/src/lib/components/layout/navbar/navbar.svelte b/src/lib/components/layout/navbar/navbar.svelte index 5caea46..00048fb 100644 --- a/src/lib/components/layout/navbar/navbar.svelte +++ b/src/lib/components/layout/navbar/navbar.svelte @@ -6,12 +6,10 @@ diff --git a/src/lib/validations/auth.ts b/src/lib/validations/auth.ts index e5f0b4c..28c5ea9 100644 --- a/src/lib/validations/auth.ts +++ b/src/lib/validations/auth.ts @@ -1,19 +1,17 @@ import { z } from 'zod'; export const loginSchema = z.object({ - pseudo: z.string({ required_error: "Nom d'utilisateur requis", }) + pseudo: z.string() .trim() .min(1, { message: "Nom d'utilisateur requis" }), - passwd: z.string({ required_error: 'Mot de passe requis' }) + passwd: z.string() .trim() .min(1, { message: 'Mot de passe requis' }), }); export const registerSchema = z.object({ email: z - .string({ - required_error: 'Email requis' - }) + .string() .trim() .max(64, { message: 'Email trop long (max 64 caractères)' @@ -22,20 +20,15 @@ export const registerSchema = z.object({ message: 'Email invalide' }), firstname: z.string() - .trim(), + .trim().min(1, { message: "Prénom requis" }), lastname: z.string() - .trim(), - pseudo: z.string({ - required_error: 'Nom d\'utilisateur requis' - }).trim(), + .trim().min(1, { message: "Nom requis" }), + pseudo: z.string().trim().min(1, { message: "Nom d'utilisateur requis" }), }); - export const registerConfirmationSchema = z.object({ email: z - .string({ - required_error: 'Email requis' - }) + .string() .trim() .max(64, { message: 'Email trop long (max 64 caractères)' @@ -44,41 +37,61 @@ export const registerConfirmationSchema = z.object({ message: 'Email invalide' }), firstname: z.string() - .trim(), + .trim() + .min(1, { message: "Prénom requis" }), lastname: z.string() - .trim(), - pseudo: z.string({ - required_error: 'Nom d\'utilisateur requis' - }).trim(), - passwd: z.string({ - required_error: 'Mot de passe requis' - }) + .trim() + .min(1, { message: "Nom requis" }), + pseudo: z.string().trim().min(1, { message: "Nom d'utilisateur requis" }), + passwd: z.string() .trim() .min(1, { message: 'Mot de passe requis' }), - code: z.string({ - required_error: 'Code manquant' - }) + confirm: z.string() + .trim() + .min(1, { message: 'Confirmation du mot de passe requise' }), + code: z.string() + .trim() .regex(/^[0-9]{4}$/, { message: 'Code invalide, il doit contenir 4 chiffres' }) - .trim(), +}).refine((data) => data.passwd == data.confirm, { + message: 'Les mots de passe ne correspondent pas', + path: ['confirm'] }); export const requestPasswordResetSchema = z.object({ - email: z.string({ required_error: 'Email requis' }) + email: z.string() .trim() - .email({ message: 'Email invalide' }) - .min(1, { message: 'Email requis' }) + .max(64, { + message: 'Email trop long (max 64 caractères)' + }) + .email({ + message: 'Email invalide' + }), }); export const resetPasswordSchema = z.object({ - email: z.string({ required_error: 'Email requis' }) + email: z.string() .trim() - .email({ message: 'Email invalide' }) - .min(1, { message: 'Email requis' }), - password: z.string({ required_error: 'Mot de passe requis' }) + .max(64, { + message: 'Email trop long (max 64 caractères)' + }) + .email({ + message: 'Email invalide' + }), + password: z.string() .trim() .min(1, { message: 'Mot de passe requis' }), - code: z.string({ - required_error: 'Code manquant' - }) - .regex(/^[0-9]{4}$/, { message: 'Code invalide, il doit contenir 4 chiffres' }), + confirm: z.string() + .trim() + .min(1, { message: 'Confirmation du mot de passe requise' }), + code: z.string() + .regex(/^[0-9]{4}$/, { message: 'Code invalide, il doit contenir 4 chiffres' }), +}).refine((data) => data.password == data.confirm, { + message: 'Les mots de passe ne correspondent pas', + path: ['confirm'] +}); + +export const settingSchema = z.object({ + firstname: z.string().trim().min(1, { message: "Prénom requis" }), + lastname: z.string().trim().min(1, { message: "Nom requis" }), + pseudo: z.string().trim().min(1, { message: "Nom d'utilisateur requis" }), }); diff --git a/src/lib/validations/group.ts b/src/lib/validations/group.ts index 0d7a427..860cc56 100644 --- a/src/lib/validations/group.ts +++ b/src/lib/validations/group.ts @@ -1,8 +1,5 @@ import { z } from 'zod'; export const groupSchema = z.object({ - name: z.string({ - required_error: 'Un nom est requis', - }) - .min(1, 'Un nom est requis',), + name: z.string().trim().min(1, 'Un nom de groupe est requis'), }); diff --git a/src/lib/validations/puzzle.ts b/src/lib/validations/puzzle.ts index 84f7a60..e592692 100644 --- a/src/lib/validations/puzzle.ts +++ b/src/lib/validations/puzzle.ts @@ -1,8 +1,6 @@ import { z } from 'zod'; export const puzzleSchema = z.object({ - answer: z.string({ - required_error: 'Une réponse est requise', - }) + answer: z.string() .min(1, 'Une réponse est requise') }); diff --git a/src/routes/(app)/+page.svelte b/src/routes/(app)/+page.svelte index d435b6a..0b70737 100644 --- a/src/routes/(app)/+page.svelte +++ b/src/routes/(app)/+page.svelte @@ -34,15 +34,7 @@ >
{data.event.name} - {#if data.event.start && data.event.end} - - {new Date(data.event.start).toLocaleDateString()} - {new Date( - data.event.end - ).toLocaleDateString()} - - {:else} - Aucune date - {/if} + Participer en équipe de 1 à 4 joueurs
diff --git a/src/routes/(app)/chapters/[chapterId]/+page.svelte b/src/routes/(app)/chapters/[chapterId]/+page.svelte index 7e1230b..8aeabf9 100644 --- a/src/routes/(app)/chapters/[chapterId]/+page.svelte +++ b/src/routes/(app)/chapters/[chapterId]/+page.svelte @@ -29,7 +29,7 @@ Voir les groupes {#if data.chapter.start && data.chapter.end} - diff --git a/src/routes/(app)/leaderboard/[chapterId]/+page.server.ts b/src/routes/(app)/chapters/[chapterId]/leaderboard/+page.server.ts similarity index 72% rename from src/routes/(app)/leaderboard/[chapterId]/+page.server.ts rename to src/routes/(app)/chapters/[chapterId]/leaderboard/+page.server.ts index b83ec81..15f9863 100644 --- a/src/routes/(app)/leaderboard/[chapterId]/+page.server.ts +++ b/src/routes/(app)/chapters/[chapterId]/leaderboard/+page.server.ts @@ -1,12 +1,10 @@ import { API_URL } from '$env/static/private'; - +import type { PageServerLoad } from './$types'; import { redirect } from '@sveltejs/kit'; import type { LeaderboardEvent } from '$lib/types'; -import type { PageServerLoad } from './$types'; - -export const load = (async ({ locals: { user }, fetch, cookies, params: { chapterId } }) => { +export const load: PageServerLoad = async ({ locals: { user }, fetch, cookies, params: { chapterId } }) => { if (!user) redirect(302, '/login'); @@ -20,14 +18,18 @@ export const load = (async ({ locals: { user }, fetch, cookies, params: { chapte } }); - if (!res.ok) redirect(302, '/'); + if (!res.ok) return { + leaderboard: [] + } const leaderboard = (await res.json()) as LeaderboardEvent; - if (!leaderboard) redirect(302, '/'); + if (!leaderboard) return { + leaderboard: [] + } return { title: "Classement", leaderboard }; -}) satisfies PageServerLoad; +}; diff --git a/src/routes/(app)/leaderboard/[chapterId]/+page.svelte b/src/routes/(app)/chapters/[chapterId]/leaderboard/+page.svelte similarity index 89% rename from src/routes/(app)/leaderboard/[chapterId]/+page.svelte rename to src/routes/(app)/chapters/[chapterId]/leaderboard/+page.svelte index 1352fe0..659c241 100644 --- a/src/routes/(app)/leaderboard/[chapterId]/+page.svelte +++ b/src/routes/(app)/chapters/[chapterId]/leaderboard/+page.svelte @@ -26,14 +26,15 @@ -
+
- +
+ @@ -42,14 +43,15 @@ {#if !data.leaderboard.groups.length} - + {:else} {#each data.leaderboard.groups.filter( (g) => g.players.reduce((a, b) => a + b.score, 0) ) as group (group)} +
#Equipe Joueurs Score Essais
Aucun groupe n'a encore de score + Aucun groupe n'a encore de score +
{group.rank}{group.name} {#if group.players?.length} {group.players.map((player) => player?.pseudo).join(', ')} diff --git a/src/routes/(app)/leaderboard/+page.server.ts b/src/routes/(app)/leaderboard/+page.server.ts index c80b75b..5d0267a 100644 --- a/src/routes/(app)/leaderboard/+page.server.ts +++ b/src/routes/(app)/leaderboard/+page.server.ts @@ -19,7 +19,7 @@ export const load = (async ({ locals: { user }, fetch, cookies }) => { if (!res.ok) { return { - leaderboard: [] as Leaderboard[] + leaderboard: [] }; } diff --git a/src/routes/(app)/leaderboard/+page.svelte b/src/routes/(app)/leaderboard/+page.svelte index f557545..f6e80e3 100644 --- a/src/routes/(app)/leaderboard/+page.svelte +++ b/src/routes/(app)/leaderboard/+page.svelte @@ -15,10 +15,12 @@

Suivez la progression des élèves en direct

-
+
- - +
+ diff --git a/src/routes/(app)/settings/+page.server.ts b/src/routes/(app)/settings/+page.server.ts index f44c18d..359b416 100644 --- a/src/routes/(app)/settings/+page.server.ts +++ b/src/routes/(app)/settings/+page.server.ts @@ -2,17 +2,11 @@ import { API_URL } from '$env/static/private'; import { fail, redirect, type Actions } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; +import { settingSchema } from '$lib/validations/auth'; import { zod } from 'sveltekit-superforms/adapters'; -import { superValidate } from 'sveltekit-superforms/server'; -import { z } from 'zod'; +import { setError, superValidate } from 'sveltekit-superforms/server'; -const settingSchema = z.object({ - firstname: z.string().min(1, { message: "Prénom requis" }), - lastname: z.string().min(1, { message: "Nom requis" }), - pseudo: z.string().min(1, { message: "Nom d'utilisateur requi" }), -}); - -export const load = (async ({ locals: { user } }) => { +export const load: PageServerLoad = async ({ locals: { user } }) => { if (!user) redirect(302, '/login'); const form = await superValidate(user, zod(settingSchema)); @@ -21,10 +15,13 @@ export const load = (async ({ locals: { user } }) => { title: 'Paramètres', form }; -}) satisfies PageServerLoad; +}; + +export const actions: Actions = { + default: async ({ request, cookies, locals: { user } }) => { + + if (!user) return fail(401); -export const actions = { - default: async ({ request, cookies }) => { const session = cookies.get('session'); const form = await superValidate(request, zod(settingSchema)); @@ -38,21 +35,20 @@ export const actions = { headers: { Authorization: `Bearer ${session}` }, - body: JSON.stringify(form.data) + body: JSON.stringify({ + ...form.data + }) }); - if (res.ok) { - return { - success: true - }; + if (!res.ok) { + if (res.status === 400) { + return setError(form, "pseudo", "Ce pseudo est déjà utilisé"); + } + return setError(form, "pseudo", "Une erreur est survenue lors de la sauvegarde des paramètres"); } - if (res.status === 400) { - form.errors.pseudo = ['Le pseudo est déjà utilisé']; - - return fail(400, { form }); - } - - return fail(500, { form }); + return { + form + }; } -} satisfies Actions; +}; diff --git a/src/routes/(app)/settings/+page.svelte b/src/routes/(app)/settings/+page.svelte index 3571914..630c175 100644 --- a/src/routes/(app)/settings/+page.svelte +++ b/src/routes/(app)/settings/+page.svelte @@ -1,106 +1,76 @@
-
+

Paramètres généraux

- +
- - + - - - - {#if $errors.firstname} - {$errors.firstname} - {/if} - - - - {#if $errors.lastname} - {$errors.lastname} - {/if} - - - - {#if $errors.pseudo} - {$errors.pseudo} - {/if} - -
- - plausible.set(!$plausible)} - checked={$plausible} - /> -
- -

- Nous utilisons Plausible pour analyser l'utilisation de notre site web de manière anonyme. -

+

Votre email ne peut pas être modifié.

+ + + Prénom + + + + + + + Nom de famille + + + + + + + Nom d'utilisateur + + + Ce nom sera visible par les autres utilisateurs. + +
diff --git a/src/routes/(auth)/login/+page.server.ts b/src/routes/(auth)/login/+page.server.ts index e19beb4..20d2de9 100644 --- a/src/routes/(auth)/login/+page.server.ts +++ b/src/routes/(auth)/login/+page.server.ts @@ -4,7 +4,7 @@ import { fail, redirect, type Actions } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; import { zod } from 'sveltekit-superforms/adapters'; -import { superValidate } from 'sveltekit-superforms/server'; +import { setError, superValidate } from 'sveltekit-superforms/server'; import { loginSchema } from '$lib/validations/auth'; @@ -37,19 +37,13 @@ export const actions: Actions = { }); if (!res.ok) { - - form.errors.passwd = ["Nom d'utilisateur ou mot de passe incorrect"]; - - return fail(400, { form }); + return setError(form, 'passwd', "Nom d'utilisateur ou mot de passe incorrect"); } - const token = res.headers.get('Authorization')?.split(' ').pop(); + const token = res.headers.get('Authorization')?.split('Bearer ').pop(); if (!token) { - - form.errors.passwd = ["Une erreur est survenue, veuillez réessayer plus tard"]; - - return fail(500, { form }); + return setError(form, 'passwd', "Une erreur est survenue, veuillez réessayer plus tard"); } cookies.set('session', token, { diff --git a/src/routes/(auth)/login/+page.svelte b/src/routes/(auth)/login/+page.svelte index 559135d..f06a4d8 100644 --- a/src/routes/(auth)/login/+page.svelte +++ b/src/routes/(auth)/login/+page.svelte @@ -1,7 +1,7 @@
{#if confirmation} -

Confirmation

+

Confirmation

+ + + Confirmer le mot de passe + + + + Code @@ -156,16 +162,12 @@
- + {#if $registerConfirmationDelayed} {/if} Continuer - - {:else}

Inscription

@@ -208,14 +210,12 @@ -
- - {#if $registerDelayed} - - {/if} - S'inscrire - -
+ + {#if $registerDelayed} + + {/if} + S'inscrire + {/if}
    diff --git a/src/routes/(auth)/reset-password/+page.server.ts b/src/routes/(auth)/reset-password/+page.server.ts index 04cdf20..afbe2b5 100644 --- a/src/routes/(auth)/reset-password/+page.server.ts +++ b/src/routes/(auth)/reset-password/+page.server.ts @@ -6,7 +6,7 @@ import { fail, redirect, type Actions } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; import { zod } from 'sveltekit-superforms/adapters'; -import { superValidate } from 'sveltekit-superforms/server'; +import { setError, superValidate } from 'sveltekit-superforms/server'; import { requestPasswordResetSchema, resetPasswordSchema } from '$lib/validations/auth'; @@ -23,7 +23,7 @@ export const load = (async ({ locals: { user } }) => { }; }) satisfies PageServerLoad; -export const actions = { +export const actions: Actions = { request: async ({ request, fetch }) => { const form = await superValidate(request, zod(requestPasswordResetSchema)); @@ -33,16 +33,17 @@ export const actions = { const res = await fetch(`${API_URL}/user/fpw`, { method: 'POST', - body: JSON.stringify(form.data) + body: JSON.stringify({ + ...form.data + }) }); if (!res.ok) { - form.errors.email = ["Une erreur s'est produite ou l'email n'existe pas"]; - return fail(400, { form }); + return setError(form, 'email', "Une erreur s'est produite ou l'email n'existe pas"); } return { - success: true + form } }, confirmation: async ({ request, cookies, fetch }) => { @@ -62,11 +63,10 @@ export const actions = { }); if (res.ok) { - const token = res.headers.get('Authorization')?.split('Bearer ')[1]; + const token = res.headers.get('Authorization')?.split('Bearer ').pop(); if (!token) { - form.errors.code = ["Une erreur s'est produite"]; - return fail(400, { form }); + return setError(form, 'code', "Une erreur est survenue, veuillez réessayer plus tard"); } cookies.set('session', token, { @@ -79,13 +79,9 @@ export const actions = { } if (res.status === 400) { - form.errors.code = ['Code invalide']; - } else { - form.errors.code = [`Une erreur s'est produite`]; + return setError(form, 'code', "Le code de confirmation est incorrect"); } - return fail(400, { - form - }); + return setError(form, 'code', "Une erreur est survenue, veuillez réessayer plus tard"); } -} satisfies Actions; +} diff --git a/src/routes/(auth)/reset-password/+page.svelte b/src/routes/(auth)/reset-password/+page.svelte index 66d34e7..da23279 100644 --- a/src/routes/(auth)/reset-password/+page.svelte +++ b/src/routes/(auth)/reset-password/+page.svelte @@ -1,15 +1,15 @@
    {#if confirmation} -

    Confirmation

    +

    Confirmation

    + + + Confirmer le mot de passe + + + + Code @@ -118,7 +128,7 @@ {#if $resetPasswordDelayed} - + {/if} Changer le mot de passe @@ -157,7 +167,7 @@ {#if $requestPasswordResetDelayed} - + {/if} Continuer
# Nom