diff options
Diffstat (limited to 'static/app.js')
| -rw-r--r-- | static/app.js | 47 |
1 files changed, 47 insertions, 0 deletions
diff --git a/static/app.js b/static/app.js index 3135aa9..796b9bf 100644 --- a/static/app.js +++ b/static/app.js @@ -592,6 +592,7 @@ async function loadGrocery() { document.getElementById('grocery-empty').classList.remove('hidden'); document.getElementById('btn-mark-purchased').classList.add('hidden'); document.getElementById('btn-clear-grocery').classList.add('hidden'); + document.getElementById('btn-copy-grocery').classList.add('hidden'); return; } @@ -599,6 +600,7 @@ async function loadGrocery() { state.currentGroceryId = res.id; document.getElementById('grocery-empty').classList.add('hidden'); document.getElementById('btn-clear-grocery').classList.remove('hidden'); + document.getElementById('btn-copy-grocery').classList.remove('hidden'); if (res.notes) { document.getElementById('grocery-notes').textContent = res.notes; @@ -691,6 +693,48 @@ function renderGroceryList() { } } +function copyGroceryList() { + if (!state.currentGrocery) return; + + let items = state.currentGrocery.items; + if (typeof items === 'string') { + try { items = JSON.parse(items); } catch { items = []; } + } + if (!Array.isArray(items)) items = []; + + const total = items.filter(i => !i.checked).reduce((sum, item) => sum + (item.estimated_cost || 0), 0); + const grouped = {}; + items.forEach(item => { + const section = item.store_section || 'other'; + if (!grouped[section]) grouped[section] = []; + grouped[section].push(item); + }); + + let md = '## Grocery List\n'; + if (total > 0) md += `**Estimated total: $${total.toFixed(2)}**\n`; + + Object.keys(grouped).sort().forEach(section => { + const unchecked = grouped[section].filter(item => !item.checked); + if (!unchecked.length) return; + const title = section.charAt(0).toUpperCase() + section.slice(1); + md += `\n### ${title}\n`; + unchecked.forEach(item => { + const qty = [item.quantity, item.unit].filter(Boolean).join(' '); + md += `- [ ] ${qty ? qty + ' ' : ''}${item.name}\n`; + }); + }); + + const notes = state.currentGrocery.notes; + if (notes) md += `\n> ${notes}\n`; + + navigator.clipboard.writeText(md).then(() => { + const btn = document.getElementById('btn-copy-grocery'); + const orig = btn.textContent; + btn.textContent = 'Copied!'; + setTimeout(() => { btn.textContent = orig; }, 2000); + }).catch(() => showToast('Could not copy to clipboard', 'error')); +} + async function checkGroceryItem(checkbox) { const checked = checkbox.checked; const row = checkbox.closest('.grocery-item'); @@ -739,6 +783,7 @@ async function generateGrocery() { document.getElementById('grocery-empty').classList.add('hidden'); document.getElementById('btn-mark-purchased').classList.remove('hidden'); document.getElementById('btn-clear-grocery').classList.remove('hidden'); + document.getElementById('btn-copy-grocery').classList.remove('hidden'); if (res.shopping_notes) { document.getElementById('grocery-notes').textContent = res.shopping_notes; @@ -771,6 +816,7 @@ async function clearGrocery() { document.getElementById('grocery-notes').classList.add('hidden'); document.getElementById('btn-mark-purchased').classList.add('hidden'); document.getElementById('btn-clear-grocery').classList.add('hidden'); + document.getElementById('btn-copy-grocery').classList.add('hidden'); showToast('Grocery list cleared'); } catch (err) { showToast(err.message, 'error'); @@ -999,6 +1045,7 @@ async function init() { // Set up grocery form document.getElementById('btn-generate-grocery').addEventListener('click', generateGrocery); document.getElementById('btn-clear-grocery').addEventListener('click', clearGrocery); + document.getElementById('btn-copy-grocery').addEventListener('click', copyGroceryList); document.getElementById('btn-mark-purchased').addEventListener('click', markPurchased); // Set up chat |
