/* ── Settings page ── */ const SettingsPage = (() => { async function init(container) { let settings, notifPrefs; try { [settings, notifPrefs] = await Promise.all([ API.settings(), fetch('/api/notifications/me').then(r => r.ok ? r.json() : null), ]); } catch (e) { container.innerHTML = `

Failed to load settings.

`; return; } const notifSection = buildNotifSection(notifPrefs); container.innerHTML = `

General

Billing Behavior

Backup

${notifSection}
`; document.getElementById('save-settings-btn').onclick = async () => { const data = { currency: document.getElementById('s-currency').value, date_format: document.getElementById('s-date-format').value, grace_period_days: document.getElementById('s-grace').value, backup_enabled: document.getElementById('s-backup-enabled').checked ? 'true' : 'false', backup_frequency_days: document.getElementById('s-backup-freq').value, backup_keep_count: document.getElementById('s-backup-keep').value, }; try { await API.saveSettings(data); showToast('Settings saved', 'success'); } catch (err) { showToast('Error: ' + err.message, 'error'); } }; // Notification save (only wired if section exists) const notifForm = document.getElementById('notif-user-form'); if (notifForm) { notifForm.onsubmit = async (e) => { e.preventDefault(); const btn = notifForm.querySelector('[type="submit"]'); btn.disabled = true; try { const res = await fetch('/api/notifications/me', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ notification_email: document.getElementById('n-email').value.trim(), notifications_enabled:document.getElementById('n-enabled').checked, notify_3d: document.getElementById('n-3d').checked, notify_1d: document.getElementById('n-1d').checked, notify_due: document.getElementById('n-due').checked, notify_overdue: document.getElementById('n-overdue').checked, }), }); if (!res.ok) throw new Error((await res.json()).error); showToast('Notification preferences saved', 'success'); } catch (err) { showToast('Error: ' + err.message, 'error'); } finally { btn.disabled = false; } }; // Toggle field visibility based on enabled checkbox const toggle = () => { const on = document.getElementById('n-enabled').checked; document.getElementById('n-options').style.opacity = on ? '1' : '.4'; document.getElementById('n-options').style.pointerEvents = on ? '' : 'none'; }; document.getElementById('n-enabled').addEventListener('change', toggle); toggle(); } } function buildNotifSection(p) { if (!p) return ''; // API call failed, skip silently if (!p.smtp_enabled) { return `

Notifications

Email notifications have not been configured by the admin.

`; } if (!p.allow_user_config) { return `

Notifications

Email notifications are enabled and managed by the admin. Your bills will generate reminders automatically.

`; } // Full user-configurable notification section const chk = (id, label, val) => ``; return `

Notifications

${chk('n-3d', '3 days before due', p.notify_3d)} ${chk('n-1d', '1 day before due', p.notify_1d)} ${chk('n-due', 'On the day it\'s due', p.notify_due)} ${chk('n-overdue', 'Daily while overdue', p.notify_overdue)}
`; } function escHtml(s) { return String(s || '').replace(/&/g,'&').replace(//g,'>').replace(/"/g,'"'); } return { init }; })();