2
CARGANDO...
CARGANDO...
`).join('');
// Insertar antes del vacío placeholder
const empty = panel.querySelector('.notif-empty');
if (empty) empty.style.display = 'none';
const feed = document.getElementById('notifFeed');
if (feed) feed.innerHTML = items;
unreadCount = data.filter(n => !n.leida).length;
updateBadges();
} catch(e) { console.warn('Notificaciones no disponibles:', e); }
}
function timeAgo(str) {
const diff = Date.now() - new Date(str).getTime();
const m = Math.floor(diff / 60000);
if (m < 1) return 'Ahora';
if (m < 60) return `Hace ${m} min`;
const h = Math.floor(m / 60);
if (h < 24) return `Hace ${h}h`;
return `Hace ${Math.floor(h/24)} días`;
}
// ── MARCAR LEÍDA ─────────────────────────────────────────────
async function markRead(id) {
const item = document.getElementById('notif-' + id);
if (!item || !item.classList.contains('unread')) return;
item.classList.remove('unread');
const dot = item.querySelector('.notif-dot');
if (dot) dot.remove();
try {
await fetch(`${API}/notificaciones`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify({ ids: [id] }),
});
} catch(e) {}
unreadCount = Math.max(0, unreadCount - 1);
updateBadges();
}
async function markAllRead() {
const unread = document.querySelectorAll('.notif-item.unread');
unread.forEach(el => {
el.classList.remove('unread');
const dot = el.querySelector('.notif-dot');
if (dot) dot.remove();
});
try {
await fetch(`${API}/notificaciones`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify({ todas: true }),
});
} catch(e) {}
unreadCount = 0;
updateBadges();
}
function updateBadges() {
const badge = document.getElementById('badgeBandeja');
const topBadge = document.getElementById('topbarBadge');
const count = document.getElementById('notifCount');
const markBtn = document.getElementById('btnMarkAll');
if (badge) badge.textContent = unreadCount || '0';
if (topBadge) { topBadge.textContent = unreadCount || '0'; topBadge.style.background = unreadCount > 0 ? 'var(--danger)' : 'var(--border)'; }
if (count) count.textContent = unreadCount > 0 ? `${unreadCount} sin leer` : 'Todo leído';
if (markBtn) { markBtn.style.opacity = unreadCount > 0 ? '1' : '0.4'; markBtn.disabled = unreadCount === 0; }
}
// ── PREFERENCIAS ─────────────────────────────────────────────
let saveTimeout = null;
let prefsCache = {};
async function initPrefs() {
if (prefsCache.loaded) return;
try {
const res = await fetch(`${API}/notificaciones/preferencias`, { headers: { 'Authorization': `Bearer ${token}` } });
const data = await res.json();
if (data.error) return;
prefsCache = { ...data, loaded: true };
// Actualizar toggles en el DOM
Object.entries(data).forEach(([key, val]) => {
const el = document.querySelector(`[data-pref="${key}"]`);
if (el && el.type === 'checkbox') el.checked = !!val;
});
} catch(e) {}
}
function savePref(key, value) {
prefsCache[key] = value;
if (saveTimeout) clearTimeout(saveTimeout);
saveTimeout = setTimeout(async () => {
try {
await fetch(`${API}/notificaciones/preferencias`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
body: JSON.stringify({ [key]: value }),
});
} catch(e) {}
const msg = document.getElementById('saveConfirmMsg');
if (msg) { msg.style.opacity = '1'; setTimeout(() => { msg.style.opacity = '0'; }, 2500); }
}, 600);
}
initNotif();