document.addEventListener('DOMContentLoaded', function() { // Initialize tooltips const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl); }); // Initialize variables let currentPage = 1; let totalPages = parseInt(document.getElementById('totalPages').textContent) || 1; let isFetching = false; // Get filter elements const notifTypeFilter = document.getElementById('notifTypeFilter'); const dateRangeFilter = document.getElementById('dateRangeFilter'); const clearFiltersBtn = document.getElementById('clearFilters'); const markAllReadBtn = document.getElementById('markAllRead'); // Get pagination elements const prevPageBtn = document.getElementById('prevPage'); const nextPageBtn = document.getElementById('nextPage'); const currentPageSpan = document.getElementById('currentPage'); const totalPagesSpan = document.getElementById('totalPages'); const notifsTableBody = document.getElementById('notifsTableBody'); // Notification details modal const notifDetailsModal = document.getElementById('notifDetailsModal'); const notifDetailsContent = document.getElementById('notifDetailsContent'); // Get CSRF token from meta tag const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); // Function to update URL with current filters function updateURL() { const params = new URLSearchParams(window.location.search); params.set('notif_type', notifTypeFilter.value); params.set('date_range', dateRangeFilter.value); params.set('page', currentPage); window.history.replaceState({}, '', `${window.location.pathname}?${params.toString()}`); } // Function to fetch notifications async function fetchNotifications() { if (isFetching) return; isFetching = true; // Show loading state notifsTableBody.innerHTML = 'Loading...'; const params = new URLSearchParams({ notif_type: notifTypeFilter.value, date_range: dateRangeFilter.value, page: currentPage, ajax: 'true' }); try { const response = await fetch(`${window.location.pathname}?${params.toString()}`, { headers: { 'X-Requested-With': 'XMLHttpRequest' } }); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); updateNotificationsTable(data.notifications); updatePagination(data.total_pages, data.current_page); // Reinitialize tooltips after updating the table const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')); tooltipTriggerList.map(function (tooltipTriggerEl) { return new bootstrap.Tooltip(tooltipTriggerEl); }); } catch (error) { console.error('Error fetching notifications:', error); notifsTableBody.innerHTML = 'Error loading notifications'; } finally { isFetching = false; } } // Function to get notification type badge function getNotifTypeBadge(type) { const badges = { 'account_created': 'Account Created', 'password_reset': 'Password Reset', 'account_deleted': 'Account Deleted', 'account_updated': 'Account Updated', 'room_invite': 'Room Invite', 'room_invite_removed': 'Room Invite Removed', 'conversation_invite': 'Conversation Invite', 'conversation_invite_removed': 'Conversation Invite Removed', 'conversation_message': 'Conversation Message' }; return badges[type] || `${type}`; } // Function to load notification details function loadNotifDetails(notifId) { fetch(`/api/notifications/${notifId}`) .then(response => response.json()) .then(data => { const detailsContent = document.getElementById('notifDetailsContent'); if (data.details) { detailsContent.textContent = JSON.stringify(data.details, null, 2); } else { detailsContent.textContent = 'No additional details available'; } }) .catch(error => { console.error('Error loading notification details:', error); document.getElementById('notifDetailsContent').textContent = 'Error loading notification details'; }); } // Function to update notification counter function updateNotificationCounter() { counter.textContent = document.querySelector('.nav-link[href*="notifications"] .badge'); } // Function to mark notification as read async function markAsRead(notifId) { try { const response = await fetch(`/api/notifications/${notifId}/read`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken, 'X-Requested-With': 'XMLHttpRequest' } }); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); if (data.success) { // Update the UI to show the notification as read const notifRow = document.querySelector(`tr[data-notif-id="${notifId}"]`); if (notifRow) { notifRow.classList.remove('table-warning'); const statusCell = notifRow.querySelector('td:nth-last-child(2)'); if (statusCell) { statusCell.innerHTML = 'Read'; } const actionsCell = notifRow.querySelector('td:last-child'); if (actionsCell) { const markReadBtn = actionsCell.querySelector('.mark-read'); if (markReadBtn) { markReadBtn.remove(); } } } // Update the notification counter updateNotificationCounter(); } } catch (error) { console.error('Error marking notification as read:', error); } } // Function to delete notification async function deleteNotification(notifId) { try { const response = await fetch(`/api/notifications/${notifId}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken, 'X-Requested-With': 'XMLHttpRequest' } }); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); if (data.success) { // Remove the notification row from the table const notifRow = document.querySelector(`tr[data-notif-id="${notifId}"]`); if (notifRow) { // Only update counter if the notification was unread if (notifRow.classList.contains('table-warning')) { updateNotificationCounter(); } notifRow.remove(); } } } catch (error) { console.error('Error deleting notification:', error); } } // Function to mark all notifications as read async function markAllAsRead() { try { const response = await fetch('/api/notifications/mark-all-read', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': csrfToken, 'X-Requested-With': 'XMLHttpRequest' } }); if (!response.ok) { throw new Error('Network response was not ok'); } const data = await response.json(); if (data.success) { // Update all notifications to show as read document.querySelectorAll('tr[data-notif-id]').forEach(row => { row.classList.remove('table-warning'); const statusCell = row.querySelector('td:nth-last-child(2)'); if (statusCell) { statusCell.innerHTML = 'Read'; } const actionsCell = row.querySelector('td:last-child'); if (actionsCell) { const markReadBtn = actionsCell.querySelector('.mark-read'); if (markReadBtn) { markReadBtn.remove(); } } }); // Remove the notification counter const counter = document.querySelector('.nav-link[href*="notifications"] .badge'); if (counter) { counter.remove(); } } } catch (error) { console.error('Error marking all notifications as read:', error); } } // Function to handle notification action clicks function handleNotificationAction(notifId, actionType) { // Mark the notification as read when an action is taken markAsRead(notifId); // Additional handling for specific action types can be added here if (actionType === 'view_room' || actionType === 'view_conversation') { // The link will handle the navigation automatically return true; } } // Function to attach event listeners function attachEventListeners() { // Mark as read buttons document.querySelectorAll('.mark-read').forEach(btn => { btn.addEventListener('click', (e) => { const notifId = e.target.closest('.mark-read').dataset.notifId; markAsRead(notifId); }); }); // Delete buttons document.querySelectorAll('.delete-notif').forEach(btn => { btn.addEventListener('click', (e) => { const notifId = e.target.closest('.delete-notif').dataset.notifId; deleteNotification(notifId); }); }); // View details buttons document.querySelectorAll('[data-bs-target="#notifDetailsModal"]').forEach(btn => { btn.addEventListener('click', (e) => { const notifId = e.target.closest('[data-notif-id]').dataset.notifId; loadNotifDetails(notifId); }); }); // Action buttons (View Room, View Conversation) document.querySelectorAll('.btn-group a').forEach(btn => { btn.addEventListener('click', (e) => { const notifId = e.target.closest('tr').dataset.notifId; const actionType = btn.classList.contains('fa-door-open') ? 'view_room' : 'view_conversation'; handleNotificationAction(notifId, actionType); }); }); } // Initialize event listeners attachEventListeners(); // Add event listeners for filters notifTypeFilter.addEventListener('change', () => { currentPage = 1; fetchNotifications(); updateURL(); }); dateRangeFilter.addEventListener('change', () => { currentPage = 1; fetchNotifications(); updateURL(); }); clearFiltersBtn.addEventListener('click', () => { notifTypeFilter.value = ''; dateRangeFilter.value = '7d'; currentPage = 1; fetchNotifications(); updateURL(); }); markAllReadBtn.addEventListener('click', markAllAsRead); // Add event listeners for pagination prevPageBtn.addEventListener('click', () => { if (currentPage > 1) { currentPage--; fetchNotifications(); updateURL(); } }); nextPageBtn.addEventListener('click', () => { if (currentPage < totalPages) { currentPage++; fetchNotifications(); updateURL(); } }); });