'use client'; import { useState, useEffect, useCallback } from 'react'; import Link from 'next/link'; import type { Recipe } from '../../features/inventory/types'; const DAYS_SV = ['Måndag', 'Tisdag', 'Onsdag', 'Torsdag', 'Fredag', 'Lördag', 'Söndag']; type MealPlanEntry = { id: number; date: string; recipe: Pick & { ingredients: { quantity: string; unit: string; note: string | null; product: { id: number; name: string; canonicalName: string | null } }[]; }; }; type ShoppingItem = { productId: number; name: string; quantity: number; unit: string }; function getWeekDates(offset = 0): string[] { const now = new Date(); const day = now.getDay(); const monday = new Date(now); monday.setDate(now.getDate() - (day === 0 ? 6 : day - 1) + offset * 7); return Array.from({ length: 7 }, (_, i) => { const d = new Date(monday); d.setDate(monday.getDate() + i); return d.toISOString().slice(0, 10); }); } export default function MealPlanClient({ recipes }: { recipes: Recipe[] }) { const [weekOffset, setWeekOffset] = useState(0); const [entries, setEntries] = useState([]); const [shopping, setShopping] = useState([]); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(null); // date being saved const weekDates = getWeekDates(weekOffset); const from = weekDates[0]; const to = weekDates[6]; const weekLabel = (() => { const f = new Date(from); const t = new Date(to); return `${f.toLocaleDateString('sv-SE', { day: 'numeric', month: 'short' })} – ${t.toLocaleDateString('sv-SE', { day: 'numeric', month: 'short', year: 'numeric' })}`; })(); const load = useCallback(async () => { setLoading(true); try { const [entriesRes, shoppingRes] = await Promise.all([ fetch(`/api/meal-plan-proxy?from=${from}&to=${to}`), fetch(`/api/meal-plan-proxy/shopping?from=${from}&to=${to}`), ]); const entriesData = await entriesRes.json(); setEntries(Array.isArray(entriesData) ? entriesData : []); if (shoppingRes.ok) setShopping(await shoppingRes.json()); else setShopping([]); } catch { setEntries([]); setShopping([]); } finally { setLoading(false); } }, [from, to]); useEffect(() => { load(); }, [load]); const entryForDate = (date: string) => entries.find((e) => e.date.slice(0, 10) === date); const handleSelect = async (date: string, recipeId: string) => { setSaving(date); try { if (!recipeId) { await fetch(`/api/meal-plan-proxy?date=${date}`, { method: 'DELETE' }); } else { await fetch('/api/meal-plan-proxy', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ date, recipeId: Number(recipeId) }), }); } await load(); } finally { setSaving(null); } }; const plannedCount = weekDates.filter((d) => entryForDate(d)).length; return (
{/* Veckonavigering */}
{weekLabel} {weekOffset !== 0 && ( )}
{loading ? (

Laddar...

) : ( <> {/* Veckovy */}
{weekDates.map((date, i) => { const entry = entryForDate(date); const isSaving = saving === date; const isToday = date === new Date().toISOString().slice(0, 10); return (
{DAYS_SV[i]}
{new Date(date).toLocaleDateString('sv-SE', { day: 'numeric', month: 'short' })}
{entry && ( Visa recept → )} {isSaving && Sparar...}
); })}
{/* Samlad ingredienslista */}

Inköpslista ({plannedCount} {plannedCount === 1 ? 'recept' : 'recept'} planerade)

{plannedCount === 0 ? (

Välj recept ovan för att se en samlad ingredienslista.

) : shopping.length === 0 ? (

Laddar ingredienser...

) : (
    {shopping.map((item) => (
  • {item.quantity % 1 === 0 ? item.quantity : item.quantity.toFixed(1)} {item.unit} {item.name}
  • ))}
)}
)}
); } function btnStyle(bg?: string): React.CSSProperties { return { padding: '0.45rem 0.9rem', background: bg || '#f0f0f0', color: bg ? '#fff' : '#333', border: '1px solid ' + (bg || '#ccc'), borderRadius: '6px', cursor: 'pointer', fontSize: '0.9rem', fontWeight: 500, }; }