"use strict"; // Global variables let currentFilter = "all"; let currentOffset = 0; const pageSize = 20; let hasMoreNotifications = true; let isLoading = false; // Timezone configuration let dashboardTimezone = 'America/Los_Angeles'; // Default window.dashboardTimezone = dashboardTimezone; // Make it globally accessible // Initialize when document is ready $(document).ready(() => { console.log("Notification page initializing..."); // Fetch timezone configuration fetchTimezoneConfig(); // Set up filter buttons $('.filter-button').click(function () { $('.filter-button').removeClass('active'); $(this).addClass('active'); currentFilter = $(this).data('filter'); resetAndLoadNotifications(); }); // Set up action buttons $('#mark-all-read').click(markAllAsRead); $('#clear-read').click(clearReadNotifications); $('#clear-all').click(clearAllNotifications); $('#load-more').click(loadMoreNotifications); // Initial load of notifications loadNotifications(); // Start polling for unread count startUnreadCountPolling(); // Initialize BitcoinMinuteRefresh if available if (typeof BitcoinMinuteRefresh !== 'undefined' && BitcoinMinuteRefresh.initialize) { BitcoinMinuteRefresh.initialize(refreshNotifications); console.log("BitcoinMinuteRefresh initialized with refresh function"); } // Start periodic update of notification timestamps every 30 seconds setInterval(updateNotificationTimestamps, 30000); }); // Fetch timezone configuration from server function fetchTimezoneConfig() { return fetch('/api/timezone') .then(response => response.json()) .then(data => { if (data && data.timezone) { dashboardTimezone = data.timezone; window.dashboardTimezone = dashboardTimezone; // Make it globally accessible console.log(`Notifications page using timezone: ${dashboardTimezone}`); // Store in localStorage for future use try { localStorage.setItem('dashboardTimezone', dashboardTimezone); } catch (e) { console.error("Error storing timezone in localStorage:", e); } // Update all timestamps with the new timezone updateNotificationTimestamps(); return dashboardTimezone; } }) .catch(error => { console.error('Error fetching timezone config:', error); return null; }); } // Load notifications with current filter function loadNotifications() { if (isLoading) return; isLoading = true; showLoading(); const params = { limit: pageSize, offset: currentOffset }; if (currentFilter !== "all") { params.category = currentFilter; } $.ajax({ url: `/api/notifications?${$.param(params)}`, method: "GET", dataType: "json", success: (data) => { renderNotifications(data.notifications, currentOffset === 0); updateUnreadBadge(data.unread_count); // Update load more button state hasMoreNotifications = data.notifications.length === pageSize; $('#load-more').prop('disabled', !hasMoreNotifications); isLoading = false; }, error: (xhr, status, error) => { console.error("Error loading notifications:", error); showError("Failed to load notifications. Please try again."); isLoading = false; } }); } // Reset offset and load notifications function resetAndLoadNotifications() { currentOffset = 0; loadNotifications(); } // Load more notifications function loadMoreNotifications() { if (!hasMoreNotifications || isLoading) return; currentOffset += pageSize; loadNotifications(); } // Refresh notifications (for periodic updates) function refreshNotifications() { // Only refresh if we're on the first page if (currentOffset === 0) { resetAndLoadNotifications(); } else { // Just update the unread count updateUnreadCount(); } } // This refreshes all timestamps on the page periodically function updateNotificationTimestamps() { $('.notification-item').each(function () { const timestampStr = $(this).attr('data-timestamp'); if (timestampStr) { try { const timestamp = new Date(timestampStr); // Update relative time $(this).find('.notification-time').text(formatTimestamp(timestamp)); // Update full timestamp with configured timezone if ($(this).find('.full-timestamp').length) { const options = { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true, timeZone: window.dashboardTimezone || 'America/Los_Angeles' }; const fullTimestamp = timestamp.toLocaleString('en-US', options); $(this).find('.full-timestamp').text(fullTimestamp); } } catch (e) { console.error("Error updating timestamp:", e, timestampStr); } } }); } // Show loading indicator function showLoading() { if (currentOffset === 0) { // First page load, show loading message $('#notifications-container').html('
'); } else { // Pagination load, show loading below $('#load-more').prop('disabled', true).text('Loading...'); } } // Show error message function showError(message) { $('#notifications-container').html(` `); $('#load-more').hide(); } // Render notifications in the container function renderNotifications(notifications, isFirstPage) { const container = $('#notifications-container'); // If first page and no notifications if (isFirstPage && (!notifications || notifications.length === 0)) { container.html($('#empty-template').html()); $('#load-more').hide(); return; } // If first page, clear container if (isFirstPage) { container.empty(); } // Render each notification notifications.forEach(notification => { const notificationElement = createNotificationElement(notification); container.append(notificationElement); }); // Show/hide load more button $('#load-more').show().prop('disabled', !hasMoreNotifications); } // Create notification element from template function createNotificationElement(notification) { const template = $('#notification-template').html(); const element = $(template); // Set data attributes element.attr('data-id', notification.id) .attr('data-level', notification.level) .attr('data-category', notification.category) .attr('data-read', notification.read) .attr('data-timestamp', notification.timestamp); // Set icon based on level const iconElement = element.find('.notification-icon i'); switch (notification.level) { case 'success': iconElement.addClass('fa-check-circle'); break; case 'info': iconElement.addClass('fa-info-circle'); break; case 'warning': iconElement.addClass('fa-exclamation-triangle'); break; case 'error': iconElement.addClass('fa-times-circle'); break; default: iconElement.addClass('fa-bell'); } // Important: Do not append "Z" here, as that can cause timezone issues // Create a date object from the notification timestamp let notificationDate; try { // Parse the timestamp directly without modifications notificationDate = new Date(notification.timestamp); // Validate the date object - if invalid, try alternative approach if (isNaN(notificationDate.getTime())) { console.warn("Invalid date from notification timestamp, trying alternative format"); // Try adding Z to make it explicit UTC if not already ISO format if (!notification.timestamp.endsWith('Z') && !notification.timestamp.includes('+')) { notificationDate = new Date(notification.timestamp + 'Z'); } } } catch (e) { console.error("Error parsing notification date:", e); notificationDate = new Date(); // Fallback to current date } // Format the timestamp using the configured timezone const options = { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true, timeZone: window.dashboardTimezone || 'America/Los_Angeles' }; // Format full timestamp with configured timezone let fullTimestamp; try { fullTimestamp = notificationDate.toLocaleString('en-US', options); } catch (e) { console.error("Error formatting timestamp with timezone:", e); fullTimestamp = notificationDate.toLocaleString('en-US'); // Fallback without timezone } // Append the message and formatted timestamp const messageWithTimestamp = `${notification.message}