From 8f1a2b785f2f656bc38d02b95da277e959e37b26 Mon Sep 17 00:00:00 2001 From: dadaloop82 Date: Sun, 15 Mar 2026 18:15:09 +0000 Subject: [PATCH] Scadenza: freezer estende durata, sotto vuoto formaggi potenziato, ricalcolo al cambio posizione --- assets/js/app.js | 121 ++++++++++++++++++++++++++++++----------------- data/dispensa.db | Bin 167936 -> 172032 bytes index.html | 4 +- 3 files changed, 80 insertions(+), 45 deletions(-) diff --git a/assets/js/app.js b/assets/js/app.js index ae4513c..cf0072b 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -260,41 +260,59 @@ const EXPIRY_DAYS = { }; // More specific expiry by product name keywords -function estimateExpiryDays(product) { +function estimateExpiryDays(product, location) { const name = (product.name || '').toLowerCase(); const cat = (product.category || '').toLowerCase(); + const loc = (location || '').toLowerCase(); + + let days; // Specific product overrides - if (/latte\s+(fresco|intero|parzial|scremato)/.test(name)) return 7; - if (/latte\s+uht|latte\s+a\s+lunga/.test(name)) return 90; - if (/yogurt/.test(name)) return 21; - if (/mozzarella|burrata|stracciatella/.test(name)) return 5; - if (/formaggio\s+(fresco|ricotta|mascarpone|stracchino|crescenza)/.test(name)) return 10; - if (/parmigiano|grana|pecorino|provolone/.test(name)) return 60; - if (/prosciutto\s+cotto|mortadella|wurstel/.test(name)) return 7; - if (/prosciutto\s+crudo|salame|bresaola|speck/.test(name)) return 30; - if (/uova/.test(name)) return 28; - if (/pane\s+fresco|pane\s+in\s+cassetta/.test(name)) return 5; - if (/pane\s+confezionato|pan\s+carr|pancarrè/.test(name)) return 14; - if (/insalata|rucola|spinaci\s+freschi/.test(name)) return 5; - if (/pollo|tacchino|maiale|manzo|vitello/.test(name)) return 3; - if (/salmone|tonno\s+fresco|pesce/.test(name) && !/tonno\s+in\s+scatola|tonno\s+rio/.test(name)) return 2; - if (/tonno\s+in\s+scatola|tonno\s+rio|sgombro\s+in/.test(name)) return 1095; - if (/surgelat|frozen|findus|4\s*salti/.test(name)) return 180; - if (/gelato/.test(name)) return 365; - if (/succo|spremuta/.test(name)) return 7; - if (/birra|vino/.test(name)) return 365; - if (/acqua/.test(name)) return 365; - if (/biscott|cracker|grissini|fette\s+biscott/.test(name)) return 180; - if (/nutella|marmellata|miele/.test(name)) return 365; - if (/passata|pelati|pomodor/.test(name)) return 730; - if (/olio|aceto/.test(name)) return 548; - - // Fallback to category - for (const [key, days] of Object.entries(EXPIRY_DAYS)) { - if (cat.includes(key)) return days; + if (/latte\s+(fresco|intero|parzial|scremato)/.test(name)) days = 7; + else if (/latte\s+uht|latte\s+a\s+lunga/.test(name)) days = 90; + else if (/yogurt/.test(name)) days = 21; + else if (/mozzarella|burrata|stracciatella/.test(name)) days = 5; + else if (/formaggio\s+(fresco|ricotta|mascarpone|stracchino|crescenza)/.test(name)) days = 10; + else if (/parmigiano|grana|pecorino|provolone/.test(name)) days = 60; + else if (/prosciutto\s+cotto|mortadella|wurstel/.test(name)) days = 7; + else if (/prosciutto\s+crudo|salame|bresaola|speck/.test(name)) days = 30; + else if (/uova/.test(name)) days = 28; + else if (/pane\s+fresco|pane\s+in\s+cassetta/.test(name)) days = 5; + else if (/pane\s+confezionato|pan\s+carr|pancarrè/.test(name)) days = 14; + else if (/insalata|rucola|spinaci\s+freschi/.test(name)) days = 5; + else if (/pollo|tacchino|maiale|manzo|vitello|sovracosci|cosci/.test(name)) days = 3; + else if (/salmone|tonno\s+fresco|pesce/.test(name) && !/tonno\s+in\s+scatola|tonno\s+rio/.test(name)) days = 2; + else if (/tonno\s+in\s+scatola|tonno\s+rio|sgombro\s+in/.test(name)) days = 1095; + else if (/surgelat|frozen|findus|4\s*salti/.test(name)) days = 180; + else if (/gelato/.test(name)) days = 365; + else if (/succo|spremuta/.test(name)) days = 7; + else if (/birra|vino/.test(name)) days = 365; + else if (/acqua/.test(name)) days = 365; + else if (/biscott|cracker|grissini|fette\s+biscott/.test(name)) days = 180; + else if (/nutella|marmellata|miele/.test(name)) days = 365; + else if (/passata|pelati|pomodor/.test(name)) days = 730; + else if (/olio|aceto/.test(name)) days = 548; + else { + // Fallback to category + days = 180; // generic default + for (const [key, d] of Object.entries(EXPIRY_DAYS)) { + if (cat.includes(key)) { days = d; break; } + } } - return 180; // generic default + + // Freezer extends shelf life significantly + if (loc === 'freezer' && days < 180) { + // Fresh meat/fish: 3-6 months in freezer + if (days <= 4) days = 120; + // Short-lived (cheese, dairy, bread): 2-3 months + else if (days <= 14) days = 75; + // Medium (yogurt, cured meats): 3-4 months + else if (days <= 30) days = 120; + // Already long-lasting: at least 6 months + else days = Math.max(days, 180); + } + + return days; } function formatEstimatedExpiry(days) { @@ -2887,10 +2905,12 @@ function showAddForm() { // Show the purchase-type selector const expirySection = document.getElementById('add-expiry-section'); - const estimatedDays = estimateExpiryDays(currentProduct); + const estimatedDays = estimateExpiryDays(currentProduct, autoLoc); const estimatedDate = addDays(estimatedDays); const estimateLabel = formatEstimatedExpiry(estimatedDays); + let expirySuffix = autoLoc === 'freezer' ? ' (freezer)' : ''; + // Reset vacuum sealed toggle const vacuumCb = document.getElementById('add-vacuum-sealed'); if (vacuumCb) { @@ -2912,7 +2932,7 @@ function showAddForm() {
- Scadenza stimata: ${estimateLabel} + Scadenza stimata: ${estimateLabel}${expirySuffix} ${formatDate(estimatedDate)}
@@ -2933,30 +2953,44 @@ function toggleVacuumSealed() { } function onVacuumSealedChange() { - const isVacuum = document.getElementById('add-vacuum-sealed')?.checked; const hint = document.getElementById('add-vacuum-hint'); - if (hint) hint.style.display = isVacuum ? 'block' : 'none'; + if (hint) hint.style.display = document.getElementById('add-vacuum-sealed')?.checked ? 'block' : 'none'; + recalculateAddExpiry(); +} + +function recalculateAddExpiry() { + if (!currentProduct) return; + const loc = document.getElementById('add-location')?.value || ''; + const isVacuum = document.getElementById('add-vacuum-sealed')?.checked; + + let days = estimateExpiryDays(currentProduct, loc); + if (isVacuum) days = getVacuumExpiryDays(days); + + window._addBaseExpiryDays = estimateExpiryDays(currentProduct, loc); - // Recalculate expiry based on vacuum sealed - const baseDays = window._addBaseExpiryDays || 180; - const days = isVacuum ? getVacuumExpiryDays(baseDays) : baseDays; const newDate = addDays(days); const newLabel = formatEstimatedExpiry(days); + let suffix = ''; + if (loc === 'freezer' && isVacuum) suffix = ' (freezer + sotto vuoto)'; + else if (loc === 'freezer') suffix = ' (freezer)'; + else if (isVacuum) suffix = ' (sotto vuoto)'; + const expiryInput = document.getElementById('add-expiry'); const estimateEl = document.querySelector('.expiry-estimate-label'); const dateEl = document.querySelector('.expiry-estimate-date'); if (expiryInput) expiryInput.value = newDate; - if (estimateEl) estimateEl.innerHTML = `Scadenza stimata: ${newLabel}${isVacuum ? ' (sotto vuoto)' : ''}`; + if (estimateEl) estimateEl.innerHTML = `Scadenza stimata: ${newLabel}${suffix}`; if (dateEl) dateEl.textContent = formatDate(newDate); } function getVacuumExpiryDays(baseDays) { - // Vacuum sealing roughly triples fresh food shelf life, less effect on long-lasting items - if (baseDays <= 7) return Math.round(baseDays * 3); // fresh: 3x (e.g., 3→9, 7→21) - if (baseDays <= 30) return Math.round(baseDays * 2.5); // short: 2.5x (e.g., 14→35) - if (baseDays <= 90) return Math.round(baseDays * 2); // medium: 2x - return Math.round(baseDays * 1.5); // long-lasting: 1.5x + // Vacuum sealing extends shelf life significantly + if (baseDays <= 7) return Math.round(baseDays * 3); // very fresh: 3x (e.g., 3→9, 7→21) + if (baseDays <= 14) return Math.round(baseDays * 3); // fresh cheese/dairy: 3x (10→30) + if (baseDays <= 30) return Math.round(baseDays * 2.5); // short: 2.5x (e.g., 21→52) + if (baseDays <= 90) return Math.round(baseDays * 2.5); // medium (cheese ~60d): 2.5x (60→150) + return Math.round(baseDays * 1.5); // long-lasting: 1.5x } function onAddUnitChange() { @@ -3103,6 +3137,7 @@ function selectLocation(btn, loc) { btn.parentElement.querySelectorAll('.loc-btn').forEach(b => b.classList.remove('active')); btn.classList.add('active'); document.getElementById('add-location').value = loc; + recalculateAddExpiry(); } async function submitAdd(e) { diff --git a/data/dispensa.db b/data/dispensa.db index 89e6bc1eac90a5abdae76d4325591c542f10b03b..e4211e247d0ba088b6cd1206f56d458d7a8bf09d 100644 GIT binary patch delta 1556 zcmY*ZO>7%Q6yBM{ahxAEBq^zYG~+Ezn&2e6v7I`G;3OARDTtH?Bt)e$UQeA-*E`Pc zI--rLG$14-4q&Wmj+6>oR25YaDsw_WgTw&|5EW;{B^-Ky3$0YO&uH(a}LI)H@87q?vI`HM2W(IY=vz@7KXV5|qx+%j;Xc*lrmoIdleydv< znH?JHR@>#zOXzvoaSRQGQ)xp_Pw7?t7`ipl8&Y=wOBqw|ssE|}s<+jht;gqXsrZ?Q zy!`>%-_xdUDscOQ`iFW!y{2w%MSBWre_v~KADYsqrpNX8xRErOO*`dsa2~W0$@5zpT&`fAD{7u+{{GGP0h0U&r zf(LLk9*@YjyJ)JW+K5Z<4tlRcL=?0e{OKVw+IL%0s+qg!vrr#I2N9IEZ{)aJWVTDO zymKFo`XENyNLEK4Ac~nBb zPCIxg63`iOMX8=}@TY@cU3{f=OYhmjxcz>4exSd6vNNni_gz|#Hyo-=UC|C&%=Wlx zu5d;e0b%B8VhWp_5&4qik-Wo9Q8{~Mb~s52+}2{6NAs?henWGqE#SDuEMYSEuvk9N z968&9pFBuCu?xj*;+iza?6VZ$n?NgbpFiDmJfMS|Wrx}(7xMaHlxZ;%Dfu9chowG( z`sLp#^iuCpi{wi#pn^1y=D00nF^vaOiE$&Lor|q&HZ3qMtu5A@0Y$6c8MsR6Bwst6 zv`d97bF_3yul#m3iW5hqF^flQG-4LdhT=&`maDD!&@e2~%(!7RgTG$0zW~4=45H=%+-I8gF(YjQFm~gSeDHoOR zuMJiHyxJ?@kKj-Czie^e>smvPW=+ai2VSc@`^Dgf#YodI!BuLmmMF;z%fE)iIT3f8Dhiw z<@g$Cro?oFX;M(%kP%OlFY%trMsXrdj@qPT12PvLpv3Am zK~qf|8Z4Xqu^W?(Mtw3(USp2ylXJ`G$ngRQ6(D$TyWJA_-K4AjtQztd$%3~H)M;pm zIcwZ+X@tYCAsCd$S&`@HgeK=RxSzf1`{}=d+Dj9@+3;`!>Y^h&#%<;snFSO^;3f+l za+6Px#rm-Fd0w*f{wfqjkd}8~w6Fkv6F$4NGAKD8lssYuEkc36JiA1|V8R5sn9$BO NekjBUerAay{{s*5?Un!l delta 378 zcmZoTz}2vTYl1YZECU0B=0pX1M%j%C$@Yv~%}4CFAF*e25@0+yojrh2jq%{biIcf= zD|i{yZRO>8`I)Al3t+TiV$_+=704*hZf<2{U}bEv-5`+hik<)q{~Mrj3@ZG;`M>dh zDispensa Manager - + @@ -894,6 +894,6 @@
- +