/* ───────────────────────────────────────────── Notification Preferences (v0.20.0 Phase 3) Settings → Notifications tab ───────────────────────────────────────────── */ // eslint-disable-next-line no-unused-vars // // Exports: window.NotifPrefs const NotifPrefs = { _loaded: false, _prefs: [], // Known notification types for the UI _types: [ { key: 'kb.ready', label: 'Knowledge base ready' }, { key: 'kb.error', label: 'Knowledge base error' }, { key: 'role.fallback', label: 'Model fallback' }, { key: 'grant.changed', label: 'Group membership change' }, { key: '*', label: 'Default (all others)' }, ], async load() { try { this._prefs = await API.listNotifPrefs() || []; } catch (e) { console.warn('[notif-prefs] failed to load:', e.message); this._prefs = []; } this._loaded = true; this.render(); }, render() { const container = document.getElementById('notifPrefsBody'); if (!container) return; const prefMap = {}; for (const p of this._prefs) { prefMap[p.type] = p; } let html = ''; for (const t of this._types) { const p = prefMap[t.key]; const inApp = p ? p.in_app : true; const email = p ? p.email : false; html += ` ${esc(t.label)} `; } container.innerHTML = `${html}
Notification Type In-App Email
`; // Attach change listeners container.querySelectorAll('.notif-pref-row').forEach(row => { const type = row.dataset.type; row.querySelector('.notif-pref-inapp').addEventListener('change', (e) => { this._save(type, { in_app: e.target.checked }); }); row.querySelector('.notif-pref-email').addEventListener('change', (e) => { this._save(type, { email: e.target.checked }); }); }); }, async _save(type, patch) { try { await API.setNotifPref(type, patch); // Update cache const existing = this._prefs.find(p => p.type === type); if (existing) { Object.assign(existing, patch); } else { this._prefs.push({ type, in_app: true, email: false, ...patch }); } } catch (e) { UI.toast('Failed to save preference', 'error'); this.render(); // revert checkboxes } }, }; // ── Admin SMTP UI helpers ─────────────────── // Called from index.html onclick // eslint-disable-next-line no-unused-vars NotifPrefs._testEmail = async function() { const status = document.getElementById('smtpTestStatus'); const btn = document.getElementById('adminSmtpTestBtn'); if (!status || !btn) return; btn.disabled = true; status.textContent = 'Sending…'; status.className = 'smtp-test-status'; try { const result = await API.adminTestEmail(); status.textContent = `✓ Sent to ${result.sent_to}`; status.className = 'smtp-test-status success'; } catch (e) { status.textContent = '✗ ' + (e.message || 'Failed'); status.className = 'smtp-test-status error'; } finally { btn.disabled = false; } }; NotifPrefs._initAdminSmtp = function() { const toggle = document.getElementById('adminEmailEnabled'); const fields = document.getElementById('smtpConfigFields'); if (!toggle || !fields) return; toggle.addEventListener('change', () => { fields.style.display = toggle.checked ? '' : 'none'; }); }; NotifPrefs._loadAdminSmtp = function(cfg) { if (!cfg) return; const el = (id) => document.getElementById(id); if (cfg.email_enabled) el('adminEmailEnabled').checked = true; if (cfg.smtp_host) el('adminSmtpHost').value = cfg.smtp_host; if (cfg.smtp_port) el('adminSmtpPort').value = cfg.smtp_port; if (cfg.smtp_user) el('adminSmtpUser').value = cfg.smtp_user; // Don't populate password (security) if (cfg.smtp_from) el('adminSmtpFrom').value = cfg.smtp_from; if (cfg.smtp_tls != null) el('adminSmtpTls').value = String(cfg.smtp_tls); // Show/hide SMTP fields const fields = document.getElementById('smtpConfigFields'); if (fields) fields.style.display = cfg.email_enabled ? '' : 'none'; }; NotifPrefs._getAdminSmtp = function() { const el = (id) => document.getElementById(id); const config = { email_enabled: el('adminEmailEnabled')?.checked || false, smtp_host: el('adminSmtpHost')?.value?.trim() || '', smtp_port: parseInt(el('adminSmtpPort')?.value) || 587, smtp_user: el('adminSmtpUser')?.value?.trim() || '', smtp_from: el('adminSmtpFrom')?.value?.trim() || '', smtp_tls: el('adminSmtpTls')?.value === 'true', }; // Only include password if user typed something new const pw = el('adminSmtpPassword')?.value; if (pw) config.smtp_password = pw; return config; }; // ── Exports ───────────────────────────────── sb.ns('NotifPrefs', NotifPrefs);