const tabs = document.querySelectorAll('.tab'); const contents = document.querySelectorAll('.content'); tabs.forEach(tab => tab.addEventListener('click', () => { tabs.forEach(t => t.classList.remove('active')); tab.classList.add('active'); contents.forEach(c => c.classList.remove('active')); document.getElementById(tab.dataset.tab).classList.add('active'); })); // --- Scanner --- let html5QrCode = null; let currentProduct = null; const modalContainer = document.getElementById('modalContainer'); document.getElementById('scanBtn').addEventListener('click', () => { modalContainer.style.display = 'block'; if (!html5QrCode) html5QrCode = new Html5Qrcode("scanner"); html5QrCode.start({ facingMode: "environment" }, { fps: 15, qrbox: 250 }, (decodedText) => { onBarcodeScanned(decodedText); }); }); document.getElementById('closeModal').addEventListener('click', stopScanner); document.getElementById('cancelProduct').addEventListener('click', stopScanner); document.getElementById('scanAnother').addEventListener('click', () => { stopScanner(); modalContainer.style.display = 'block'; if (!html5QrCode) html5QrCode = new Html5Qrcode("scanner"); html5QrCode.start({ facingMode: "environment" }, { fps: 15, qrbox: 250 }, (decodedText) => { onBarcodeScanned(decodedText); }); }); function stopScanner() { if (html5QrCode) html5QrCode.stop().then(() => { html5QrCode.clear(); html5QrCode = null; }).catch(err => console.error(err)); modalContainer.style.display = 'none'; resetForm(); } // --- Ajouter / modifier produit --- document.getElementById('saveProduct').addEventListener('click', async () => { if (!currentProduct) return showToast('Aucun produit scanné', 'red'); currentProduct.name = document.getElementById('product-name').value; currentProduct.qty = parseInt(document.getElementById('product-qty').value); currentProduct.exp = document.getElementById('product-exp').value; currentProduct.location = document.getElementById('product-location').value; await set(ref(db, 'products/' + currentProduct.code), currentProduct); showToast('Produit sauvegardé'); resetForm(); stopScanner(); }); // --- Fonctions utilitaires --- function resetForm() { document.getElementById('product-name').value = ''; document.getElementById('product-qty').value = 1; document.getElementById('product-exp').value = ''; document.getElementById('product-location').value = 'frigo'; currentProduct = null; } function formatDate(dateStr) { if (!dateStr) return '-'; const d = new Date(dateStr); return `${String(d.getDate()).padStart(2,'0')}/${String(d.getMonth()+1).padStart(2,'0')}/${d.getFullYear()}`; } function isExpiringSoon(expDate) { if (!expDate) return false; const diffDays = (new Date(expDate) - new Date()) / (1000*60*60*24); return diffDays <=3 && diffDays >=0; } async function onBarcodeScanned(code) { currentProduct = { code, name: code, qty:1, exp:'', location:'frigo' }; document.getElementById('product-name').value = code; document.getElementById('product-qty').value = 1; document.getElementById('product-exp').value = ''; document.getElementById('product-location').value = 'frigo'; try { const res = await fetch(`https://world.openfoodfacts.org/api/v0/product/${code}.json`); const data = await res.json(); if (data?.product?.product_name) { currentProduct.name = data.product.product_name; document.getElementById('product-name').value = data.product.product_name; } } catch(e){console.warn(e);} } // --- Affichage toast --- function showToast(msg, color='#27ae60') { const toast = document.getElementById('toast'); toast.style.background=color; toast.innerText=msg; toast.style.display='block'; setTimeout(()=>toast.style.display='none',2500); } // --- Rendu produits --- function renderProducts(products) { ['frigo','garde-manger','divers'].forEach(loc=>{ const container=document.getElementById(loc); container.innerHTML=''; let arr=Object.values(products).filter(p=>p.location===loc); arr.sort((a,b)=>{ const da=a.exp?new Date(a.exp):new Date('9999-12-31'); const db=b.exp?new Date(b.exp):new Date('9999-12-31'); return da-db; }); let count=0, alertCount=0; arr.forEach(p=>{ count+=p.qty; if(isExpiringSoon(p.exp)) alertCount+=p.qty; const div=document.createElement('div'); div.className='product'+(isExpiringSoon(p.exp)?' expiring-soon':''); div.innerHTML=`
${p.name}Qté: ${p.qty}
`; container.appendChild(div); // --- Events dynamiques --- div.querySelector('.btn-plus').addEventListener('click', ()=>updateQty(p.code,1)); div.querySelector('.btn-minus').addEventListener('click', ()=>updateQty(p.code,-1)); div.querySelector('.btn-edit').addEventListener('click', ()=>editProduct(p.code)); div.querySelector('.btn-delete').addEventListener('click', ()=>deleteProduct(p.code)); }); document.getElementById('badge-'+loc).innerText=count; document.getElementById('alert-'+loc).innerText=alertCount; }); } // --- Actions CRUD --- function updateQty(code, delta){ get(ref(db,'products/'+code)).then(s=>{ const p=s.val(); if(p){ p.qty=Math.max(0,p.qty+delta); set(ref(db,'products/'+code),p); } }); } function editProduct(code){ get(ref(db,'products/'+code)).then(s=>{ const p=s.val(); if(p){ currentProduct = p; document.getElementById('product-name').value = p.name; document.getElementById('product-qty').value = p.qty; document.getElementById('product-exp').value = p.exp; document.getElementById('product-location').value = p.location; modalContainer.style.display = 'block'; // on ne stoppe pas le scanner ici } }); } function deleteProduct(code){ if(confirm('Supprimer ce produit ?')) remove(ref(db,'products/'+code)); } // --- Écoute Firebase --- onValue(ref(db,'products'), s=>renderProducts(s.val()||{})); // --- Filtre produits expirant bientôt --- document.getElementById('filterExpiring').addEventListener('click', ()=>{ const btn=document.getElementById('filterExpiring'); const showOnly=btn.classList.toggle('active'); btn.innerText=showOnly?'Afficher tous les produits':'Afficher les produits expirant bientôt'; onValue(ref(db,'products'), s=>{ const all=s.val()||{}; const filtered={}; Object.keys(all).forEach(k=>{ if(!showOnly || isExpiringSoon(all[k].exp)) filtered[k]=all[k]; }); renderProducts(filtered); }); });