fix(frontend): address all PR review concerns
- Fix 7px → 11px font-size on section headers in RecipePicker - Extract shared slotActions.ts with UUID validation for planId/slotId/recipeId - Load full recipe list in planner page load (was placeholder current-week slots) - Update planner/+page.svelte to pass data.recipes as allRecipes to RecipePicker - Update planner and recipes page.server.ts to use shared slot action helpers - Fix planner page.server tests: add recipes mock for parallel GET load - Update action tests to use valid UUIDs (were 'plan-1'/'r1' style strings) - Add validation-path tests for blank/invalid input on all slot actions - Add tests for recipes/+server.ts GET endpoint (DayPicker week navigation) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -73,7 +73,7 @@
|
||||
<!-- Empfohlen section -->
|
||||
{#if suggestions.length > 0}
|
||||
<div
|
||||
style="font-size: 7px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-muted); padding: 5px 12px 3px; background: var(--color-subtle);"
|
||||
style="font-size: 11px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-muted); padding: 5px 12px 3px; background: var(--color-subtle);"
|
||||
>
|
||||
Empfohlen · Beste Abwechslung
|
||||
</div>
|
||||
@@ -127,7 +127,7 @@
|
||||
|
||||
<!-- Alle Rezepte section -->
|
||||
<div
|
||||
style="font-size: 7px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-muted); padding: 5px 12px 3px; background: var(--color-subtle);"
|
||||
style="font-size: 11px; font-weight: 500; letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-muted); padding: 5px 12px 3px; background: var(--color-subtle);"
|
||||
>
|
||||
Alle Rezepte
|
||||
</div>
|
||||
|
||||
65
frontend/src/lib/server/slotActions.ts
Normal file
65
frontend/src/lib/server/slotActions.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { apiClient } from '$lib/server/api';
|
||||
|
||||
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
||||
|
||||
function isValidUuid(value: string | null): value is string {
|
||||
return typeof value === 'string' && UUID_RE.test(value);
|
||||
}
|
||||
|
||||
export async function addSlotAction({ fetch, request }: { fetch: typeof globalThis.fetch; request: Request }) {
|
||||
const formData = await request.formData();
|
||||
const planId = formData.get('planId') as string | null;
|
||||
const slotDate = formData.get('slotDate') as string | null;
|
||||
const recipeId = formData.get('recipeId') as string | null;
|
||||
|
||||
if (!isValidUuid(planId) || !isValidUuid(recipeId) || !slotDate) {
|
||||
return { success: false, error: 'Ungültige Eingabe.' };
|
||||
}
|
||||
|
||||
const api = apiClient(fetch);
|
||||
const { data, error } = await api.POST('/v1/week-plans/{id}/slots', {
|
||||
params: { path: { id: planId } },
|
||||
body: { slotDate, recipeId }
|
||||
});
|
||||
|
||||
if (error || !data) return { success: false };
|
||||
return { success: true, slot: data };
|
||||
}
|
||||
|
||||
export async function updateSlotAction({ fetch, request }: { fetch: typeof globalThis.fetch; request: Request }) {
|
||||
const formData = await request.formData();
|
||||
const planId = formData.get('planId') as string | null;
|
||||
const slotId = formData.get('slotId') as string | null;
|
||||
const recipeId = formData.get('recipeId') as string | null;
|
||||
|
||||
if (!isValidUuid(planId) || !isValidUuid(slotId) || !isValidUuid(recipeId)) {
|
||||
return { success: false, error: 'Ungültige Eingabe.' };
|
||||
}
|
||||
|
||||
const api = apiClient(fetch);
|
||||
const { data, error } = await api.PATCH('/v1/week-plans/{planId}/slots/{slotId}', {
|
||||
params: { path: { planId, slotId } },
|
||||
body: { recipeId }
|
||||
});
|
||||
|
||||
if (error || !data) return { success: false };
|
||||
return { success: true, slot: data };
|
||||
}
|
||||
|
||||
export async function deleteSlotAction({ fetch, request }: { fetch: typeof globalThis.fetch; request: Request }) {
|
||||
const formData = await request.formData();
|
||||
const planId = formData.get('planId') as string | null;
|
||||
const slotId = formData.get('slotId') as string | null;
|
||||
|
||||
if (!isValidUuid(planId) || !isValidUuid(slotId)) {
|
||||
return { success: false, error: 'Ungültige Eingabe.' };
|
||||
}
|
||||
|
||||
const api = apiClient(fetch);
|
||||
const { error } = await api.DELETE('/v1/week-plans/{planId}/slots/{slotId}', {
|
||||
params: { path: { planId, slotId } }
|
||||
});
|
||||
|
||||
if (error) return { success: false };
|
||||
return { success: true };
|
||||
}
|
||||
Reference in New Issue
Block a user