/* notifications.js - small admin notification panel Requires jQuery. */ (function($){ function timeAgo(ts){ var seconds = Math.floor((Date.now() - (new Date(ts)).getTime())/1000); if (seconds < 60) return seconds + 's ago'; var minutes = Math.floor(seconds/60); if (minutes < 60) return minutes + 'm ago'; var hours = Math.floor(minutes/60); if (hours < 24) return hours + 'h ago'; var days = Math.floor(hours/24); return days + 'd ago'; } function renderNotifications(list){ var $panel = $('#notif-panel'); $panel.empty(); if (!list || list.length === 0) { $panel.append('
No notifications
'); return; } list.forEach(function(n){ var actorAvatar = (n.data && n.data.actor_avatar) ? n.data.actor_avatar : 'assets/images/icons/user.png'; // Prefer the notification payload title (n.data.title). Do NOT fall back to the event string. var title = (n.data && n.data.title) ? n.data.title : 'Notification'; var time = n.time_created || new Date().toISOString(); var read = (n.read_by && Array.isArray(n.read_by) && n.read_by.length>0); var $item = $('
'); $item.append('avatar'); var $body = $('
'); $body.append('
'+escapeHtml(title)+'
'); $body.append('
'+timeAgo(time)+'
'); $item.append($body); $item.append(''); $panel.append($item); }); } function escapeHtml(str) { if (!str) return ''; return String(str).replace(/[&<>"'`]/g, function(s){ return {'&':'&','<':'<','>':'>','"':'"',"'":"'",'`':'`'}[s]; }); } function fetchAndRender(adminId){ $.getJSON('/src/api/notifications.php', { action: 'fetch' }, function(resp){ if (resp && resp.success) { renderNotifications(resp.notifications); if (resp.unread_count && resp.unread_count > 0) { $('#notif-badge').text(resp.unread_count).show(); } else { $('#notif-badge').hide(); } } }); } // Fetch only unread count (used on page load so badge shows without opening panel) function fetchUnreadCount(){ $.getJSON('/src/api/notifications.php', { action: 'fetch' }, function(resp){ if (resp && resp.success) { if (resp.unread_count && resp.unread_count > 0) { $('#notif-badge').text(resp.unread_count).show(); } else { $('#notif-badge').hide(); } } }); } $(function(){ var $container = $('.notif-avatar-container'); if (!$container.length) return; var adminId = $container.data('admin-id'); // ensure badge is populated on page load fetchUnreadCount(); $container.on('click', function(e){ e.preventDefault(); $('#notif-panel').toggle(); if ($('#notif-panel').is(':visible')) fetchAndRender(adminId); }); $(document).on('click', '.notif-close', function(e){ e.stopPropagation(); var $it = $(this).closest('.notif-item'); var id = $it.data('id'); if (!id) return; $.post('/src/api/notifications.php', { action: 'mark_read', id: id }, function(resp){ if (resp && resp.success) { $it.remove(); // refresh count fetchAndRender(adminId); } }, 'json'); }); // click outside to close $(document).on('click', function(e){ if (!$(e.target).closest('#notif-panel, .notif-avatar-container').length) { $('#notif-panel').hide(); } }); }); })(jQuery);