import { INGREDIENTS, CATEGORY_LABELS, pantryQtyStep, splitStockIntoPacks, } from '../data/catalog.js'; import { addIngredientToKitchenList, categoryLabel, loadPantry, setPantryQty } from '../services/pantryShopping.js'; import { showAppToast } from '../ui/toast.js'; function escapeHtml(s) { return String(s) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function pantryUnitLabel(u) { if (u === 'szt') return 'szt.'; return u; } function normalizeSearch(q) { return String(q).trim().toLowerCase(); } const PANTRY_SHOP_BOTTOM = '5.25rem'; const PANTRY_SHOP_OFF = `translateY(calc(100% + ${PANTRY_SHOP_BOTTOM}))`; /** @type {string | null} */ let shopPickerIngredientId = null; /** @type {number} */ let shopPickerStep = 1; /** Czy licznik w arkuszu to liczba opakowań (vs. jednostki magazynowe). */ let shopPickerUsesPacks = false; export function getPantryHTML() { return `
${escapeHtml(def.name)}
${packPill}${escapeHtml(categoryLabel(def.category))} · stan w ${unit}
${packStockCaption(def, qty)}Brak wyników — zmień wyszukiwanie lub filtr kategorii.
'; return; } const { have, catalogOnly } = splitHaveAndCatalog(ids, pantry); const haveBody = have.length ? `Żaden z widocznych produktów nie ma jeszcze zapasu — ustaw ilość w katalogu poniżej.
'; const catBody = catalogOnly.length ? `Wszystkie widoczne pozycje są na stanie.
'; const haveHint = have.length === 0 ? 'Brak zapasu w tym widoku' : have.length === 1 ? '1 produkt z zapasem' : `${have.length} produktów z zapasem`; const catHint = catalogOnly.length === 0 ? 'Nic do uzupełnienia w tym widoku' : catalogOnly.length === 1 ? '1 pozycja bez zapasu' : `${catalogOnly.length} pozycji bez zapasu`; root.innerHTML = pantryAccordionSection('have', { title: 'Na stanie', hint: haveHint, count: have.length, tone: 'emerald', open: pantryAccordionHaveOpen, searching, bodyInner: haveBody, }) + pantryAccordionSection('catalog', { title: 'Katalog — bez zapasu', hint: catHint, count: catalogOnly.length, tone: 'slate', open: pantryAccordionCatalogOpen, searching, bodyInner: catBody, }); root.querySelectorAll('.pantry-acc-toggle').forEach((btn) => { btn.addEventListener('click', () => { const key = btn.getAttribute('data-pantry-acc'); if (key === 'have') pantryAccordionHaveOpen = !pantryAccordionHaveOpen; else if (key === 'catalog') pantryAccordionCatalogOpen = !pantryAccordionCatalogOpen; renderPantryResults(); }); }); root.querySelectorAll('[data-ingredient-id]').forEach((card) => { const id = card.getAttribute('data-ingredient-id'); if (!id) return; const input = card.querySelector('[data-pantry-qty]'); const step = parseFloat(String(input?.getAttribute('data-pantry-step'))) || pantryQtyStep(id); const applyQty = (n) => { const v = Math.max(0, Math.round(Number(n) * 1000) / 1000 || 0); setPantryQty(id, v); if (input) { input.value = v > 0 ? String(v) : ''; } const prevVariant = card.getAttribute('data-pantry-variant'); const nowHave = v > 0; const expectVariant = nowHave ? 'have' : 'catalog'; if (prevVariant === 'have' || prevVariant === 'catalog') { if (prevVariant !== expectVariant) { const existing = pantrySectionPins[id]; const t = Date.now(); const extending = Boolean( existing && existing.until > t && existing.section === prevVariant, ); pinPantrySection(id, prevVariant); if (!extending) { renderPantryResults(); } } } }; card.querySelector('.pantry-qty-minus')?.addEventListener('click', () => { const cur = parseFloat(String(input?.value).replace(',', '.')) || 0; applyQty(Math.max(0, cur - step)); }); card.querySelector('.pantry-qty-plus')?.addEventListener('click', () => { const cur = parseFloat(String(input?.value).replace(',', '.')) || 0; applyQty(cur + step); }); input?.addEventListener('change', () => { const raw = String(input.value).replace(',', '.').trim(); const v = raw === '' ? 0 : parseFloat(raw); applyQty(Number.isFinite(v) ? v : 0); }); card.querySelector('.pantry-add-shop')?.addEventListener('click', () => { openPantryShopPicker(id); }); card.querySelector('.pantry-nutrition-toggle')?.addEventListener('click', (ev) => { ev.preventDefault(); const btn = /** @type {HTMLButtonElement} */ (ev.currentTarget); const panel = card.querySelector('.pantry-nutrition-panel'); const chevron = card.querySelector('.pantry-nutrition-chevron'); if (!panel) return; const willOpen = panel.classList.contains('hidden'); panel.classList.toggle('hidden', !willOpen); btn.setAttribute('aria-expanded', String(willOpen)); chevron?.classList.toggle('rotate-180', willOpen); }); }); } function readShopPickerQty() { const el = document.getElementById('pantry-shop-qty'); const raw = parseFloat(String(el?.value).replace(',', '.')) || 0; return Math.max(1, Math.round(raw)); } function setShopPickerQtyDisplay(v) { const el = document.getElementById('pantry-shop-qty'); if (el) el.value = String(Math.max(1, Math.round(Number(v)))); } function openPantryShopPicker(ingredientId) { const def = INGREDIENTS[ingredientId]; if (!def) return; shopPickerIngredientId = ingredientId; const unit = pantryUnitLabel(def.pantryUnit); const pack = def.purchasePack; shopPickerUsesPacks = Boolean(pack && pack.amount > 0); const heading = document.getElementById('pantry-shop-heading'); const sub = document.getElementById('pantry-shop-sub'); if (shopPickerUsesPacks) { shopPickerStep = 1; if (heading) heading.textContent = `Ile opakowań: ${def.name}?`; if (sub) { const lab = pack.label || `${pack.amount} ${unit}`; sub.textContent = `Jedno = ${lab}. Na listę trafi suma w ${unit} (${lab}).`; } setShopPickerQtyDisplay(1); } else { shopPickerStep = pantryQtyStep(ingredientId); if (heading) heading.textContent = `Ile dodać: ${def.name}?`; if (sub) { sub.textContent = `Jednostka na liście: ${unit}. Przyciski +/−: ${shopPickerStep} ${unit}.`; } setShopPickerQtyDisplay(shopPickerStep); } const backdrop = document.getElementById('pantry-shop-backdrop'); const sheet = document.getElementById('pantry-shop-sheet'); if (!backdrop || !sheet) return; sheet.classList.remove('hidden'); backdrop.classList.remove('hidden'); requestAnimationFrame(() => { backdrop.classList.remove('opacity-0'); sheet.style.transform = 'translateY(0)'; }); } function closePantryShopPicker() { shopPickerIngredientId = null; shopPickerUsesPacks = false; const backdrop = document.getElementById('pantry-shop-backdrop'); const sheet = document.getElementById('pantry-shop-sheet'); if (sheet) { sheet.style.transform = PANTRY_SHOP_OFF; } if (backdrop) { backdrop.classList.add('opacity-0'); } setTimeout(() => { backdrop?.classList.add('hidden'); sheet?.classList.add('hidden'); }, 300); } function bindPantryShopSheet() { document.getElementById('pantry-shop-backdrop')?.addEventListener('click', closePantryShopPicker); document.getElementById('pantry-shop-cancel')?.addEventListener('click', closePantryShopPicker); document.getElementById('pantry-shop-minus')?.addEventListener('click', () => { const cur = readShopPickerQty(); const dec = shopPickerUsesPacks ? 1 : shopPickerStep; setShopPickerQtyDisplay(Math.max(1, cur - dec)); }); document.getElementById('pantry-shop-plus')?.addEventListener('click', () => { const cur = readShopPickerQty(); const inc = shopPickerUsesPacks ? 1 : shopPickerStep; setShopPickerQtyDisplay(cur + inc); }); document.getElementById('pantry-shop-qty')?.addEventListener('change', () => { setShopPickerQtyDisplay(readShopPickerQty()); }); document.getElementById('pantry-shop-add')?.addEventListener('click', () => { if (!shopPickerIngredientId) return; const def = INGREDIENTS[shopPickerIngredientId]; if (!def) return; const count = readShopPickerQty(); const unit = pantryUnitLabel(def.pantryUnit); if (shopPickerUsesPacks && def.purchasePack) { const packAmt = def.purchasePack.amount; const total = count * packAmt; const note = `${count}× ${def.purchasePack.label || `${packAmt} ${unit}`}`; addIngredientToKitchenList(shopPickerIngredientId, total, note); showAppToast(`Dodano ${count} op. (${total} ${unit}) na listę kuchni.`); } else { addIngredientToKitchenList(shopPickerIngredientId, count); showAppToast(`Dodano ${count} ${unit} na listę kuchni.`); } closePantryShopPicker(); window.refreshShopping?.(); }); } export function refreshPantry() { renderCategoryChips(); renderPantryResults(); } export function setupPantry() { renderCategoryChips(); renderPantryResults(); bindPantryShopSheet(); document.getElementById('pantry-search')?.addEventListener('input', () => { renderPantryResults(); }); window.refreshPantry = refreshPantry; }