Fix: svuota ricerca, rimuovi autocomplete prodotto nuovo, camera più grande, modalità spesa, fix duplicati chat

This commit is contained in:
dadaloop82
2026-03-13 14:20:00 +00:00
parent cbb7d53e78
commit d92b72cfae
4 changed files with 120 additions and 14 deletions
+25 -3
View File
@@ -98,9 +98,9 @@ body {
background: rgba(255,255,255,0.25);
border: 2px solid rgba(255,255,255,0.5);
color: white;
font-size: 1.8rem;
width: 52px;
height: 52px;
font-size: 2.1rem;
width: 58px;
height: 58px;
border-radius: 50%;
cursor: pointer;
display: flex;
@@ -142,6 +142,28 @@ body {
background: rgba(255,255,255,0.4);
}
/* Spesa mode banner */
.spesa-mode-banner {
display: flex;
align-items: center;
justify-content: space-between;
background: linear-gradient(135deg, #f59e0b, #d97706);
color: #fff;
padding: 10px 16px;
border-radius: var(--radius-sm);
margin-bottom: 10px;
font-weight: 600;
font-size: 0.95rem;
box-shadow: var(--shadow);
}
.spesa-mode-banner .btn {
background: rgba(255,255,255,0.25);
color: #fff;
border: 1px solid rgba(255,255,255,0.5);
font-weight: 600;
padding: 6px 14px;
}
@keyframes pulse-scan {
0%, 100% { box-shadow: 0 2px 8px rgba(0,0,0,0.2); }
50% { box-shadow: 0 2px 16px rgba(255,255,255,0.4); }
+88 -8
View File
@@ -699,7 +699,7 @@ function showPage(pageId, param = null) {
}
loadInventory();
break;
case 'scan': initScanner(); clearQuickNameResults(); break;
case 'scan': initScanner(); clearQuickNameResults(); updateSpesaBanner(); break;
case 'products': loadAllProducts(); break;
case 'shopping': loadShoppingList(); break;
case 'recipe': loadRecipeArchive(); break;
@@ -1916,6 +1916,9 @@ function selectQuickProduct(product) {
if (pesoMatch) currentProduct.weight_info = pesoMatch[1].trim();
}
clearQuickNameResults();
// Clear the search input
const qInput = document.getElementById('quick-product-name');
if (qInput) qInput.value = '';
showProductAction();
}
@@ -1983,6 +1986,10 @@ function startManualEntry(barcode = '') {
document.getElementById('pf-image-preview').style.display = 'none';
document.getElementById('product-form-title').textContent = 'Nuovo Prodotto';
// Remove datalist/autocomplete suggestions for new products (they cause confusion)
document.getElementById('pf-name').removeAttribute('list');
document.getElementById('pf-brand').removeAttribute('list');
// Reset conf-size-row visibility
const pfConfRow = document.getElementById('pf-conf-size-row');
if (pfConfRow) pfConfRow.style.display = 'none';
@@ -2822,7 +2829,7 @@ async function submitAdd(e) {
showLoading(false);
if (result.success) {
showToast(`${currentProduct.name} aggiunto!`, 'success');
showPage('dashboard');
if (!spesaModeAfterAdd()) showPage('dashboard');
} else {
showToast(result.error || 'Errore', 'error');
}
@@ -3245,6 +3252,11 @@ async function selectProductForAction(productId) {
if (data.product) {
currentProduct = data.product;
showLoading(false);
// Clear search inputs after selecting a product
const psInput = document.getElementById('products-search');
if (psInput) psInput.value = '';
const invInput = document.getElementById('inventory-search');
if (invInput) invInput.value = '';
showProductAction();
} else {
showLoading(false);
@@ -4480,16 +4492,20 @@ async function generateRecipe() {
// ===== GEMINI CHAT =====
let chatHistory = [];
let chatInventoryContext = null;
let _chatSavedCount = 0; // track how many messages already saved to DB
function initChat() {
// Load chat history from DB
api('chat_list').then(res => {
if (res.success && res.messages && res.messages.length > 0) {
chatHistory = res.messages.map(m => ({ role: m.role, text: m.text }));
_chatSavedCount = chatHistory.length;
renderChatHistory();
} else {
_chatSavedCount = 0;
}
}).catch(() => {});
// Pre-load inventory context
}).catch(() => { _chatSavedCount = 0; });
// Always reload fresh inventory context
loadChatContext();
// Focus input
setTimeout(() => {
@@ -4643,10 +4659,17 @@ function clearChat() {
function saveChatHistory() {
// Keep last 50 messages max
if (chatHistory.length > 50) chatHistory = chatHistory.slice(-50);
// Save last 2 messages (the newest pair) to DB
const newMsgs = chatHistory.slice(-2);
api('chat_save', {}, 'POST', { messages: newMsgs }).catch(() => {});
if (chatHistory.length > 50) {
const trimmed = chatHistory.length - 50;
chatHistory = chatHistory.slice(-50);
_chatSavedCount = Math.max(0, _chatSavedCount - trimmed);
}
// Only save messages that haven't been saved yet (prevent duplicates)
const unsaved = chatHistory.slice(_chatSavedCount);
if (unsaved.length === 0) return;
api('chat_save', {}, 'POST', { messages: unsaved }).then(() => {
_chatSavedCount = chatHistory.length;
}).catch(() => {});
}
// ===== SCREENSAVER & INACTIVITY AUTO-REFRESH =====
@@ -5070,6 +5093,62 @@ function generateScreensaverFact() {
return facts[Math.floor(Math.random() * facts.length)]();
}
// ===== SPESA MODE (long-press camera for continuous scanning) =====
let _spesaMode = false;
let _longPressTimer = null;
function initSpesaMode() {
const btn = document.getElementById('btn-header-scan');
if (!btn) return;
btn.addEventListener('pointerdown', (e) => {
_longPressTimer = setTimeout(() => {
_longPressTimer = null;
startSpesaMode();
}, 600);
});
btn.addEventListener('pointerup', () => {
if (_longPressTimer) {
clearTimeout(_longPressTimer);
_longPressTimer = null;
// Short press — normal scan
showPage('scan');
}
});
btn.addEventListener('pointerleave', () => {
if (_longPressTimer) {
clearTimeout(_longPressTimer);
_longPressTimer = null;
}
});
}
function startSpesaMode() {
_spesaMode = true;
showToast('🛒 Modalità Spesa attivata!', 'success');
showPage('scan');
updateSpesaBanner();
}
function endSpesaMode() {
_spesaMode = false;
updateSpesaBanner();
stopScanner();
showPage('dashboard');
}
function updateSpesaBanner() {
const banner = document.getElementById('spesa-mode-banner');
if (banner) banner.style.display = _spesaMode ? 'flex' : 'none';
}
// Called after successful add — returns true if spesa mode handled navigation
function spesaModeAfterAdd() {
if (!_spesaMode) return false;
showPage('scan');
return true;
}
function initInactivityWatcher() {
const events = ['pointerdown', 'pointermove', 'keydown', 'scroll', 'touchstart'];
events.forEach(evt => {
@@ -5089,6 +5168,7 @@ document.addEventListener('DOMContentLoaded', () => {
syncSettingsFromDB();
showPage('dashboard');
initInactivityWatcher();
initSpesaMode();
});
// ===== DUPLICLICK (SPESA ONLINE) =====
BIN
View File
Binary file not shown.
+7 -3
View File
@@ -9,7 +9,7 @@
<title>Dispensa Manager</title>
<link rel="manifest" href="manifest.json">
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🏠</text></svg>">
<link rel="stylesheet" href="assets/css/style.css?v=20260313b">
<link rel="stylesheet" href="assets/css/style.css?v=20260313c">
<!-- QuaggaJS for barcode scanning -->
<script src="https://cdn.jsdelivr.net/npm/@ericblade/quagga2@1.8.4/dist/quagga.min.js"></script>
</head>
@@ -23,7 +23,7 @@
<button class="header-scan-btn header-gemini-btn" onclick="showPage('chat')" title="Chat con Gemini">
<svg class="gemini-icon" viewBox="0 0 24 24" width="28" height="28" fill="white"><path d="M12 0C12 6.627 6.627 12 0 12c6.627 0 12 5.373 12 12 0-6.627 5.373-12 12-12-6.627 0-12-5.373-12-12z"/></svg>
</button>
<button class="header-scan-btn" onclick="showPage('scan')" title="Scansiona prodotto">
<button class="header-scan-btn" id="btn-header-scan" title="Scansiona prodotto (tieni premuto per modalità spesa)">
📷
</button>
</div>
@@ -103,6 +103,10 @@
<button class="back-btn" onclick="stopScanner(); showPage('dashboard')">← Indietro</button>
<h2>Scansiona Prodotto</h2>
</div>
<div class="spesa-mode-banner" id="spesa-mode-banner" style="display:none">
<span>🛒 Modalità Spesa attiva</span>
<button class="btn btn-small" onclick="endSpesaMode()">✅ Fine spesa</button>
</div>
<div class="scan-container">
<div class="scanner-viewport" id="scanner-viewport">
<div class="scanner-overlay">
@@ -870,6 +874,6 @@
</div>
</div>
<script src="assets/js/app.js?v=20260313b"></script>
<script src="assets/js/app.js?v=20260313c"></script>
</body>
</html>