import { INGREDIENTS, RECIPES, PRODUCTS } from '../data/catalog.js?v=9'; import { MEAL_SLOTS } from '../planner/mealSlots.js'; import { PLANS_STORAGE_KEY } from '../storageKeys.js'; import { startOfDay } from './dateUtils.js'; export function dateKey(d) { const x = startOfDay(d); const y = x.getFullYear(); const m = String(x.getMonth() + 1).padStart(2, '0'); const day = String(x.getDate()).padStart(2, '0'); return `${y}-${m}-${day}`; } export function newPlanEntryId() { if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') { return crypto.randomUUID(); } return `e${Date.now()}-${Math.random().toString(36).slice(2, 11)}`; } function normalizeEntryExtras(x) { const out = {}; if (x.substitutions && typeof x.substitutions === 'object' && !Array.isArray(x.substitutions) && Object.keys(x.substitutions).length > 0) { out.substitutions = { ...x.substitutions }; } if (Array.isArray(x.excludedIngredients)) { const arr = x.excludedIngredients.filter((id) => typeof id === 'string'); if (arr.length > 0) out.excludedIngredients = arr; } if (x.amountOverrides && typeof x.amountOverrides === 'object' && !Array.isArray(x.amountOverrides)) { const filtered = {}; for (const [k, v] of Object.entries(x.amountOverrides)) { if (typeof v === 'number' && v >= 0) filtered[k] = v; } if (Object.keys(filtered).length > 0) out.amountOverrides = filtered; } if (Array.isArray(x.addedIngredients)) { const valid = x.addedIngredients .filter((a) => a && typeof a.ingredientId === 'string' && INGREDIENTS[a.ingredientId] && typeof a.amount === 'number' && a.amount >= 0 && typeof a.unit === 'string') .map((a) => ({ ingredientId: a.ingredientId, amount: a.amount, unit: a.unit })); if (valid.length > 0) out.addedIngredients = valid; } if (x.productSelections && typeof x.productSelections === 'object' && !Array.isArray(x.productSelections)) { const ps = {}; for (const [k, v] of Object.entries(x.productSelections)) { if (typeof v === 'string' && PRODUCTS[v]) ps[k] = v; } if (Object.keys(ps).length > 0) out.productSelections = ps; } return out; } /** Jedna pora dnia = tablica wpisów { id, recipeId, servings, ...extras } */ export function normalizeSlotValue(v) { if (!v) return []; if (Array.isArray(v)) { return v .filter((x) => x && x.recipeId && RECIPES[x.recipeId]) .map((x) => ({ id: x.id && String(x.id).length ? String(x.id) : newPlanEntryId(), recipeId: x.recipeId, servings: Math.max(1, Math.min(12, Number(x.servings) || 1)), ...normalizeEntryExtras(x), })); } if (typeof v === 'object' && v.recipeId && RECIPES[v.recipeId]) { return [{ id: newPlanEntryId(), recipeId: v.recipeId, servings: Math.max(1, Math.min(12, Number(v.servings) || 1)), ...normalizeEntryExtras(v), }]; } return []; } export function normalizeDayPlan(day) { if (!day || typeof day !== 'object') return {}; const out = {}; MEAL_SLOTS.forEach((s) => { const arr = normalizeSlotValue(day[s.id]); if (arr.length > 0) out[s.id] = arr; }); if (day._skipped && typeof day._skipped === 'object') { const sk = {}; for (const k of Object.keys(day._skipped)) { if (day._skipped[k] === true) sk[k] = true; } if (Object.keys(sk).length > 0) out._skipped = sk; } return out; } export function normalizeAllPlans(plans) { if (!plans || typeof plans !== 'object') return {}; const out = {}; Object.keys(plans).forEach((key) => { const d = normalizeDayPlan(plans[key]); if (Object.keys(d).length > 0) out[key] = d; }); return out; } export function loadPlans() { try { const raw = localStorage.getItem(PLANS_STORAGE_KEY); if (!raw) return {}; const parsed = JSON.parse(raw); if (typeof parsed !== 'object' || parsed === null) return {}; return normalizeAllPlans(parsed); } catch { return {}; } } export function savePlans(plans) { try { localStorage.setItem(PLANS_STORAGE_KEY, JSON.stringify(plans)); } catch { /* ignore */ } } export function getDayPlan(plans, d) { const key = dateKey(d); const day = plans[key]; return day && typeof day === 'object' ? day : {}; }