import {
INGREDIENTS,
PRODUCTS,
CATEGORY_LABELS,
getProductsForIngredient,
ingredientHasProducts,
pantryQtyStep,
} from '../data/catalog.js?v=8';
import {
addOrMergeShoppingLines,
loadPantry,
setPantryQty,
setPantryProductQty,
getPantryTotal,
getPantryProducts,
} from '../services/pantryShopping.js?v=2';
import { showAppToast } from './toast.js';
const CATEGORY_ICONS = {
pieczywo: 'fa-bread-slice',
nabial: 'fa-cheese',
mieso_ryby: 'fa-drumstick-bite',
warzywa: 'fa-carrot',
owoce: 'fa-apple-whole',
suche: 'fa-wheat-awn',
przyprawy: 'fa-leaf',
inne: 'fa-jar',
};
function esc(s) {
return String(s).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
}
function unitLabel(u) {
return u === 'szt' ? 'szt.' : u;
}
function formatQty(n) {
const rounded = Math.round((Number(n) || 0) * 10) / 10;
return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1).replace(/\.0$/, '');
}
function formatQtyWithUnit(qty, unit) {
return `${formatQty(qty)} ${unitLabel(unit)}`;
}
function productCountLabel(count) {
if (count === 1) return '1 produkt';
const mod10 = count % 10;
const mod100 = count % 100;
if (mod10 >= 2 && mod10 <= 4 && !(mod100 >= 12 && mod100 <= 14)) return `${count} produkty`;
return `${count} produktów`;
}
function nutritionForQty(def, qty, nutrition = def?.nutritionPer100g) {
if (!def || !nutrition || !Number.isFinite(qty) || qty <= 0) return null;
let grams = qty;
if (def.pantryUnit === 'szt' && def.weightPerPiece) grams = qty * def.weightPerPiece;
const factor = grams / 100;
return {
kcal: Math.round(nutrition.kcal * factor),
protein: Math.round(nutrition.protein * factor * 10) / 10,
fat: Math.round(nutrition.fat * factor * 10) / 10,
carbs: Math.round(nutrition.carbs * factor * 10) / 10,
};
}
function macroLine(n) {
if (!n) return '';
return `${n.kcal} kcal · ${formatQty(n.protein)}g B · ${formatQty(n.fat)}g T · ${formatQty(n.carbs)}g W`;
}
function mediaHtml(image, icon, sizeClass = 'w-9 h-9', radiusClass = 'rounded-lg') {
if (image) {
return ``;
}
return `
Wartości odżywcze
${esc(unitScope)} • ${esc(hint)}
${nutrition.kcal}
kcal
${formatQty(nutrition.protein)}g
białko
${formatQty(nutrition.fat)}g
tłuszcz
${formatQty(nutrition.carbs)}g
węgl.
Zapas
${esc(formatQty(totalQty))} ${esc(unit)}
${stockedCount} z ${getProductsForIngredient(state.ingredientId).length} produktów ma stan
${esc(macroLine(summaryNutrition))}
` : ''}Zapas
${esc(formatQty(qty))} ${esc(unit)}
Krok: ${esc(formatQty(step))} ${esc(unit)}
${esc(macroLine(stockNutrition))} na stanie
` : ''}`; wrap.querySelectorAll('.ingredient-card-stock-btn').forEach((btn) => { btn.addEventListener('click', () => { const pid = btn.dataset.pid; const stepVal = Number(btn.dataset.step) || 1; const dir = Number(btn.dataset.dir) || 1; const pantryState = loadPantry(); if (pid === '_generic') { const current = getPantryTotal(state.ingredientId, pantryState); setPantryQty(state.ingredientId, Math.max(0, current + stepVal * dir)); } else { const items = getPantryProducts(state.ingredientId, pantryState); const current = items.find((i) => i.productId === pid)?.qty || 0; setPantryProductQty(state.ingredientId, pid, Math.max(0, current + stepVal * dir)); } render(); state.onAfterChange?.(); }); }); } function productRowHtml(ingredientId, productId, pantry, selectedProductId) { const def = INGREDIENTS[ingredientId]; const product = PRODUCTS[productId]; const icon = CATEGORY_ICONS[def.category] || 'fa-jar'; const qty = getPantryProducts(ingredientId, pantry).find((i) => i.productId === productId)?.qty || 0; const isSelected = selectedProductId === productId; return ``; } function renderProducts() { const wrap = el('products'); if (!wrap || !state.ingredientId) return; if (!ingredientHasProducts(state.ingredientId)) { wrap.innerHTML = ''; return; } const pantry = loadPantry(); const products = sortProductsByStock(getProductsForIngredient(state.ingredientId), getPantryProducts(state.ingredientId, pantry)); const selectedProductId = state.selectedProductId || state.productId; const subtitle = state.productId ? 'Wróć lub wybierz inny wariant.' : 'Wybierz wariant, aby zobaczyć szczegóły.'; wrap.innerHTML = `Produkty
${esc(subtitle)}
Lista zakupów
${esc(helperText)}
`; wrap.querySelector('.ingredient-card-add-list')?.addEventListener('click', () => { const amount = usesPacks ? packSize : pantryQtyStep(state.ingredientId); const note = usesPacks ? (packLabel || `${formatQty(packSize)} ${unitLabel(def.pantryUnit)}`) : undefined; const line = { ingredientId: state.ingredientId, amount, unit: unitLabel(def.pantryUnit), name: product?.name || def.name, category: def.category, sourceNote: note || state.sourceNote || defaultSourceNote, }; if (state.productId) line.productId = state.productId; addOrMergeShoppingLines([line]); showAppToast(`Dodano ${product?.name || def.name} na listę.`); window.refreshShopping?.(); }); } function render() { if (!state.ingredientId) return; const def = INGREDIENTS[state.ingredientId]; if (!def) return; const product = state.productId ? PRODUCTS[state.productId] : null; const pantry = loadPantry(); renderHeader(def, product, pantry); renderNutrition(def, product); renderStock(); renderProducts(); renderShop(); } function open({ ingredientId, productId = null, selectedProductId = productId, sourceNote = defaultSourceNote, onProductChange = null, onAfterChange = null, } = {}) { const def = ingredientId ? INGREDIENTS[ingredientId] : null; const overlay = el('overlay'); const card = el(); if (!def || !overlay || !card) return; state.ingredientId = ingredientId; state.productId = productId && PRODUCTS[productId] ? productId : null; state.selectedProductId = selectedProductId && PRODUCTS[selectedProductId] ? selectedProductId : state.productId; state.sourceNote = sourceNote; state.onProductChange = onProductChange; state.onAfterChange = onAfterChange; render(); clearTimeout(state.closeTimer); overlay.classList.remove('hidden'); overlay.style.pointerEvents = 'auto'; requestAnimationFrame(() => { overlay.classList.add('opacity-100'); card.style.opacity = '1'; card.style.transform = 'translateY(0)'; }); } function close() { const overlay = el('overlay'); const card = el(); if (overlay && card) { overlay.classList.remove('opacity-100'); overlay.style.pointerEvents = 'none'; card.style.opacity = '0'; card.style.transform = 'translateY(1.5rem)'; state.closeTimer = setTimeout(() => overlay.classList.add('hidden'), 220); } state.ingredientId = null; state.productId = null; state.selectedProductId = null; state.onProductChange = null; state.onAfterChange = null; state.sourceNote = defaultSourceNote; } function bind() { if (bound) return; bound = true; el('close')?.addEventListener('click', close); el('back')?.addEventListener('click', () => { state.productId = null; render(); }); el('overlay')?.addEventListener('click', (event) => { if (event.target.id === `${idBase}-overlay`) close(); }); } function refresh() { if (state.ingredientId) render(); } return { bind, open, close, refresh, isOpen: () => Boolean(state.ingredientId), }; }