(() => {
const bell = document.querySelector('[data-notification-bell]');
const count = document.querySelector('[data-notification-count]');
if (!bell || !count) return;
let loading = false;
let checkedAt = 0;
const refresh = async () => {
if (loading || document.hidden || Date.now() - checkedAt < 5000) return;
loading = true;
try {
const response = await fetch('/-/notifications/unread', { headers: { Accept: 'application/json' }, cache: 'no-store' });
if (!response.ok) return;
const data = await response.json();
const unread = Number(data.unread_count) || 0;
const label = data.has_more ? '99+' : String(unread);
count.textContent = label;
count.hidden = unread === 0;
bell.setAttribute('aria-label', unread ? `Notifications (${label} unread)` : 'Notifications');
checkedAt = Date.now();
} catch (_) {
// Keep the last successful count if the connection is interrupted.
} finally {
loading = false;
}
};
window.addEventListener('pageshow', (event) => {
const navigation = performance.getEntriesByType('navigation')[0];
if (!event.persisted && (!navigation || navigation.type !== 'back_forward')) return;
if (document.querySelector('[data-notification-feed]')) {
window.location.reload();
} else {
checkedAt = 0;
refresh();
}
});
refresh();
setInterval(refresh, 60000);
window.addEventListener('focus', refresh);
document.addEventListener('visibilitychange', refresh);
})();