import { INGREDIENTS, CATEGORY_LABELS } 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; export function getPantryHTML() { return ` `; } let pantryFilterCategory = ''; /** Zwijanie sekcji (ignorowane przy aktywnym wyszukiwaniu — widać wszystkie trafienia). */ let pantryAccordionHaveOpen = true; let pantryAccordionCatalogOpen = false; function allCategoryKeys() { const s = new Set(); Object.values(INGREDIENTS).forEach((d) => s.add(d.category)); return [...s].sort((a, b) => categoryLabel(a).localeCompare(categoryLabel(b))); } function renderCategoryChips() { const wrap = document.getElementById('pantry-category-filters'); if (!wrap) return; const keys = allCategoryKeys(); const chips = [ { id: '', label: 'Wszystkie' }, ...keys.map((k) => ({ id: k, label: categoryLabel(k) })), ]; wrap.innerHTML = chips.map((c) => { const active = c.id === pantryFilterCategory; const cls = active ? 'shrink-0 px-3 py-1.5 rounded-full text-[11px] font-semibold bg-gray-900 text-white' : 'shrink-0 px-3 py-1.5 rounded-full text-[11px] font-semibold bg-gray-100 text-gray-600 hover:bg-gray-200'; return ``; }).join(''); wrap.querySelectorAll('.pantry-cat-btn').forEach((btn) => { btn.addEventListener('click', () => { pantryFilterCategory = btn.getAttribute('data-pantry-cat') || ''; renderCategoryChips(); renderPantryResults(); }); }); } function filterIds(searchRaw) { const q = normalizeSearch(searchRaw); return Object.keys(INGREDIENTS) .filter((id) => { const d = INGREDIENTS[id]; if (pantryFilterCategory && d.category !== pantryFilterCategory) return false; if (!q) return true; const name = d.name.toLowerCase(); const cat = (CATEGORY_LABELS[d.category] || '').toLowerCase(); return name.includes(q) || cat.includes(q); }) .sort((a, b) => INGREDIENTS[a].name.localeCompare(INGREDIENTS[b].name, 'pl')); } /** Krok +/-: tylko liczby całkowite (szt. ±1, g/ml ±10). */ function qtyStepForIngredient(id) { const u = INGREDIENTS[id]?.pantryUnit; return u === 'szt' ? 1 : 10; } function splitHaveAndCatalog(ids, pantry) { const have = ids.filter((id) => (Number(pantry[id]) || 0) > 0); const catalogOnly = ids.filter((id) => !pantry[id] || Number(pantry[id]) <= 0); return { have, catalogOnly }; } /** * @param {'have' | 'catalog'} sectionKey * @param {{ title: string, hint: string, count: number, tone: 'emerald' | 'slate', open: boolean, searching: boolean, bodyInner: string }} opts */ function pantryAccordionSection(sectionKey, opts) { const { title, hint, count, tone, open, searching, bodyInner } = opts; const showToggle = !searching && count > 0; const isOpen = searching || open || count === 0; const ring = tone === 'emerald' ? 'ring-emerald-100/90' : 'ring-gray-200/90'; const dot = tone === 'emerald' ? 'bg-emerald-500 shadow-[0_0_0_3px_rgba(16,185,129,0.2)]' : 'bg-slate-400 shadow-[0_0_0_3px_rgba(148,163,184,0.25)]'; const chevronRot = isOpen ? '' : '-rotate-90'; const rowCls = 'w-full flex items-center gap-3 px-3.5 py-3 text-left min-h-[3.25rem]' + (showToggle ? ' hover:bg-gray-50/80 transition-colors pantry-acc-toggle cursor-pointer' : ''); const chevron = showToggle ? `` : ''; const headerInner = ` ${escapeHtml(title)} ${count} ${escapeHtml(hint)} ${chevron}`; const header = showToggle ? `` : `
${headerInner}
`; return `
${header}
${bodyInner}
`; } function pantryCardHtml(id, pantry, variant) { const def = INGREDIENTS[id]; const unit = pantryUnitLabel(def.pantryUnit); const qty = Number(pantry[id]) || 0; const val = qty > 0 ? String(Math.round(qty)) : ''; const step = qtyStepForIngredient(id); const shell = variant === 'have' ? 'rounded-xl border border-emerald-200 bg-gradient-to-br from-emerald-50/80 to-white p-3 shadow-sm ring-1 ring-emerald-100/80' : 'rounded-xl border border-dashed border-gray-200 bg-gray-50/90 p-3 shadow-sm'; return `

${escapeHtml(def.name)}

${escapeHtml(categoryLabel(def.category))} · magazyn: ${unit}

`; } function renderPantryResults() { const root = document.getElementById('pantry-results'); if (!root) return; const searchEl = document.getElementById('pantry-search'); const q = searchEl?.value || ''; const searching = normalizeSearch(q) !== ''; const pantry = loadPantry(); const ids = filterIds(q); if (ids.length === 0) { root.innerHTML = '

Brak wyników — zmień wyszukiwanie lub filtr kategorii.

'; return; } const { have, catalogOnly } = splitHaveAndCatalog(ids, pantry); const haveBody = have.length ? `
${have.map((id) => pantryCardHtml(id, pantry, 'have')).join('')}
` : '

Żaden z widocznych produktów nie ma jeszcze zapasu — ustaw ilość w katalogu poniżej.

'; const catBody = catalogOnly.length ? `
${catalogOnly.map((id) => pantryCardHtml(id, pantry, 'catalog')).join('')}
` : '

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 = parseInt(String(input?.getAttribute('data-pantry-step')), 10) || qtyStepForIngredient(id); const applyQty = (n) => { const v = Math.max(0, Math.round(Number(n)) || 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 !== expectVariant) { renderPantryResults(); } }; card.querySelector('.pantry-qty-minus')?.addEventListener('click', () => { const cur = Math.round(parseFloat(String(input?.value).replace(',', '.')) || 0); applyQty(Math.max(0, cur - step)); }); card.querySelector('.pantry-qty-plus')?.addEventListener('click', () => { const cur = Math.round(parseFloat(String(input?.value).replace(',', '.')) || 0); applyQty(cur + step); }); input?.addEventListener('change', () => { const raw = String(input.value).replace(',', '.').trim(); const v = raw === '' ? 0 : Math.round(parseFloat(raw)); applyQty(Number.isFinite(v) ? v : 0); }); card.querySelector('.pantry-add-shop')?.addEventListener('click', () => { openPantryShopPicker(id); }); }); } function readShopPickerQty() { const el = document.getElementById('pantry-shop-qty'); const n = Math.round(parseFloat(String(el?.value).replace(',', '.')) || 0); return Math.max(1, n); } function setShopPickerQtyDisplay(v) { const el = document.getElementById('pantry-shop-qty'); if (el) el.value = String(Math.max(1, Math.round(v))); } function openPantryShopPicker(ingredientId) { const def = INGREDIENTS[ingredientId]; if (!def) return; shopPickerIngredientId = ingredientId; shopPickerStep = qtyStepForIngredient(ingredientId); const unit = pantryUnitLabel(def.pantryUnit); const heading = document.getElementById('pantry-shop-heading'); const sub = document.getElementById('pantry-shop-sub'); 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; 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(); setShopPickerQtyDisplay(Math.max(1, cur - shopPickerStep)); }); document.getElementById('pantry-shop-plus')?.addEventListener('click', () => { const cur = readShopPickerQty(); setShopPickerQtyDisplay(cur + shopPickerStep); }); document.getElementById('pantry-shop-qty')?.addEventListener('change', () => { setShopPickerQtyDisplay(readShopPickerQty()); }); document.getElementById('pantry-shop-add')?.addEventListener('click', () => { if (!shopPickerIngredientId) return; const qty = readShopPickerQty(); addIngredientToKitchenList(shopPickerIngredientId, qty); showAppToast(`Dodano ${qty} 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; }