From 6e76977aceba3e316fb5d24d68a7957971e779ef Mon Sep 17 00:00:00 2001 From: ulfrxdev Date: Wed, 25 Mar 2026 23:57:47 +0100 Subject: [PATCH] Unify UX --- stacks/recipe/js/services/planIngredients.js | 50 ++ stacks/recipe/js/views/MealPlanner.js | 511 +++++++++++++------ stacks/recipe/js/views/Pantry.js | 32 +- stacks/recipe/js/views/RecipeDetail.js | 172 +++---- 4 files changed, 492 insertions(+), 273 deletions(-) diff --git a/stacks/recipe/js/services/planIngredients.js b/stacks/recipe/js/services/planIngredients.js index 0377c97..c5fcc95 100644 --- a/stacks/recipe/js/services/planIngredients.js +++ b/stacks/recipe/js/services/planIngredients.js @@ -139,3 +139,53 @@ export function aggregateDayIngredientsBySlot(dayPlan) { }); return blocks; } + +export function countDayShortfalls(dayPlan, pantry) { + const lines = mergeIngredientLines(flattenDayIngredientLines(dayPlan)); + let count = 0; + for (const line of lines) { + if ((Number(pantry[line.ingredientId]) || 0) < line.amount) count++; + } + return count; +} + +/** + * Kumulatywna prognoza zużycia spiżarni: od startDate przez lookAheadDays dni. + * Zwraca tablicę dni (tylko te z posiłkami), każdy z listą składników i informacją + * ile jest w spiżarni (po odjęciu zużycia z poprzednich dni) i ile brakuje. + */ +export function computeFullForecast(plans, pantry, startDate, lookAheadDays = 8) { + const running = { ...pantry }; + const days = []; + + for (let i = 0; i < lookAheadDays; i++) { + const day = addDays(startDate, i); + const dayPlan = getDayPlan(plans, day); + const lines = mergeIngredientLines(flattenDayIngredientLines(dayPlan)); + if (lines.length === 0) continue; + + const items = lines.map((line) => { + const def = INGREDIENTS[line.ingredientId]; + const have = Math.round((Number(running[line.ingredientId]) || 0) * 10) / 10; + const miss = Math.max(0, Math.round((line.amount - have) * 10) / 10); + return { + ...line, + pantryQty: have, + shortfall: miss, + enough: miss <= 0, + pantryUnit: def + ? def.pantryUnit === 'szt' ? 'szt.' : def.pantryUnit + : line.unit, + }; + }); + + for (const line of lines) { + const have = Number(running[line.ingredientId]) || 0; + running[line.ingredientId] = Math.max(0, Math.round((have - line.amount) * 10) / 10); + } + + days.push({ date: day, dayIndex: i, items, hasShortfall: items.some((it) => !it.enough) }); + } + + return days; +} diff --git a/stacks/recipe/js/views/MealPlanner.js b/stacks/recipe/js/views/MealPlanner.js index f638537..de72e69 100644 --- a/stacks/recipe/js/views/MealPlanner.js +++ b/stacks/recipe/js/views/MealPlanner.js @@ -1,4 +1,4 @@ -import { RECIPES } from '../data/catalog.js'; +import { INGREDIENTS, RECIPES } from '../data/catalog.js'; import { MEAL_SLOTS } from '../planner/mealSlots.js'; import { addDays, @@ -12,11 +12,12 @@ import { weekContains, } from '../services/dateUtils.js'; import { - aggregateDayIngredientsBySlot, + computeFullForecast, + countDayShortfalls, dayHasAnyMeal, sumDayNutrition, } from '../services/planIngredients.js'; -import { addOrMergeShoppingLines } from '../services/pantryShopping.js'; +import { addOrMergeShoppingLines, loadPantry } from '../services/pantryShopping.js'; import { dateKey, getDayPlan, @@ -72,44 +73,39 @@ export function getMealPlannerHTML() { -
+
-
- - -
-
-
- ${WEEKDAYS_SHORT.map((d) => `
${d}
`).join('')} +
+
+
+ ${WEEKDAYS_SHORT.map((d) => `
${d}
`).join('')} +
+
-
-
-
-

-
+

+

Dziś — podsumowanie

-

0 kcal

+

0 kcal

-
@@ -149,30 +145,30 @@ export function getMealPlannerHTML() {