import { RECIPES, INGREDIENTS } from '../data/catalog.js'; import { MEAL_SLOTS } from '../planner/mealSlots.js'; import { addDays, startOfDay } from '../services/dateUtils.js'; import { addOrMergeShoppingLines, loadPantry } from '../services/pantryShopping.js'; import { dateKey, loadPlans, newPlanEntryId, savePlans } from '../services/planStore.js'; import { showAppToast } from '../ui/toast.js'; function escapeHtml(s) { return String(s) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } const slotLabelMap = Object.fromEntries(MEAL_SLOTS.map((s) => [s.id, s.label])); export function getRecipeDetailHTML() { return `

1
`; } let currentRecipeId = null; let currentServings = 1; function populateDetail(recipeId) { const recipe = RECIPES[recipeId]; if (!recipe) return; currentRecipeId = recipeId; currentServings = 1; document.getElementById('rd-hero-label').textContent = `Zdjęcie: ${recipe.title}`; document.getElementById('rd-title').textContent = recipe.title; document.getElementById('rd-time').textContent = `${recipe.minutes} min`; updateKcalDisplay(); const tagsHtml = []; for (const slotId of recipe.allowedSlots) { const label = slotLabelMap[slotId]; if (label) tagsHtml.push(`${escapeHtml(label)}`); } for (const tag of (recipe.tags || [])) { tagsHtml.push(`${escapeHtml(tag)}`); } document.getElementById('rd-tags').innerHTML = tagsHtml.join(''); document.getElementById('rd-servings').textContent = '1'; renderIngredients(recipe); renderSteps(recipe); renderNutrition(recipe); const tabBtns = document.querySelectorAll('.rd-tab-btn'); const tabs = document.querySelectorAll('.rd-tab-content'); tabBtns.forEach((b) => { b.classList.remove('text-gray-900', 'border-gray-900', 'font-semibold'); b.classList.add('text-gray-500', 'border-transparent', 'font-medium'); }); tabBtns[0]?.classList.remove('text-gray-500', 'border-transparent', 'font-medium'); tabBtns[0]?.classList.add('text-gray-900', 'border-gray-900', 'font-semibold'); tabs.forEach((t) => { t.classList.add('hidden'); t.classList.remove('block'); }); document.getElementById('rd-tab-ingredients')?.classList.remove('hidden'); document.getElementById('rd-tab-ingredients')?.classList.add('block'); } function updateKcalDisplay() { const recipe = RECIPES[currentRecipeId]; if (!recipe) return; const kcal = Math.round(recipe.nutritionPerServing.kcal * currentServings); document.getElementById('rd-kcal').textContent = `${kcal} kcal`; } function renderIngredients(recipe) { const container = document.getElementById('rd-tab-ingredients'); if (!container) return; const pantry = loadPantry(); const rows = recipe.ingredients.map((ing) => { const def = INGREDIENTS[ing.ingredientId]; const name = def?.name || ing.ingredientId; const scaledAmount = ing.amount * currentServings; const displayAmount = Number.isInteger(scaledAmount) ? scaledAmount : parseFloat(scaledAmount.toFixed(1)); const pantryQty = Number(pantry[ing.ingredientId]) || 0; let stockBadge = ''; if (def) { const u = def.pantryUnit === 'szt' ? 'szt.' : def.pantryUnit; if (pantryQty >= scaledAmount) { stockBadge = `Masz`; } else if (pantryQty > 0) { const miss = parseFloat((scaledAmount - pantryQty).toFixed(1)); stockBadge = `Brak ${miss} ${u}`; } else { stockBadge = `Brak`; } } return `
  • ${escapeHtml(name)} ${stockBadge} ${displayAmount} ${escapeHtml(ing.unit)}
  • `; }).join(''); container.innerHTML = `
    Zaznacz składniki do kupienia
    `; container.querySelectorAll('.rd-ingredient-row').forEach((row) => { row.addEventListener('click', () => row.classList.toggle('ingredient-active')); }); document.getElementById('rd-add-to-shopping')?.addEventListener('click', () => { const recipe = RECIPES[currentRecipeId]; if (!recipe) return; const checkedRows = container.querySelectorAll('.rd-ingredient-row.ingredient-active'); if (checkedRows.length === 0) { showAppToast('Zaznacz składniki, które chcesz dodać.'); return; } const lines = []; checkedRows.forEach((row) => { const ingredientId = row.dataset.ingredientId; const baseAmount = parseFloat(row.dataset.baseAmount); const unit = row.dataset.unit; const def = INGREDIENTS[ingredientId]; lines.push({ ingredientId, amount: Math.round(baseAmount * currentServings * 100) / 100, unit, name: def?.name || ingredientId, category: def?.category || 'inne', sourceNote: `Przepis: ${recipe.title}`, }); }); addOrMergeShoppingLines(lines); showAppToast(`Dodano ${lines.length} składnik(ów) na listę zakupów.`); window.refreshShopping?.(); checkedRows.forEach((row) => row.classList.remove('ingredient-active')); }); } function renderSteps(recipe) { const container = document.getElementById('rd-tab-steps'); if (!container) return; const steps = recipe.steps || []; if (steps.length === 0) { container.innerHTML = '

    Brak kroków przygotowania.

    '; return; } container.innerHTML = `
    ${steps.map((step, i) => `
    ${i + 1}

    ${escapeHtml(step)}

    `).join('')}
    `; } function renderNutrition(recipe) { const container = document.getElementById('rd-tab-nutrition'); if (!container) return; const n = recipe.nutritionPerServing; const s = currentServings; container.innerHTML = `

    ${s > 1 ? `Wartości dla ${s} porcji` : 'Wartości na 1 porcję'}

    `; } export function setupRecipeDetail() { document.querySelectorAll('.rd-tab-btn').forEach((btn) => { btn.addEventListener('click', () => { const tabId = btn.dataset.rdTab; document.querySelectorAll('.rd-tab-content').forEach((el) => { el.classList.add('hidden'); el.classList.remove('block'); }); const target = document.getElementById(`rd-tab-${tabId}`); if (target) { target.classList.remove('hidden'); target.classList.add('block'); target.parentElement.scrollTop = 0; } document.querySelectorAll('.rd-tab-btn').forEach((b) => { b.classList.remove('text-gray-900', 'border-gray-900', 'font-semibold'); b.classList.add('text-gray-500', 'border-transparent', 'font-medium'); }); btn.classList.remove('text-gray-500', 'border-transparent', 'font-medium'); btn.classList.add('text-gray-900', 'border-gray-900', 'font-semibold'); }); }); document.getElementById('rd-serv-minus')?.addEventListener('click', () => { if (currentServings <= 1) return; currentServings--; document.getElementById('rd-servings').textContent = currentServings; const recipe = RECIPES[currentRecipeId]; if (recipe) { renderIngredients(recipe); renderNutrition(recipe); updateKcalDisplay(); } }); document.getElementById('rd-serv-plus')?.addEventListener('click', () => { if (currentServings >= 12) return; currentServings++; document.getElementById('rd-servings').textContent = currentServings; const recipe = RECIPES[currentRecipeId]; if (recipe) { renderIngredients(recipe); renderNutrition(recipe); updateKcalDisplay(); } }); const WEEKDAYS_LONG = ['Niedziela', 'Poniedziałek', 'Wtorek', 'Środa', 'Czwartek', 'Piątek', 'Sobota']; const MONTHS_SHORT = ['sty', 'lut', 'mar', 'kwi', 'maj', 'cze', 'lip', 'sie', 'wrz', 'paź', 'lis', 'gru']; let plannerPickerDay = null; let plannerPickerSlot = null; const plannerOverlay = document.getElementById('rd-planner-picker'); const plannerSheet = document.getElementById('rd-planner-sheet'); function openPlannerPicker() { const recipe = RECIPES[currentRecipeId]; if (!recipe) return; document.getElementById('rd-planner-recipe-name').textContent = recipe.title; const daysContainer = document.getElementById('rd-planner-days'); const today = startOfDay(new Date()); const days = []; for (let i = 0; i < 7; i++) days.push(addDays(today, i)); plannerPickerDay = today; plannerPickerSlot = recipe.allowedSlots[0] || MEAL_SLOTS[0]?.id; daysContainer.innerHTML = days.map((d, idx) => { const wd = WEEKDAYS_LONG[d.getDay()]; const label = idx === 0 ? `Dziś — ${wd}, ${d.getDate()} ${MONTHS_SHORT[d.getMonth()]}` : `${wd}, ${d.getDate()} ${MONTHS_SHORT[d.getMonth()]}`; const sel = idx === 0; return ``; }).join(''); const slotsContainer = document.getElementById('rd-planner-slots'); slotsContainer.innerHTML = MEAL_SLOTS.filter((s) => recipe.allowedSlots.includes(s.id)).map((s) => { const sel = s.id === plannerPickerSlot; return ``; }).join(''); plannerOverlay.classList.remove('hidden'); plannerOverlay.style.pointerEvents = 'auto'; requestAnimationFrame(() => { plannerSheet.style.transform = 'translateY(0)'; }); } function closePlannerPicker() { plannerSheet.style.transform = 'translateY(100%)'; setTimeout(() => { plannerOverlay.classList.add('hidden'); plannerOverlay.style.pointerEvents = 'none'; }, 300); } document.getElementById('rd-add-to-planner-btn')?.addEventListener('click', openPlannerPicker); plannerOverlay?.addEventListener('click', (e) => { if (e.target === plannerOverlay) closePlannerPicker(); }); document.getElementById('rd-planner-days')?.addEventListener('click', (e) => { const btn = e.target.closest('.rd-plan-day-btn'); if (!btn) return; plannerPickerDay = new Date(Number(btn.getAttribute('data-day-ts'))); document.querySelectorAll('.rd-plan-day-btn').forEach((b) => { b.classList.remove('border-gray-900', 'bg-gray-900', 'text-white'); b.classList.add('border-gray-200', 'bg-gray-50', 'text-gray-900'); }); btn.classList.remove('border-gray-200', 'bg-gray-50', 'text-gray-900'); btn.classList.add('border-gray-900', 'bg-gray-900', 'text-white'); }); document.getElementById('rd-planner-slots')?.addEventListener('click', (e) => { const btn = e.target.closest('.rd-plan-slot-btn'); if (!btn) return; plannerPickerSlot = btn.getAttribute('data-slot-id'); document.querySelectorAll('.rd-plan-slot-btn').forEach((b) => { b.classList.remove('border-gray-900', 'bg-gray-900', 'text-white'); b.classList.add('border-gray-200', 'bg-gray-50', 'text-gray-700'); }); btn.classList.remove('border-gray-200', 'bg-gray-50', 'text-gray-700'); btn.classList.add('border-gray-900', 'bg-gray-900', 'text-white'); }); document.getElementById('rd-planner-confirm')?.addEventListener('click', () => { if (!currentRecipeId || !plannerPickerDay || !plannerPickerSlot) return; const plans = loadPlans(); const key = dateKey(plannerPickerDay); if (!plans[key]) plans[key] = {}; if (!plans[key][plannerPickerSlot]) plans[key][plannerPickerSlot] = []; plans[key][plannerPickerSlot].push({ id: newPlanEntryId(), recipeId: currentRecipeId, servings: currentServings, }); savePlans(plans); closePlannerPicker(); showAppToast('Dodano do planera!'); window.refreshPlanner?.(); }); window.openRecipeDetail = (recipeId) => { if (!recipeId || !RECIPES[recipeId]) return; populateDetail(recipeId); const view = document.getElementById('recipe-detail-view'); view.classList.remove('translate-x-full', 'opacity-0', 'pointer-events-none'); view.classList.add('translate-x-0', 'opacity-100', 'pointer-events-auto'); }; window.closeRecipeDetail = () => { closePlannerPicker(); const view = document.getElementById('recipe-detail-view'); view.classList.remove('translate-x-0', 'opacity-100', 'pointer-events-auto'); view.classList.add('translate-x-full', 'opacity-0', 'pointer-events-none'); }; }