From 4e576559a9ac4e83cae2ef263e79cf9ba1366686 Mon Sep 17 00:00:00 2001 From: dadaloop82 Date: Tue, 7 Apr 2026 12:17:18 +0000 Subject: [PATCH] feat: barcode scan button + reminder in manual product form MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 📷 scan button next to the barcode field in product form Opens a camera modal (BarcodeDetector if available, manual fallback) Detects barcode after 2 consistent frames, fills field and closes modal - Show ⚠️ hint below the barcode field when it's empty (new products only): 'Aggiungi il barcode così al prossimo acquisto basta scansionarlo!' Hint hides automatically when a code is entered or scanned - Hint is hidden in edit-product mode (barcode already saved) - scanBarcodeForForm() reuses the modal overlay; handles camera permission errors gracefully (shows manual input only) --- assets/js/app.js | 103 +++++++++++++++++++++++++++++++++ data/cron.log | 1 + data/dispensa.db | Bin 364544 -> 368640 bytes data/smart_shopping_cache.json | 2 +- index.html | 6 +- 5 files changed, 110 insertions(+), 2 deletions(-) diff --git a/assets/js/app.js b/assets/js/app.js index e0ce1c9..50c492a 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -2425,6 +2425,10 @@ function startManualEntry(barcode = '') { document.getElementById('product-form-title').textContent = 'Nuovo Prodotto'; const pfAiRow = document.getElementById('pf-ai-fill-row'); if (pfAiRow) pfAiRow.style.display = 'block'; + + // Show barcode hint when no barcode was passed + _updateBarcodeHint(); + document.getElementById('pf-barcode').addEventListener('input', _updateBarcodeHint); // Remove datalist/autocomplete suggestions for new products (they cause confusion) document.getElementById('pf-name').removeAttribute('list'); @@ -2552,6 +2556,102 @@ function onPfUnitChange() { if (confRow) confRow.style.display = unit === 'conf' ? 'block' : 'none'; } +function _updateBarcodeHint() { + const hint = document.getElementById('pf-barcode-hint'); + const val = (document.getElementById('pf-barcode')?.value || '').trim(); + if (hint) hint.style.display = val ? 'none' : 'block'; +} + +/** + * Open a temporary camera modal to scan a barcode and fill the pf-barcode field. + * Uses BarcodeDetector if available, otherwise shows manual-input fallback. + */ +async function scanBarcodeForForm() { + const overlayEl = document.getElementById('modal-overlay'); + const contentEl = document.getElementById('modal-content'); + + let stream = null; + let scanning = true; + + const stopStream = () => { + scanning = false; + if (stream) stream.getTracks().forEach(t => t.stop()); + stream = null; + }; + + const closeScanner = () => { + stopStream(); + overlayEl.style.display = 'none'; + }; + + contentEl.innerHTML = ` + +
+ +
+
+

Inquadra il codice a barre del prodotto

