Fix: svuota ricerca, rimuovi autocomplete prodotto nuovo, camera più grande, modalità spesa, fix duplicati chat
This commit is contained in:
+25
-3
@@ -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
@@ -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) =====
|
||||
|
||||
Binary file not shown.
+7
-3
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user