/** * alerts-controller.js - Notification Management with Acknowledgement * =================================================================== * Handles polling, rendering, and acknowledging system alerts. * * Hardened for Enterprise MVC: * - Uses central `apiFetch` to automatically inherit HTTP-Only Cookies and CSRF headers. * - Relies on `fetch-wrapper.js` for 401 session expiration handling. * - Uses `SecurityUtils` for XSS-safe DOM generation. */ (function() { 'use strict'; // Safe HTML Escaping (Fallback to native if SecurityUtils isn't loaded yet) const escapeHTML = (text) => { if (window.SecurityUtils) return window.SecurityUtils.escapeHTML(text); const div = document.createElement('div'); div.textContent = text; return div.innerHTML; }; // ── Data Fetching ─────────────────────────────────────────────────────── async function loadAlerts() { // Only fetch if user is authenticated (UI hint check) const user = JSON.parse(localStorage.getItem('user') || 'null'); if (!user || (!user.email && !user.temp)) return; try { // Enterprise Architecture: Centralized apiFetch handles CSRF, Cookies, and 401s automatically const data = await window.apiFetch('/alerts?limit=20'); if (data.success) { renderAlerts(data.alerts || []); // Ensure we only count unacknowledged alerts for the badge const unread = data.alerts ? data.alerts.filter(a => !a.acknowledged).length : 0; updateBadgeCount(unread); } } catch (error) { // Silently fail for background polling to prevent spamming the user, // but log for debugging purposes. console.error('[Alerts] Background sync failed:', error); } } // ── Rendering ─────────────────────────────────────────────────────────── function renderAlerts(alerts) { const list = document.querySelector('.notifications-list'); if (!list) return; if (alerts.length === 0) { list.innerHTML = '
'; return; } list.innerHTML = alerts.map(alert => `${escapeHTML(alert.message)}
${escapeHTML(formatTimeAgo(alert.created_at))}