From 04fabf115ccea31ac504b06cc51d78423b697f60 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Tue, 28 Jul 2026 15:07:57 +0200 Subject: refactor: services layer, valibot validation, shared CSS utilities, aria labels, and drizzle migrate - Extract groceries/categories/references services with db injection - Add valibot for form validation and safe numeric id parsing - Fix category delete FK behavior with onDelete: set null + migration - Replace custom migrate.js with drizzle-orm/libsql/migrator - Add shared CSS utility classes in app.css (forms, lists, buttons) - Add aria-pressed and aria-label on interactive elements - Remove redundant app.css imports and unused /stores import - Add integration tests for all services using drizzle migrate helper - Remove smoke test; add db:migrate and db:studio scripts --- src/routes/categories/+page.server.ts | 32 ++++---- src/routes/categories/+page.svelte | 146 +++++----------------------------- 2 files changed, 36 insertions(+), 142 deletions(-) (limited to 'src/routes/categories') diff --git a/src/routes/categories/+page.server.ts b/src/routes/categories/+page.server.ts index 7cedd98..ac53ca8 100644 --- a/src/routes/categories/+page.server.ts +++ b/src/routes/categories/+page.server.ts @@ -1,38 +1,38 @@ import { fail } from '@sveltejs/kit'; -import { db } from '$lib/server/db'; -import { categories } from '$lib/server/db/schema'; -import { eq, asc } from 'drizzle-orm'; +import { loadAll, add, deleteCategory } from '$lib/server/services/categories'; +import { numericId, parseFormString } from '$lib/server/services/validation'; +import type { Category } from '$lib/server/services/types'; import type { Actions, PageServerLoad } from './$types'; -export const load: PageServerLoad = async () => { - const items = await db - .select() - .from(categories) - .orderBy(asc(categories.name)); +export interface CategoriesOutput { + categories: Category[]; +} - return { categories: items }; +export const load: PageServerLoad = async () => { + return { categories: await loadAll() }; }; export const actions: Actions = { add: async ({ request }) => { const data = await request.formData(); - const name = data.get('name')?.toString().trim(); + const name = parseFormString(data.get('name')); if (!name) { return fail(400, { error: 'Le nom est requis' }); } - await db.insert(categories).values({ name }); - + await add(name); return { success: true }; }, delete: async ({ request }) => { const data = await request.formData(); - const id = Number(data.get('id')); - - await db.delete(categories).where(eq(categories.id, id)); - + try { + const id = numericId(data.get('id')); + await deleteCategory(id); + } catch { + return fail(400, { error: 'ID invalide' }); + } return { success: true }; }, }; diff --git a/src/routes/categories/+page.svelte b/src/routes/categories/+page.svelte index eab0219..41b40c5 100644 --- a/src/routes/categories/+page.svelte +++ b/src/routes/categories/+page.svelte @@ -1,15 +1,20 @@ -
+ - +
{#if form?.error} @@ -27,9 +32,15 @@