+
+ + +
+ `; + overlayEl.style.display = 'flex'; + + // Attach close handler (clicking backdrop) + overlayEl.onclick = (e) => { if (e.target === overlayEl) { stopStream(); overlayEl.style.display = 'none'; overlayEl.onclick = null; } }; + + try { + stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } }); + const video = document.getElementById('pf-bc-video'); + video.srcObject = stream; + await video.play(); + + if (!('BarcodeDetector' in window)) { + // No native API — just let user type manually + return; + } + + const detector = new BarcodeDetector({ formats: ['ean_13','ean_8','code_128','code_39','upc_a','upc_e'] }); + const detectionHistory = {}; + + const scanFrame = async () => { + if (!scanning || !stream) return; + try { + const barcodes = await detector.detect(video); + if (barcodes.length > 0) { + const code = barcodes[0].rawValue; + detectionHistory[code] = (detectionHistory[code] || 0) + 1; + if (detectionHistory[code] >= 2) { + scanning = false; + stopStream(); + overlayEl.style.display = 'none'; + overlayEl.onclick = null; + document.getElementById('pf-barcode').value = code; + _updateBarcodeHint(); + if (navigator.vibrate) navigator.vibrate(80); + showToast(`🔖 Barcode acquisito: ${code}`, 'success'); + return; + } + } + } catch (_) {} + if (scanning) requestAnimationFrame(scanFrame); + }; + requestAnimationFrame(scanFrame); + + } catch (err) { + // Camera not available — user can still type manually + const videoEl = document.getElementById('pf-bc-video'); + if (videoEl) videoEl.style.display = 'none'; + } +} + async function submitProduct(e) { e.preventDefault(); showLoading(true); @@ -2870,6 +2970,9 @@ function editProductFromAction() { document.getElementById('product-form-title').textContent = 'Modifica Prodotto'; const pfAiRow = document.getElementById('pf-ai-fill-row'); if (pfAiRow) pfAiRow.style.display = 'none'; + // Keep barcode hint hidden in edit mode + const pfBcHint = document.getElementById('pf-barcode-hint'); + if (pfBcHint) pfBcHint.style.display = 'none'; // Restore datalist for editing (was removed for new products) document.getElementById('pf-name').setAttribute('list', 'common-products'); diff --git a/data/cron.log b/data/cron.log index b724db9..6d3f673 100644 --- a/data/cron.log +++ b/data/cron.log @@ -1802,3 +1802,4 @@ [2026-04-07 12:00:02] OK — 31 items cached [2026-04-07 12:05:02] OK — 31 items cached [2026-04-07 12:10:01] OK — 30 items cached +[2026-04-07 12:15:02] OK — 30 items cached diff --git a/data/dispensa.db b/data/dispensa.db index d8a1b6c4e551ebb033b767a21cdd781d9e59c310..66283bc3bd43aa7e0cc6899afea4a000561f0e38 100644 GIT binary patch delta 2205 zcmdT_-EY%Y6u=o4x|0xcB)sTc7LKfe zA5+h)9$??3n*x^ucLLuaqw40cAI`51`78#)uf}#ZZy|@*z*e$dl*L$kL=@#%y9j2A zA~AwKM6pAbqF}lxk~)-*I5LaK3Yc1UP!Z*5q#aCRQACW0@hCbNZSRo4#1mFxhu99r zi&k+N8H(cApJoH_{OZ5Q=mCQ82O0x40WLtHZ>joE|7IGJB$x)*ymbo9 zdFv#Y_0|b+)mz8G%vj6NT?o%JR~&j|+{gUEeDBPTbgyFWFmucmcNRb47Vk?Mt+1rtqMxy9typ$4jn-+-rdPzz|<%&~S z^bWf~pqE51EU*i{#~YzU-*D+_s>jdtGdr0EdV#)y>hGniTSi}J02w6eI2laq26UU( zQ)_Facp|E_j2>Q6P3Z>dsk)?CLQ*!5_IRpBbZSyJe5J%Hl93aVylM0`Y)aw)6S_g2 z_S}eG#hXVDEx8#-!T-YzuBq^0J(W}7@9f3`ouZ}*Kf8^Mvtf1lt5VwjmLEJ3P1o2CuyN8;p^&O&Z;BHBgpP|#=u5$l5MXf!Kizeplp^Pu9*Qdqq z;F5{kD=2V*#H|$+xSzz$6%@D@lmv>mim7FpOQ0&xX@N(9Gl4q)tiOjHVlJVKhMA<@ zYj3Xtt#X5G$AauGS>~Q#qXXtiRp_>~!SpdrcnJ~2Q9Whp{kp0diHvIX>qgeS7orkw z^(Km?MX?Q2n5&v(jr+qXGT^-T6Yoslq7Otvi!~|5G~2Nn5~UGD z+q)341ilJgHenPgv@}*%i84x;^_#D4|%y%V$MBHvAWtO-jl zo+3>=7$xOm9axmKcPw)<9;YOXQh%F~6J4u3$XbMj>bNDuoz6RvGRB&Ny~? zo@G3Dcuq~0P}F1N)@3Q;VBQ>{sKYebL7;B)JLRp?BD(}xnN^ueiW2jR6O&6a^Ye-s zuT9==ug8KzkSz_E_=11)4}Ts3vaCxM<6&;#QQgd5z{t4S zP(YS@vue$KX66Qtuansuc27Rm;06?Z%ijF8WBb<*M*ehWQ%26|>>n6&CL0M%Yv=sP z2*gZ4%)FiRBg=0&W*v?h)7b@BBZ0asIJVD_V9haSzR&5lojrhcKgfax_U&$wtoy`R zg4q8tOxFouS^^XdVxKM(%)~XlyPTDCyI=+DXLc@To*xW+CA_ITKY;SDc((uOVdY>3 E0KM39vH$=8 diff --git a/data/smart_shopping_cache.json b/data/smart_shopping_cache.json index 7e6564a..f925a8c 100644 --- a/data/smart_shopping_cache.json +++ b/data/smart_shopping_cache.json @@ -1 +1 @@ -{"success":true,"items":[{"product_id":70,"name":"Latte Parzialmente Scremato Uht","brand":"Latteria","category":"bevande","unit":"conf","current_qty":0,"default_qty":500,"package_unit":"ml","pct_left":0,"use_count":13,"buy_count":3,"daily_rate":6.04,"uses_per_month":13.9,"days_since_last_use":12,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (13x)"],"score":135,"on_bring":false,"locations":""},{"product_id":10,"name":"Passata di pomodoro","brand":"Primia","category":"en:condiments","unit":"g","current_qty":0,"default_qty":700,"package_unit":"","pct_left":0,"use_count":8,"buy_count":3,"daily_rate":47.09,"uses_per_month":8.6,"days_since_last_use":1,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (8x)"],"score":135,"on_bring":false,"locations":""},{"product_id":115,"name":"Aglio rosso","brand":"Duoccio","category":"condimenti","unit":"pz","current_qty":0,"default_qty":0,"package_unit":"","pct_left":0,"use_count":2,"buy_count":2,"daily_rate":0.12,"uses_per_month":2.4,"days_since_last_use":18,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito"],"score":100,"on_bring":false,"locations":""},{"product_id":152,"name":"Muesli Frutta Secca","brand":"Crownfield","category":"altro","unit":"g","current_qty":0,"default_qty":750,"package_unit":"","pct_left":0,"use_count":4,"buy_count":2,"daily_rate":29.14,"uses_per_month":5.9,"days_since_last_use":12,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito"],"score":100,"on_bring":false,"locations":""},{"product_id":69,"name":"Cipolla Dorata","brand":"","category":"verdura","unit":"pz","current_qty":1.8,"default_qty":0,"package_unit":"","pct_left":19,"use_count":15,"buy_count":1,"daily_rate":0.37,"uses_per_month":16.1,"days_since_last_use":1,"days_left":5,"expiry_date":"2026-04-13","days_to_expiry":5,"is_opened":false,"urgency":"high","reasons":["Finisce tra ~5gg"],"score":90,"on_bring":false,"locations":"frigo"},{"product_id":3,"name":"Cracker integrali","brand":"Barilla,Mulino Bianco","category":"en:snacks","unit":"conf","current_qty":2,"default_qty":25,"package_unit":"g","pct_left":12,"use_count":6,"buy_count":1,"daily_rate":0.5,"uses_per_month":6.4,"days_since_last_use":9,"days_left":4,"expiry_date":"2026-04-28","days_to_expiry":20,"is_opened":true,"urgency":"high","reasons":["Quasi finito (12%)"],"score":90,"on_bring":false,"locations":"dispensa"},{"product_id":47,"name":"Lenticchie","brand":"Primia","category":"en:plant-based-foods-and-beverages","unit":"conf","current_qty":2,"default_qty":400,"package_unit":"g","pct_left":1,"use_count":5,"buy_count":4,"daily_rate":32.16,"uses_per_month":5.4,"days_since_last_use":3,"days_left":0,"expiry_date":"2029-12-13","days_to_expiry":1345,"is_opened":false,"urgency":"high","reasons":["Quasi finito (1%)"],"score":90,"on_bring":false,"locations":"dispensa"},{"product_id":161,"name":"Yogurt agrumi","brand":"Vipiteno","category":"latticini","unit":"conf","current_qty":0.3,"default_qty":500,"package_unit":"g","pct_left":26,"use_count":2,"buy_count":1,"daily_rate":0.65,"uses_per_month":1,"days_since_last_use":1,"days_left":0,"expiry_date":"2026-04-09","days_to_expiry":1,"is_opened":true,"urgency":"medium","reasons":["Finisce tra ~0gg","Scade tra 1gg"],"score":90,"on_bring":false,"locations":"frigo"},{"product_id":154,"name":"Mela Rossa","brand":"","category":"frutta","unit":"pz","current_qty":6,"default_qty":1,"package_unit":"","pct_left":27,"use_count":6,"buy_count":1,"daily_rate":0.8,"uses_per_month":9,"days_since_last_use":3,"days_left":8,"expiry_date":"2026-04-15","days_to_expiry":7,"is_opened":false,"urgency":"medium","reasons":["Finisce tra ~8gg"],"score":60,"on_bring":false,"locations":"frigo"},{"product_id":144,"name":"Pancetta Dolce","brand":"Negroni","category":"en:meats-and-their-products","unit":"conf","current_qty":1,"default_qty":80,"package_unit":"g","pct_left":50,"use_count":1,"buy_count":1,"daily_rate":0.04,"uses_per_month":1.3,"days_since_last_use":8,"days_left":23,"expiry_date":"2026-09-11","days_to_expiry":156,"is_opened":false,"urgency":"high","reasons":["Solo 1 confezione rimasta"],"score":60,"on_bring":true,"locations":"frigo"},{"product_id":29,"name":"Sale marino iodato","brand":"Primia","category":"","unit":"pz","current_qty":1,"default_qty":1,"package_unit":"","pct_left":100,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":28,"days_left":365,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"high","reasons":["Solo 1 pezzo rimasto"],"score":60,"on_bring":false,"locations":"dispensa"},{"product_id":56,"name":"Tonno all'Olio di Oliva","brand":"Rio Mare","category":"conserve","unit":"pz","current_qty":1,"default_qty":1,"package_unit":"","pct_left":50,"use_count":1,"buy_count":1,"daily_rate":0.04,"uses_per_month":1.1,"days_since_last_use":26,"days_left":28,"expiry_date":"2029-12-31","days_to_expiry":1363,"is_opened":false,"urgency":"high","reasons":["Solo 1 pezzo rimasto"],"score":60,"on_bring":false,"locations":"dispensa"},{"product_id":163,"name":"Yogurt vaniglia","brand":"Vipiteno","category":"latticini","unit":"conf","current_qty":1,"default_qty":500,"package_unit":"g","pct_left":100,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":1,"days_left":365,"expiry_date":"2026-05-19","days_to_expiry":41,"is_opened":false,"urgency":"high","reasons":["Solo 1 confezione rimasta"],"score":60,"on_bring":false,"locations":"frigo"},{"product_id":106,"name":"Zuppalatte","brand":"Colussi","category":"en:plant-based-foods-and-beverages","unit":"conf","current_qty":1,"default_qty":250,"package_unit":"g","pct_left":33,"use_count":1,"buy_count":1,"daily_rate":0.08,"uses_per_month":1.2,"days_since_last_use":25,"days_left":12,"expiry_date":"2027-06-01","days_to_expiry":419,"is_opened":false,"urgency":"high","reasons":["Solo 1 confezione rimasta"],"score":60,"on_bring":false,"locations":"dispensa"},{"product_id":166,"name":"mix energia","brand":"","category":"","unit":"pz","current_qty":1,"default_qty":1,"package_unit":"","pct_left":100,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":1,"days_left":365,"expiry_date":"2026-11-29","days_to_expiry":235,"is_opened":false,"urgency":"high","reasons":["Solo 1 pezzo rimasto"],"score":60,"on_bring":false,"locations":"dispensa"},{"product_id":132,"name":"Noci sgusciate","brand":"Fruttbella","category":"conserve","unit":"g","current_qty":60,"default_qty":200,"package_unit":"","pct_left":30,"use_count":4,"buy_count":1,"daily_rate":6.15,"uses_per_month":5.3,"days_since_last_use":3,"days_left":10,"expiry_date":"2026-04-29","days_to_expiry":21,"is_opened":true,"urgency":"medium","reasons":["Finisce tra ~10gg"],"score":50,"on_bring":true,"locations":"dispensa"},{"product_id":130,"name":"Uova Sfoglia Gialla","brand":"Naturelle","category":"latticini","unit":"pz","current_qty":4,"default_qty":1,"package_unit":"","pct_left":67,"use_count":5,"buy_count":2,"daily_rate":0.35,"uses_per_month":6.6,"days_since_last_use":1,"days_left":11,"expiry_date":"2026-04-09","days_to_expiry":1,"is_opened":false,"urgency":"medium","reasons":["Scade tra 1gg"],"score":50,"on_bring":false,"locations":"frigo"},{"product_id":87,"name":"Aroma per dolci e creme Rum","brand":"Dr. Oetker, Cameo, Paneangeli","category":"en:food-additives","unit":"pz","current_qty":2,"default_qty":5,"package_unit":"","pct_left":40,"use_count":3,"buy_count":1,"daily_rate":0.11,"uses_per_month":3.4,"days_since_last_use":3,"days_left":18,"expiry_date":"2028-09-28","days_to_expiry":904,"is_opened":false,"urgency":"medium","reasons":["Solo 2 pezzi rimasti"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":86,"name":"Arome Orange Pour Gateaux","brand":"Dr. Oetker, Cameo, Paneangeli","category":"","unit":"pz","current_qty":2,"default_qty":1,"package_unit":"","pct_left":67,"use_count":1,"buy_count":1,"daily_rate":0.04,"uses_per_month":1.1,"days_since_last_use":7,"days_left":54,"expiry_date":"2027-02-01","days_to_expiry":299,"is_opened":false,"urgency":"medium","reasons":["Solo 2 pezzi rimasti"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":170,"name":"Avocado Hass","brand":"Alce nero","category":"en:plant-based-foods-and-beverages","unit":"pz","current_qty":2,"default_qty":2,"package_unit":"","pct_left":100,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":1,"days_left":365,"expiry_date":"2026-10-03","days_to_expiry":178,"is_opened":false,"urgency":"medium","reasons":["Solo 2 pezzi rimasti"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":8,"name":"Condoro Sugo Al Pomodoro Sauce Le Conserve Della Nonna","brand":"Fini, Le conserve della nonna","category":"en:condiments","unit":"conf","current_qty":2,"default_qty":350,"package_unit":"g","pct_left":1,"use_count":0,"buy_count":2,"daily_rate":0,"uses_per_month":0,"days_since_last_use":28,"days_left":365,"expiry_date":"2028-07-31","days_to_expiry":845,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":1,"name":"Grissini","brand":"GrissinBon","category":"en:plant-based-foods-and-beverages","unit":"conf","current_qty":2,"default_qty":500,"package_unit":"","pct_left":100,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":28,"days_left":365,"expiry_date":"2026-07-09","days_to_expiry":92,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":129,"name":"Latte di Montagna","brand":"Mila","category":"en:dairies","unit":"conf","current_qty":4.8,"default_qty":1000,"package_unit":"ml","pct_left":192,"use_count":14,"buy_count":6,"daily_rate":0.45,"uses_per_month":18.4,"days_since_last_use":0,"days_left":11,"expiry_date":"2026-04-11","days_to_expiry":3,"is_opened":true,"urgency":"low","reasons":["Previsto esaurimento tra ~11gg"],"score":40,"on_bring":false,"locations":"frigo"},{"product_id":92,"name":"Lievito istantaneo","brand":"Paneangeli","category":"altro","unit":"g","current_qty":5,"default_qty":15,"package_unit":"","pct_left":33,"use_count":1,"buy_count":1,"daily_rate":0.37,"uses_per_month":1.1,"days_since_last_use":27,"days_left":13,"expiry_date":"2026-04-10","days_to_expiry":2,"is_opened":true,"urgency":"medium","reasons":["Scade tra 2gg"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":55,"name":"Mais Dolce","brand":"Despar","category":"conserve","unit":"conf","current_qty":2,"default_qty":160,"package_unit":"g","pct_left":0,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":28,"days_left":365,"expiry_date":"2028-12-31","days_to_expiry":998,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":39,"name":"Panna da cucina","brand":"Chef, Parmalat","category":"altro","unit":"conf","current_qty":2,"default_qty":125,"package_unit":"g","pct_left":67,"use_count":2,"buy_count":1,"daily_rate":0.01,"uses_per_month":2.1,"days_since_last_use":8,"days_left":138,"expiry_date":"2026-04-29","days_to_expiry":21,"is_opened":true,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":2,"name":"Pera Italiana Succo e polpa frutta","brand":"Conserve Italia, Valfrutta","category":"bevande","unit":"conf","current_qty":2,"default_qty":200,"package_unit":"ml","pct_left":50,"use_count":3,"buy_count":1,"daily_rate":0.11,"uses_per_month":3.2,"days_since_last_use":2,"days_left":19,"expiry_date":"2027-02-01","days_to_expiry":299,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":127,"name":"Polpa di pomodoro finissima","brand":"Primia","category":"en:plant-based-foods-and-beverages","unit":"conf","current_qty":2,"default_qty":500,"package_unit":"g","pct_left":1,"use_count":0,"buy_count":2,"daily_rate":0,"uses_per_month":0,"days_since_last_use":23,"days_left":365,"expiry_date":"2028-03-14","days_to_expiry":706,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":114,"name":"Vino bianco Trebbiano igt Rubicone","brand":"Vesoletto","category":"bevande","unit":"conf","current_qty":2,"default_qty":250,"package_unit":"ml","pct_left":100,"use_count":1,"buy_count":1,"daily_rate":0,"uses_per_month":1.2,"days_since_last_use":4,"days_left":365,"expiry_date":"2027-04-03","days_to_expiry":360,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"frigo"},{"product_id":136,"name":"Biscotti Pastefrolle","brand":"Balocco","category":"snack","unit":"g","current_qty":350,"default_qty":700,"package_unit":"","pct_left":67,"use_count":4,"buy_count":2,"daily_rate":30.74,"uses_per_month":5.3,"days_since_last_use":3,"days_left":11,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"low","reasons":["Previsto esaurimento tra ~11gg"],"score":25,"on_bring":false,"locations":"dispensa"}],"cached_at":"2026-04-07T12:10:01+00:00","cached_ts":1775563801} \ No newline at end of file +{"success":true,"items":[{"product_id":70,"name":"Latte Parzialmente Scremato Uht","brand":"Latteria","category":"bevande","unit":"conf","current_qty":0,"default_qty":500,"package_unit":"ml","pct_left":0,"use_count":13,"buy_count":3,"daily_rate":6.04,"uses_per_month":13.9,"days_since_last_use":12,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (13x)"],"score":135,"on_bring":false,"locations":""},{"product_id":10,"name":"Passata di pomodoro","brand":"Primia","category":"en:condiments","unit":"g","current_qty":0,"default_qty":700,"package_unit":"","pct_left":0,"use_count":8,"buy_count":3,"daily_rate":47.08,"uses_per_month":8.6,"days_since_last_use":1,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito","Uso frequente (8x)"],"score":135,"on_bring":false,"locations":""},{"product_id":115,"name":"Aglio rosso","brand":"Duoccio","category":"condimenti","unit":"pz","current_qty":0,"default_qty":0,"package_unit":"","pct_left":0,"use_count":2,"buy_count":2,"daily_rate":0.12,"uses_per_month":2.4,"days_since_last_use":18,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito"],"score":100,"on_bring":false,"locations":""},{"product_id":152,"name":"Muesli Frutta Secca","brand":"Crownfield","category":"altro","unit":"g","current_qty":0,"default_qty":750,"package_unit":"","pct_left":0,"use_count":4,"buy_count":2,"daily_rate":29.13,"uses_per_month":5.9,"days_since_last_use":12,"days_left":0,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"critical","reasons":["Esaurito"],"score":100,"on_bring":false,"locations":""},{"product_id":69,"name":"Cipolla Dorata","brand":"","category":"verdura","unit":"pz","current_qty":1.8,"default_qty":0,"package_unit":"","pct_left":19,"use_count":15,"buy_count":1,"daily_rate":0.37,"uses_per_month":16.1,"days_since_last_use":1,"days_left":5,"expiry_date":"2026-04-13","days_to_expiry":5,"is_opened":false,"urgency":"high","reasons":["Finisce tra ~5gg"],"score":90,"on_bring":false,"locations":"frigo"},{"product_id":3,"name":"Cracker integrali","brand":"Barilla,Mulino Bianco","category":"en:snacks","unit":"conf","current_qty":2,"default_qty":25,"package_unit":"g","pct_left":12,"use_count":6,"buy_count":1,"daily_rate":0.5,"uses_per_month":6.4,"days_since_last_use":9,"days_left":4,"expiry_date":"2026-04-28","days_to_expiry":20,"is_opened":true,"urgency":"high","reasons":["Quasi finito (12%)"],"score":90,"on_bring":false,"locations":"dispensa"},{"product_id":47,"name":"Lenticchie","brand":"Primia","category":"en:plant-based-foods-and-beverages","unit":"conf","current_qty":2,"default_qty":400,"package_unit":"g","pct_left":1,"use_count":5,"buy_count":4,"daily_rate":32.16,"uses_per_month":5.4,"days_since_last_use":3,"days_left":0,"expiry_date":"2029-12-13","days_to_expiry":1345,"is_opened":false,"urgency":"high","reasons":["Quasi finito (1%)"],"score":90,"on_bring":false,"locations":"dispensa"},{"product_id":161,"name":"Yogurt agrumi","brand":"Vipiteno","category":"latticini","unit":"conf","current_qty":0.3,"default_qty":500,"package_unit":"g","pct_left":26,"use_count":2,"buy_count":1,"daily_rate":0.65,"uses_per_month":1,"days_since_last_use":1,"days_left":0,"expiry_date":"2026-04-09","days_to_expiry":1,"is_opened":true,"urgency":"medium","reasons":["Finisce tra ~0gg","Scade tra 1gg"],"score":90,"on_bring":false,"locations":"frigo"},{"product_id":154,"name":"Mela Rossa","brand":"","category":"frutta","unit":"pz","current_qty":6,"default_qty":1,"package_unit":"","pct_left":27,"use_count":6,"buy_count":1,"daily_rate":0.8,"uses_per_month":9,"days_since_last_use":3,"days_left":8,"expiry_date":"2026-04-15","days_to_expiry":7,"is_opened":false,"urgency":"medium","reasons":["Finisce tra ~8gg"],"score":60,"on_bring":false,"locations":"frigo"},{"product_id":144,"name":"Pancetta Dolce","brand":"Negroni","category":"en:meats-and-their-products","unit":"conf","current_qty":1,"default_qty":80,"package_unit":"g","pct_left":50,"use_count":1,"buy_count":1,"daily_rate":0.04,"uses_per_month":1.3,"days_since_last_use":8,"days_left":23,"expiry_date":"2026-09-11","days_to_expiry":156,"is_opened":false,"urgency":"high","reasons":["Solo 1 confezione rimasta"],"score":60,"on_bring":true,"locations":"frigo"},{"product_id":29,"name":"Sale marino iodato","brand":"Primia","category":"","unit":"pz","current_qty":1,"default_qty":1,"package_unit":"","pct_left":100,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":28,"days_left":365,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"high","reasons":["Solo 1 pezzo rimasto"],"score":60,"on_bring":false,"locations":"dispensa"},{"product_id":56,"name":"Tonno all'Olio di Oliva","brand":"Rio Mare","category":"conserve","unit":"pz","current_qty":1,"default_qty":1,"package_unit":"","pct_left":50,"use_count":1,"buy_count":1,"daily_rate":0.04,"uses_per_month":1.1,"days_since_last_use":26,"days_left":28,"expiry_date":"2029-12-31","days_to_expiry":1363,"is_opened":false,"urgency":"high","reasons":["Solo 1 pezzo rimasto"],"score":60,"on_bring":false,"locations":"dispensa"},{"product_id":163,"name":"Yogurt vaniglia","brand":"Vipiteno","category":"latticini","unit":"conf","current_qty":1,"default_qty":500,"package_unit":"g","pct_left":100,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":1,"days_left":365,"expiry_date":"2026-05-19","days_to_expiry":41,"is_opened":false,"urgency":"high","reasons":["Solo 1 confezione rimasta"],"score":60,"on_bring":false,"locations":"frigo"},{"product_id":106,"name":"Zuppalatte","brand":"Colussi","category":"en:plant-based-foods-and-beverages","unit":"conf","current_qty":1,"default_qty":250,"package_unit":"g","pct_left":33,"use_count":1,"buy_count":1,"daily_rate":0.08,"uses_per_month":1.2,"days_since_last_use":25,"days_left":12,"expiry_date":"2027-06-01","days_to_expiry":419,"is_opened":false,"urgency":"high","reasons":["Solo 1 confezione rimasta"],"score":60,"on_bring":false,"locations":"dispensa"},{"product_id":166,"name":"mix energia","brand":"","category":"","unit":"pz","current_qty":1,"default_qty":1,"package_unit":"","pct_left":100,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":1,"days_left":365,"expiry_date":"2026-11-29","days_to_expiry":235,"is_opened":false,"urgency":"high","reasons":["Solo 1 pezzo rimasto"],"score":60,"on_bring":false,"locations":"dispensa"},{"product_id":132,"name":"Noci sgusciate","brand":"Fruttbella","category":"conserve","unit":"g","current_qty":60,"default_qty":200,"package_unit":"","pct_left":30,"use_count":4,"buy_count":1,"daily_rate":6.15,"uses_per_month":5.3,"days_since_last_use":3,"days_left":10,"expiry_date":"2026-04-29","days_to_expiry":21,"is_opened":true,"urgency":"medium","reasons":["Finisce tra ~10gg"],"score":50,"on_bring":true,"locations":"dispensa"},{"product_id":130,"name":"Uova Sfoglia Gialla","brand":"Naturelle","category":"latticini","unit":"pz","current_qty":4,"default_qty":1,"package_unit":"","pct_left":67,"use_count":5,"buy_count":2,"daily_rate":0.35,"uses_per_month":6.6,"days_since_last_use":1,"days_left":11,"expiry_date":"2026-04-09","days_to_expiry":1,"is_opened":false,"urgency":"medium","reasons":["Scade tra 1gg"],"score":50,"on_bring":false,"locations":"frigo"},{"product_id":87,"name":"Aroma per dolci e creme Rum","brand":"Dr. Oetker, Cameo, Paneangeli","category":"en:food-additives","unit":"pz","current_qty":2,"default_qty":5,"package_unit":"","pct_left":40,"use_count":3,"buy_count":1,"daily_rate":0.11,"uses_per_month":3.4,"days_since_last_use":3,"days_left":18,"expiry_date":"2028-09-28","days_to_expiry":904,"is_opened":false,"urgency":"medium","reasons":["Solo 2 pezzi rimasti"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":86,"name":"Arome Orange Pour Gateaux","brand":"Dr. Oetker, Cameo, Paneangeli","category":"","unit":"pz","current_qty":2,"default_qty":1,"package_unit":"","pct_left":67,"use_count":1,"buy_count":1,"daily_rate":0.04,"uses_per_month":1.1,"days_since_last_use":7,"days_left":54,"expiry_date":"2027-02-01","days_to_expiry":299,"is_opened":false,"urgency":"medium","reasons":["Solo 2 pezzi rimasti"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":170,"name":"Avocado Hass","brand":"Alce nero","category":"en:plant-based-foods-and-beverages","unit":"pz","current_qty":2,"default_qty":2,"package_unit":"","pct_left":100,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":1,"days_left":365,"expiry_date":"2026-10-03","days_to_expiry":178,"is_opened":false,"urgency":"medium","reasons":["Solo 2 pezzi rimasti"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":8,"name":"Condoro Sugo Al Pomodoro Sauce Le Conserve Della Nonna","brand":"Fini, Le conserve della nonna","category":"en:condiments","unit":"conf","current_qty":2,"default_qty":350,"package_unit":"g","pct_left":1,"use_count":0,"buy_count":2,"daily_rate":0,"uses_per_month":0,"days_since_last_use":28,"days_left":365,"expiry_date":"2028-07-31","days_to_expiry":845,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":1,"name":"Grissini","brand":"GrissinBon","category":"en:plant-based-foods-and-beverages","unit":"conf","current_qty":2,"default_qty":500,"package_unit":"","pct_left":100,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":28,"days_left":365,"expiry_date":"2026-07-09","days_to_expiry":92,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":129,"name":"Latte di Montagna","brand":"Mila","category":"en:dairies","unit":"conf","current_qty":4.8,"default_qty":1000,"package_unit":"ml","pct_left":192,"use_count":14,"buy_count":6,"daily_rate":0.45,"uses_per_month":18.4,"days_since_last_use":0,"days_left":11,"expiry_date":"2026-04-11","days_to_expiry":3,"is_opened":true,"urgency":"low","reasons":["Previsto esaurimento tra ~11gg"],"score":40,"on_bring":false,"locations":"frigo"},{"product_id":92,"name":"Lievito istantaneo","brand":"Paneangeli","category":"altro","unit":"g","current_qty":5,"default_qty":15,"package_unit":"","pct_left":33,"use_count":1,"buy_count":1,"daily_rate":0.37,"uses_per_month":1.1,"days_since_last_use":27,"days_left":13,"expiry_date":"2026-04-10","days_to_expiry":2,"is_opened":true,"urgency":"medium","reasons":["Scade tra 2gg"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":55,"name":"Mais Dolce","brand":"Despar","category":"conserve","unit":"conf","current_qty":2,"default_qty":160,"package_unit":"g","pct_left":0,"use_count":0,"buy_count":1,"daily_rate":0,"uses_per_month":0,"days_since_last_use":28,"days_left":365,"expiry_date":"2028-12-31","days_to_expiry":998,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":39,"name":"Panna da cucina","brand":"Chef, Parmalat","category":"altro","unit":"conf","current_qty":2,"default_qty":125,"package_unit":"g","pct_left":67,"use_count":2,"buy_count":1,"daily_rate":0.01,"uses_per_month":2.1,"days_since_last_use":8,"days_left":138,"expiry_date":"2026-04-29","days_to_expiry":21,"is_opened":true,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":2,"name":"Pera Italiana Succo e polpa frutta","brand":"Conserve Italia, Valfrutta","category":"bevande","unit":"conf","current_qty":2,"default_qty":200,"package_unit":"ml","pct_left":50,"use_count":3,"buy_count":1,"daily_rate":0.11,"uses_per_month":3.2,"days_since_last_use":2,"days_left":19,"expiry_date":"2027-02-01","days_to_expiry":299,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":127,"name":"Polpa di pomodoro finissima","brand":"Primia","category":"en:plant-based-foods-and-beverages","unit":"conf","current_qty":2,"default_qty":500,"package_unit":"g","pct_left":1,"use_count":0,"buy_count":2,"daily_rate":0,"uses_per_month":0,"days_since_last_use":23,"days_left":365,"expiry_date":"2028-03-14","days_to_expiry":706,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"dispensa"},{"product_id":114,"name":"Vino bianco Trebbiano igt Rubicone","brand":"Vesoletto","category":"bevande","unit":"conf","current_qty":2,"default_qty":250,"package_unit":"ml","pct_left":100,"use_count":1,"buy_count":1,"daily_rate":0,"uses_per_month":1.2,"days_since_last_use":4,"days_left":365,"expiry_date":"2027-04-03","days_to_expiry":360,"is_opened":false,"urgency":"medium","reasons":["Solo 2 confezioni rimaste"],"score":40,"on_bring":false,"locations":"frigo"},{"product_id":136,"name":"Biscotti Pastefrolle","brand":"Balocco","category":"snack","unit":"g","current_qty":350,"default_qty":700,"package_unit":"","pct_left":67,"use_count":4,"buy_count":2,"daily_rate":30.73,"uses_per_month":5.3,"days_since_last_use":3,"days_left":11,"expiry_date":null,"days_to_expiry":999,"is_opened":false,"urgency":"low","reasons":["Previsto esaurimento tra ~11gg"],"score":25,"on_bring":false,"locations":"dispensa"}],"cached_at":"2026-04-07T12:15:02+00:00","cached_ts":1775564102} \ No newline at end of file diff --git a/index.html b/index.html index e486d80..dcc29f4 100644 --- a/index.html +++ b/index.html @@ -472,7 +472,11 @@
- +
+ + +
+