From 3f4d1bd194a7e5064c0506a588c4e22611162730 Mon Sep 17 00:00:00 2001 From: dadaloop82 Date: Tue, 10 Mar 2026 13:04:53 +0000 Subject: [PATCH] Aggiunta ricerca rapida per nome prodotto (frutta/verdura sfusa) --- assets/css/style.css | 83 ++++++++++++++++++++++++ assets/js/app.js | 147 ++++++++++++++++++++++++++++++++++++++++++- data/dispensa.db | Bin 61440 -> 73728 bytes index.html | 9 ++- 4 files changed, 237 insertions(+), 2 deletions(-) diff --git a/assets/css/style.css b/assets/css/style.css index 70cdc66..85db746 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -879,6 +879,89 @@ body { flex-shrink: 0; } +.quick-name-entry { + margin-bottom: 12px; +} + +.quick-name-divider { + text-align: center; + margin: 10px 0 8px; + position: relative; +} + +.quick-name-divider::before { + content: ''; + position: absolute; + top: 50%; + left: 0; + right: 0; + height: 1px; + background: var(--border); +} + +.quick-name-divider span { + background: var(--bg-main); + padding: 0 12px; + position: relative; + font-size: 0.85rem; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.quick-name-results { + margin-top: 8px; + display: flex; + flex-direction: column; + gap: 6px; + max-height: 200px; + overflow-y: auto; +} + +.quick-name-result-item { + display: flex; + align-items: center; + gap: 10px; + padding: 10px 12px; + background: var(--bg-card); + border-radius: var(--radius); + box-shadow: var(--shadow); + cursor: pointer; + transition: transform 0.1s; +} + +.quick-name-result-item:active { + transform: scale(0.98); +} + +.quick-name-result-item .qnr-icon { + font-size: 1.5rem; + flex-shrink: 0; +} + +.quick-name-result-item .qnr-info { + flex: 1; + min-width: 0; +} + +.quick-name-result-item .qnr-name { + font-weight: 600; + font-size: 0.95rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.quick-name-result-item .qnr-detail { + font-size: 0.8rem; + color: var(--text-muted); +} + +.quick-name-result-item.qnr-new { + border: 1px dashed var(--accent); + background: rgba(124, 58, 237, 0.06); +} + .scan-hint { text-align: center; font-size: 0.85rem; diff --git a/assets/js/app.js b/assets/js/app.js index 18eec58..2a15b75 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -328,7 +328,7 @@ function showPage(pageId, param = null) { } loadInventory(); break; - case 'scan': initScanner(); break; + case 'scan': initScanner(); clearQuickNameResults(); break; case 'products': loadAllProducts(); break; case 'ai': initAICamera(); break; } @@ -1019,6 +1019,151 @@ function submitManualBarcode() { onBarcodeDetected(barcode); } +// ===== QUICK NAME ENTRY (for loose/unpackaged products) ===== +async function submitQuickName() { + const input = document.getElementById('quick-product-name'); + const name = (input.value || '').trim(); + if (!name || name.length < 2) { + showToast('Scrivi almeno 2 caratteri', 'error'); + input.focus(); + return; + } + + stopScanner(); + showLoading(true); + + try { + // Search local products DB + const localData = await api('products_search', { q: name }); + const localProducts = (localData.products || []).slice(0, 5); + + showLoading(false); + + if (localProducts.length > 0) { + // Show results to pick from + option to create new + showQuickNameResults(name, localProducts); + } else { + // No local results โ€” create new product directly + await createQuickProduct(name); + } + } catch (err) { + showLoading(false); + console.error('Quick name search error:', err); + showToast('Errore nella ricerca', 'error'); + } +} + +function showQuickNameResults(searchName, products) { + const container = document.querySelector('.quick-name-entry'); + + // Remove any previous results + const oldResults = container.querySelector('.quick-name-results'); + if (oldResults) oldResults.remove(); + + const resultsDiv = document.createElement('div'); + resultsDiv.className = 'quick-name-results'; + + // Existing products + products.forEach(p => { + const catIcon = CATEGORY_ICONS[mapToLocalCategory(p.category, p.name)] || '๐Ÿ“ฆ'; + const item = document.createElement('div'); + item.className = 'quick-name-result-item'; + item.innerHTML = ` + ${catIcon} +
+
${escapeHtml(p.name)}
+
${p.brand ? escapeHtml(p.brand) + ' ยท ' : ''}${p.barcode ? '๐Ÿ“Š ' + p.barcode : 'Senza barcode'}
+
+ `; + item.onclick = () => selectQuickProduct(p); + resultsDiv.appendChild(item); + }); + + // "Create new" button + const newItem = document.createElement('div'); + newItem.className = 'quick-name-result-item qnr-new'; + newItem.innerHTML = ` + โž• +
+
Crea "${escapeHtml(searchName)}"
+
Nuovo prodotto senza barcode
+
+ `; + newItem.onclick = () => createQuickProduct(searchName); + resultsDiv.appendChild(newItem); + + container.appendChild(resultsDiv); +} + +function selectQuickProduct(product) { + currentProduct = { + id: product.id, + barcode: product.barcode || '', + name: product.name, + brand: product.brand || '', + category: product.category || '', + image_url: product.image_url || '', + unit: product.unit || 'pz', + default_quantity: product.default_quantity || 1, + }; + // Extract weight_info from notes if available + if (product.notes) { + const pesoMatch = product.notes.match(/Peso:\s*([^ยท]+)/); + if (pesoMatch) currentProduct.weight_info = pesoMatch[1].trim(); + } + clearQuickNameResults(); + showProductAction(); +} + +async function createQuickProduct(name) { + showLoading(true); + + // Auto-detect category from name + const category = guessCategoryFromName(name); + + try { + const result = await api('product_save', {}, 'POST', { + name: name, + brand: '', + category: category, + unit: 'pz', + default_quantity: 1, + }); + + if (result.success || result.id) { + currentProduct = { + id: result.id, + name: name, + brand: '', + category: category, + unit: 'pz', + default_quantity: 1, + }; + showLoading(false); + clearQuickNameResults(); + showToast('Prodotto creato!', 'success'); + showProductAction(); + } else { + showLoading(false); + showToast(result.error || 'Errore nel salvataggio', 'error'); + } + } catch (err) { + showLoading(false); + console.error('Quick product creation error:', err); + showToast('Errore di connessione', 'error'); + } +} + +function clearQuickNameResults() { + const container = document.querySelector('.quick-name-entry'); + if (container) { + const results = container.querySelector('.quick-name-results'); + if (results) results.remove(); + } + const input = document.getElementById('quick-product-name'); + if (input) input.value = ''; +} + function startManualEntry(barcode = '') { stopScanner(); // Reset form diff --git a/data/dispensa.db b/data/dispensa.db index d4793b8ad982ad492c47f2cd5e593c3c1fa089d2..43d77c129d9d785b72689280180a7b0cac2b20fd 100644 GIT binary patch delta 5900 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 delta 682 zcmbu6-Afc<6vpSBcV=g2=KWavP$Q*P2)gJ?cilC`ubibKgRTrpsLe1JM7MR7pftBg zrBt*-SA}#D3Q@!|6dDpD)P+S6-Rw;vMGz{Ot+~0jYqRzzbS}=}JP+pwho@&+>Y2mC zJ7rlA1U}-dLUQ!nL(VW?wgiFmb-v1%&8+G#99DKY3O%GwpaSpbJ~BabNRW-ta&nz7 z(M$Xj^U@`H0u1M2LdWSOJI3Fz1yW}gIAXe4x3_oeHMfPN8SZ8|Fy4*AA%APTzcCzW zYi+M22^WW4PTzZB2q3#dJQ!FY^-igFR*~Y!CfPv*~^Efeer%MAD~i<9eyK zqCKUJTBmx&UaLM+OYJGG!aif~Q_{+$64pfJfNfFgmv$MpLcAg0lk4Ry=`DVNJMckq zK^znP@|>85V$n!5g3!-fW=(t)LHw5wuCDf(pI5daM|H7XKsjQ8%jIqg1unJ$i|?1* zWhEZ)t{Re>6lz8y74T}^2RP9WuM_V{lJoXv)@WG*Cl(Y~~GpN4Sy=fim1>c^Wf^MmsG๐Ÿ” Cerca +
+
oppure scrivi il nome
+
+ + +
+
-

Inquadra il codice a barre del prodotto oppure inseriscilo manualmente

+

Scansiona il barcode, scrivi il nome del prodotto, oppure usa l'AI per identificarlo