From 657d006441f3694234890ed01c44a997fed0288e Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Fri, 17 Apr 2026 18:43:38 +0200 Subject: [PATCH] fix(recipe): Favoriten-Markierung persistiert beim Neuladen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: Beim Neuanzeigen einer Rezeptseite war der Favoriten-Button immer grau — isFav wurde als local $state(false) initialisiert und die checkFavorite()-Funktion war eine Stub-Implementation, die nichts gemacht hat. State lebte nur innerhalb einer Session. Fix: - Neue Server-Funktion listFavoriteProfiles(db, recipeId): number[] in $lib/server/recipes/actions.ts - +page.server.ts lädt favorite_profile_ids mit in die Page-Daten - +page.svelte macht isFav zum $derived aus favoriteProfileIds + aktivem Profil. toggleFavorite mutiert die lokale Liste (Add/Remove der aktiven Profil-ID) — beim nächsten Load ist die Server-Liste wieder Source of Truth. - Alte Stub-Funktion checkFavorite() entfernt (inkl. Aufruf in onMount). --- src/lib/server/recipes/actions.ts | 11 +++++++++++ src/routes/recipes/[id]/+page.server.ts | 4 +++- src/routes/recipes/[id]/+page.svelte | 22 ++++++++++------------ 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/lib/server/recipes/actions.ts b/src/lib/server/recipes/actions.ts index 8eb38fd..6fcaf3c 100644 --- a/src/lib/server/recipes/actions.ts +++ b/src/lib/server/recipes/actions.ts @@ -73,6 +73,17 @@ export function isFavorite( ); } +export function listFavoriteProfiles( + db: Database.Database, + recipeId: number +): number[] { + return ( + db + .prepare('SELECT profile_id FROM favorite WHERE recipe_id = ?') + .all(recipeId) as { profile_id: number }[] + ).map((r) => r.profile_id); +} + export function logCooked( db: Database.Database, recipeId: number, diff --git a/src/routes/recipes/[id]/+page.server.ts b/src/routes/recipes/[id]/+page.server.ts index 9baf2a7..969a987 100644 --- a/src/routes/recipes/[id]/+page.server.ts +++ b/src/routes/recipes/[id]/+page.server.ts @@ -5,6 +5,7 @@ import { getRecipeById } from '$lib/server/recipes/repository'; import { listComments, listCookingLog, + listFavoriteProfiles, listRatings } from '$lib/server/recipes/actions'; @@ -17,7 +18,8 @@ export const load: PageServerLoad = async ({ params }) => { const ratings = listRatings(db, id); const comments = listComments(db, id); const cooking_log = listCookingLog(db, id); + const favorite_profile_ids = listFavoriteProfiles(db, id); const avg_stars = ratings.length === 0 ? null : ratings.reduce((s, r) => s + r.stars, 0) / ratings.length; - return { recipe, ratings, comments, cooking_log, avg_stars }; + return { recipe, ratings, comments, cooking_log, favorite_profile_ids, avg_stars }; }; diff --git a/src/routes/recipes/[id]/+page.svelte b/src/routes/recipes/[id]/+page.svelte index 41b4210..32ec2ff 100644 --- a/src/routes/recipes/[id]/+page.svelte +++ b/src/routes/recipes/[id]/+page.svelte @@ -13,7 +13,7 @@ let ratings = $state([]); let comments = $state([]); let cookingLog = $state([]); - let isFav = $state(false); + let favoriteProfileIds = $state([]); let onWishlist = $state(false); let newComment = $state(''); @@ -21,6 +21,7 @@ ratings = [...data.ratings]; comments = [...data.comments]; cookingLog = [...data.cooking_log]; + favoriteProfileIds = [...data.favorite_profile_ids]; }); const myRating = $derived( @@ -29,14 +30,9 @@ : null ); - async function checkFavorite() { - if (!profileStore.active) { - isFav = false; - return; - } - // Fetch favorite status via list endpoint (quick hack: GET not implemented, infer from no-op) - // Not critical for MVP — we mutate state on toggle. - } + const isFav = $derived( + profileStore.active ? favoriteProfileIds.includes(profileStore.active.id) : false + ); async function setRating(stars: number) { if (!profileStore.active) { @@ -64,13 +60,16 @@ }); return; } + const profileId = profileStore.active.id; const method = isFav ? 'DELETE' : 'PUT'; await fetch(`/api/recipes/${data.recipe.id}/favorite`, { method, headers: { 'content-type': 'application/json' }, - body: JSON.stringify({ profile_id: profileStore.active.id }) + body: JSON.stringify({ profile_id: profileId }) }); - isFav = !isFav; + favoriteProfileIds = isFav + ? favoriteProfileIds.filter((id) => id !== profileId) + : [...favoriteProfileIds, profileId]; } async function logCooked() { @@ -183,7 +182,6 @@ onMount(() => { void requestWakeLock(); - void checkFavorite(); void refreshWishlistState(); const onVisibility = () => { if (document.visibilityState === 'visible' && !wakeLock) void requestWakeLock();