mirror of
https://github.com/Retropex/custom-ocean.xyz-dashboard.git
synced 2025-05-12 19:20:45 +02:00
406 lines
12 KiB
JavaScript
406 lines
12 KiB
JavaScript
"use strict";
|
|
|
|
// Global variables
|
|
let currentFilter = "all";
|
|
let currentOffset = 0;
|
|
let pageSize = 20;
|
|
let hasMoreNotifications = true;
|
|
let isLoading = false;
|
|
|
|
// Initialize when document is ready
|
|
$(document).ready(function () {
|
|
console.log("Notification page initializing...");
|
|
|
|
// 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);
|
|
});
|
|
|
|
// 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: function (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: function (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();
|
|
}
|
|
}
|
|
// Update notification timestamps to relative time
|
|
function updateNotificationTimestamps() {
|
|
$('.notification-item').each(function () {
|
|
const timestampStr = $(this).attr('data-timestamp');
|
|
if (timestampStr) {
|
|
const timestamp = new Date(timestampStr);
|
|
const relativeTime = formatTimestamp(timestamp);
|
|
$(this).find('.notification-time').text(relativeTime);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Show loading indicator
|
|
function showLoading() {
|
|
if (currentOffset === 0) {
|
|
// First page load, show loading message
|
|
$('#notifications-container').html('<div class="loading-message">Loading notifications<span class="terminal-cursor"></span></div>');
|
|
} else {
|
|
// Pagination load, show loading below
|
|
$('#load-more').prop('disabled', true).text('Loading...');
|
|
}
|
|
}
|
|
|
|
// Show error message
|
|
function showError(message) {
|
|
$('#notifications-container').html(`<div class="error-message">${message}</div>`);
|
|
$('#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(function (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');
|
|
}
|
|
|
|
// Append "Z" to indicate UTC if not present
|
|
let utcTimestampStr = notification.timestamp;
|
|
if (!utcTimestampStr.endsWith('Z')) {
|
|
utcTimestampStr += 'Z';
|
|
}
|
|
const utcDate = new Date(utcTimestampStr);
|
|
|
|
// Convert UTC date to Los Angeles time with a timezone name for clarity
|
|
const fullTimestamp = utcDate.toLocaleString('en-US', {
|
|
timeZone: 'America/Los_Angeles',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
timeZoneName: 'short'
|
|
});
|
|
|
|
// Append the full timestamp to the notification message
|
|
const messageWithTimestamp = `${notification.message}<br><span class="full-timestamp">${fullTimestamp}</span>`;
|
|
element.find('.notification-message').html(messageWithTimestamp);
|
|
|
|
// Set metadata for relative time display
|
|
element.find('.notification-time').text(formatTimestamp(utcDate));
|
|
element.find('.notification-category').text(notification.category);
|
|
|
|
// Set up action buttons
|
|
element.find('.mark-read-button').on('click', function (e) {
|
|
e.stopPropagation();
|
|
markAsRead(notification.id);
|
|
});
|
|
element.find('.delete-button').on('click', function (e) {
|
|
e.stopPropagation();
|
|
deleteNotification(notification.id);
|
|
});
|
|
|
|
// Hide mark as read button if already read
|
|
if (notification.read) {
|
|
element.find('.mark-read-button').hide();
|
|
}
|
|
|
|
return element;
|
|
}
|
|
|
|
// Format timestamp as relative time
|
|
function formatTimestamp(timestamp) {
|
|
const now = new Date();
|
|
const diffMs = now - timestamp;
|
|
const diffSec = Math.floor(diffMs / 1000);
|
|
const diffMin = Math.floor(diffSec / 60);
|
|
const diffHour = Math.floor(diffMin / 60);
|
|
const diffDay = Math.floor(diffHour / 24);
|
|
|
|
if (diffSec < 60) {
|
|
return "just now";
|
|
} else if (diffMin < 60) {
|
|
return `${diffMin}m ago`;
|
|
} else if (diffHour < 24) {
|
|
return `${diffHour}h ago`;
|
|
} else if (diffDay < 30) {
|
|
return `${diffDay}d ago`;
|
|
} else {
|
|
// Format as date for older notifications
|
|
return timestamp.toLocaleDateString('en-US', { timeZone: 'America/Los_Angeles' });
|
|
}
|
|
}
|
|
|
|
// Mark a notification as read
|
|
function markAsRead(notificationId) {
|
|
$.ajax({
|
|
url: "/api/notifications/mark_read",
|
|
method: "POST",
|
|
data: JSON.stringify({ notification_id: notificationId }),
|
|
contentType: "application/json",
|
|
success: function (data) {
|
|
// Update UI
|
|
$(`[data-id="${notificationId}"]`).attr('data-read', 'true');
|
|
$(`[data-id="${notificationId}"]`).find('.mark-read-button').hide();
|
|
|
|
// Update unread badge
|
|
updateUnreadBadge(data.unread_count);
|
|
},
|
|
error: function (xhr, status, error) {
|
|
console.error("Error marking notification as read:", error);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Mark all notifications as read
|
|
function markAllAsRead() {
|
|
$.ajax({
|
|
url: "/api/notifications/mark_read",
|
|
method: "POST",
|
|
data: JSON.stringify({}),
|
|
contentType: "application/json",
|
|
success: function (data) {
|
|
// Update UI
|
|
$('.notification-item').attr('data-read', 'true');
|
|
$('.mark-read-button').hide();
|
|
|
|
// Update unread badge
|
|
updateUnreadBadge(0);
|
|
},
|
|
error: function (xhr, status, error) {
|
|
console.error("Error marking all notifications as read:", error);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Delete a notification
|
|
function deleteNotification(notificationId) {
|
|
$.ajax({
|
|
url: "/api/notifications/delete",
|
|
method: "POST",
|
|
data: JSON.stringify({ notification_id: notificationId }),
|
|
contentType: "application/json",
|
|
success: function (data) {
|
|
// Remove from UI with animation
|
|
$(`[data-id="${notificationId}"]`).fadeOut(300, function () {
|
|
$(this).remove();
|
|
|
|
// Check if container is empty now
|
|
if ($('#notifications-container').children().length === 0) {
|
|
$('#notifications-container').html($('#empty-template').html());
|
|
$('#load-more').hide();
|
|
}
|
|
});
|
|
|
|
// Update unread badge
|
|
updateUnreadBadge(data.unread_count);
|
|
},
|
|
error: function (xhr, status, error) {
|
|
console.error("Error deleting notification:", error);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Clear read notifications
|
|
function clearReadNotifications() {
|
|
if (!confirm("Are you sure you want to clear all read notifications?")) {
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: "/api/notifications/clear",
|
|
method: "POST",
|
|
data: JSON.stringify({
|
|
// Special parameter to clear only read notifications
|
|
read_only: true
|
|
}),
|
|
contentType: "application/json",
|
|
success: function (data) {
|
|
// Reload notifications
|
|
resetAndLoadNotifications();
|
|
},
|
|
error: function (xhr, status, error) {
|
|
console.error("Error clearing read notifications:", error);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Clear all notifications
|
|
function clearAllNotifications() {
|
|
if (!confirm("Are you sure you want to clear ALL notifications? This cannot be undone.")) {
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: "/api/notifications/clear",
|
|
method: "POST",
|
|
data: JSON.stringify({}),
|
|
contentType: "application/json",
|
|
success: function (data) {
|
|
// Reload notifications
|
|
resetAndLoadNotifications();
|
|
},
|
|
error: function (xhr, status, error) {
|
|
console.error("Error clearing all notifications:", error);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Update unread badge
|
|
function updateUnreadBadge(count) {
|
|
$('#unread-badge').text(count);
|
|
|
|
// Add special styling if unread
|
|
if (count > 0) {
|
|
$('#unread-badge').addClass('has-unread');
|
|
} else {
|
|
$('#unread-badge').removeClass('has-unread');
|
|
}
|
|
}
|
|
|
|
// Update unread count from API
|
|
function updateUnreadCount() {
|
|
$.ajax({
|
|
url: "/api/notifications/unread_count",
|
|
method: "GET",
|
|
success: function (data) {
|
|
updateUnreadBadge(data.unread_count);
|
|
},
|
|
error: function (xhr, status, error) {
|
|
console.error("Error updating unread count:", error);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Start polling for unread count
|
|
function startUnreadCountPolling() {
|
|
// Update every 30 seconds
|
|
setInterval(updateUnreadCount, 30000);
|
|
}
|