/* ─────────────────────────────────────────────
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 = `
| Notification Type |
In-App |
Email |
${html}
`;
// 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);