/* ── Categories page ── */ const CategoriesPage = (() => { function escHtml(str) { return String(str || '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } async function init(container) { await render(container); } async function render(container) { let cats; try { cats = await API.categories(); } catch (e) { container.innerHTML = `

Failed to load: ${e.message}

`; return; } container.innerHTML = `
${cats.map(c => renderItem(c)).join('')} ${cats.length === 0 ? `

No categories yet.

` : ''}
`; document.getElementById('cat-add-form').onsubmit = async (e) => { e.preventDefault(); const name = document.getElementById('cat-new-name').value.trim(); if (!name) return; try { await API.createCategory(name); document.getElementById('cat-new-name').value = ''; showToast('Category added', 'success'); render(container); } catch (err) { showToast('Error: ' + err.message, 'error'); } }; container.querySelectorAll('.btn-delete-cat').forEach(btn => { btn.onclick = async () => { if (!confirm('Delete this category? Bills using it will be uncategorized.')) return; try { await API.deleteCategory(btn.dataset.id); showToast('Category deleted', 'success'); render(container); } catch (err) { showToast('Error: ' + err.message, 'error'); } }; }); container.querySelectorAll('.cat-name-span').forEach(span => { span.ondblclick = () => startRename(span, cats.find(c => c.id == span.dataset.id), container); }); } function renderItem(cat) { return `
${escHtml(cat.name)}
`; } function startRename(span, cat, container) { const input = document.createElement('input'); input.type = 'text'; input.value = cat.name; input.className = 'cat-name'; input.style.flex = '1'; span.replaceWith(input); input.focus(); input.select(); async function commit() { const name = input.value.trim(); if (!name || name === cat.name) { render(container); return; } try { await API.updateCategory(cat.id, name); showToast('Renamed', 'success'); render(container); } catch (err) { showToast('Error: ' + err.message, 'error'); render(container); } } input.addEventListener('blur', commit); input.addEventListener('keydown', e => { if (e.key === 'Enter') input.blur(); if (e.key === 'Escape') render(container); }); } return { init }; })();