127 lines
4.5 KiB
JavaScript
127 lines
4.5 KiB
JavaScript
import { INGREDIENTS, RECIPES, PRODUCTS } from '../data/catalog.js?v=8';
|
|
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 : {};
|
|
}
|