Skip to content

Commit 8541bc6

Browse files
Update notification.js
1 parent a1e65a9 commit 8541bc6

1 file changed

Lines changed: 18 additions & 30 deletions

File tree

public/js/modules/notification.js

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,6 @@ export const addOrRemoveNotification = async (programDetails) => {
127127
async () => {
128128
const success = await deleteProgramNotification(existingNotification.id);
129129
if (success) {
130-
// Notify other tabs via BroadcastChannel after a successful local action
131130
notificationChannel.postMessage({ type: 'refresh-notifications' });
132131
guideState.userNotifications = guideState.userNotifications.filter(n => n.id !== existingNotification.id);
133132
renderNotifications();
@@ -165,9 +164,7 @@ export const addOrRemoveNotification = async (programDetails) => {
165164
}
166165
}
167166

168-
// --- **FIX 1: Robust lead time calculation** ---
169-
// Ensure notificationLeadTime is a valid number, default to 10 if not.
170-
const notificationLeadTime = parseInt(guideState.settings.notificationLeadTime, 10);
167+
let notificationLeadTime = parseInt(guideState.settings.notificationLeadTime, 10);
171168
if (isNaN(notificationLeadTime)) {
172169
console.warn(`[NOTIF] Invalid 'notificationLeadTime' in settings: ${guideState.settings.notificationLeadTime}. Defaulting to 10.`);
173170
notificationLeadTime = 10;
@@ -178,7 +175,6 @@ export const addOrRemoveNotification = async (programDetails) => {
178175

179176
const programStartTime = new Date(programDetails.programStart);
180177

181-
// --- **FIX 2: Validate program start time** ---
182178
if (isNaN(programStartTime.getTime())) {
183179
console.error('[NOTIF_ERROR] The program start time is invalid.', programDetails.programStart);
184180
showNotification('Cannot set notification due to an invalid program start time.', true);
@@ -208,8 +204,7 @@ export const addOrRemoveNotification = async (programDetails) => {
208204
const addedNotification = await addProgramNotification(newNotificationData);
209205
if (addedNotification) {
210206
notificationChannel.postMessage({ type: 'refresh-notifications' });
211-
// Manually add the lead time to the object for immediate correct rendering
212-
const completeNotification = { ...addedNotification, status: 'pending', notificationLeadTime: notificationLeadTime };
207+
const completeNotification = { ...addedNotification, status: 'pending' };
213208
guideState.userNotifications.push(completeNotification);
214209

215210
renderNotifications();
@@ -223,8 +218,7 @@ export const addOrRemoveNotification = async (programDetails) => {
223218
};
224219

225220
/**
226-
* Checks if a given program has ANY notification scheduled (pending, sent, or expired).
227-
* This makes the visual indicator in the guide persistent.
221+
* Checks if a given program has ANY notification scheduled.
228222
* @param {object} program - The program object.
229223
* @param {string} channelId - The ID of the channel the program belongs to.
230224
* @returns {object|null} The notification object if found, otherwise null.
@@ -251,17 +245,14 @@ export const renderNotifications = () => {
251245
UIElements.noNotificationsMessage.classList.toggle('hidden', upcomingNotifications.length > 0);
252246

253247
notificationListEl.innerHTML = upcomingNotifications.map(notif => {
254-
// --- **FIX 3: Robust rendering to prevent crashes and "undefined" bug** ---
255248
const programStartTime = new Date(notif.programStart);
256249
const notificationTime = new Date(notif.scheduledTime);
257250

258-
// If dates are invalid, skip rendering this item to prevent crashes.
259251
if (isNaN(programStartTime.getTime()) || isNaN(notificationTime.getTime())) {
260252
console.error('[NOTIF_RENDER] Skipping notification with invalid date:', notif);
261253
return '';
262254
}
263255

264-
// Calculate lead time directly from timestamps for accuracy.
265256
const leadTimeMinutes = Math.round((programStartTime.getTime() - notificationTime.getTime()) / 60000);
266257

267258
const formattedProgramTime = programStartTime.toLocaleString([], { weekday: 'short', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false });
@@ -298,16 +289,21 @@ export const renderPastNotifications = () => {
298289
if (!pastNotificationsListEl) return;
299290

300291
const now = new Date();
292+
293+
// --- **FIX: Correctly filter for past notifications based on the new server logic** ---
294+
// A notification is considered "past" if its scheduled time is in the past,
295+
// regardless of the master 'status', which is now derived on the server.
301296
const pastNotifications = guideState.userNotifications
302-
.filter(n => n.status === 'sent' || n.status === 'expired')
303-
.sort((a, b) => new Date(b.triggeredAt || b.notificationTime) - new Date(a.triggeredAt || a.notificationTime))
304-
.slice(0, 10);
297+
.filter(n => new Date(n.scheduledTime).getTime() <= now.getTime())
298+
.sort((a, b) => new Date(b.scheduledTime) - new Date(a.scheduledTime)) // Sort by when it was supposed to trigger
299+
.slice(0, 20); // Show a few more past notifications
305300

306301
UIElements.noPastNotificationsMessage.classList.toggle('hidden', pastNotifications.length > 0);
307302

308303
pastNotificationsListEl.innerHTML = pastNotifications.map(notif => {
309304
const programStartTime = new Date(notif.programStart);
310-
const notificationTriggerTime = new Date(notif.triggeredAt || notif.notificationTime);
305+
// Use the scheduledTime for display consistency, fallback to triggeredAt if needed.
306+
const notificationTriggerTime = new Date(notif.triggeredAt || notif.scheduledTime);
311307

312308
if (isNaN(programStartTime.getTime()) || isNaN(notificationTriggerTime.getTime())) {
313309
return '';
@@ -317,10 +313,14 @@ export const renderPastNotifications = () => {
317313
const formattedTriggerTime = notificationTriggerTime.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', hour12: false });
318314

319315
let statusText = '';
316+
// The status from the server is now reliable for display.
320317
if (notif.status === 'sent') {
321318
statusText = `Notified at ${formattedTriggerTime}`;
322319
} else if (notif.status === 'expired') {
323320
statusText = `Expired at ${formattedTriggerTime}`;
321+
} else {
322+
// This case handles notifications that were due but might not have a final status yet.
323+
statusText = `Should have been notified at ${formattedTriggerTime}`;
324324
}
325325

326326
return `
@@ -362,7 +362,6 @@ const setupNotificationListEventListeners = () => {
362362
async () => {
363363
const success = await deleteProgramNotification(notificationId);
364364
if (success) {
365-
// Notify other tabs via BroadcastChannel after a successful local action
366365
notificationChannel.postMessage({ type: 'refresh-notifications' });
367366
guideState.userNotifications = guideState.userNotifications.filter(n => n.id != notificationId);
368367
renderNotifications();
@@ -399,11 +398,9 @@ export const navigateToProgramInGuide = async (channelId, programStart, programI
399398
const stableChannelIdSuffix = channelId.includes('_') ? '_' + channelId.split('_').pop() : channelId;
400399
console.log(`[NOTIF_NAV] Using stable channel ID suffix for matching: "${stableChannelIdSuffix}"`);
401400

402-
// 1. Navigate to the guide page
403401
navigate('/tvguide');
404402
await new Promise(resolve => setTimeout(resolve, 50));
405403

406-
// 2. Adjust date if necessary
407404
const targetProgramStart = new Date(programStart);
408405
const currentGuideDate = new Date(guideState.currentDate);
409406
currentGuideDate.setHours(0, 0, 0, 0);
@@ -414,7 +411,6 @@ export const navigateToProgramInGuide = async (channelId, programStart, programI
414411
await handleSearchAndFilter(true);
415412
}
416413

417-
// 3. Scroll vertically and wait for the channel row to be rendered
418414
console.log('[NOTIF_DEBUG] Awaiting scrollToChannel to confirm vertical scroll and render.');
419415
const channelScrolledAndRendered = await scrollToChannel(stableChannelIdSuffix);
420416

@@ -424,17 +420,14 @@ export const navigateToProgramInGuide = async (channelId, programStart, programI
424420
}
425421
console.log('[NOTIF_DEBUG] scrollToChannel confirmed channel row is rendered.');
426422

427-
// 4. Now that the row is rendered, find the program element directly with a FRESH query.
428-
// This is crucial to avoid stale DOM references after potential re-renders from virtualization.
429423
const currentChannelElement = UIElements.guideGrid.querySelector(`.channel-info[data-id$="${stableChannelIdSuffix}"]`);
430424
if (!currentChannelElement) {
431425
console.error(`[NOTIF_DEBUG] CRITICAL: Channel element with suffix ${stableChannelIdSuffix} not found after scrollToChannel resolved true.`);
432426
showNotification("An unexpected error occurred while locating the channel.", true);
433427
return;
434428
}
435-
const currentDynamicChannelId = currentChannelElement.dataset.id; // Get the full dynamic ID
429+
const currentDynamicChannelId = currentChannelElement.dataset.id;
436430

437-
// Use a more specific selector now that we have the actual rendered channel's ID
438431
const programElement = UIElements.guideGrid.querySelector(
439432
`.programme-item[data-prog-start="${programStart}"][data-channel-id="${currentDynamicChannelId}"]`
440433
);
@@ -447,14 +440,11 @@ export const navigateToProgramInGuide = async (channelId, programStart, programI
447440

448441
console.log('[NOTIF_DEBUG] Program element found. Proceeding with centering and opening details.');
449442

450-
// --- 5. Centering and Opening Logic ---
451443
const guideContainer = UIElements.guideContainer;
452444

453-
// Use getBoundingClientRect for accurate positioning relative to the viewport
454445
const programRect = programElement.getBoundingClientRect();
455446
const containerRect = guideContainer.getBoundingClientRect();
456447

457-
// Calculate the desired scroll position to center the element
458448
const desiredScrollTop = guideContainer.scrollTop + programRect.top - containerRect.top - (containerRect.height / 2) + (programRect.height / 2);
459449
const desiredScrollLeft = guideContainer.scrollLeft + programRect.left - containerRect.left - (containerRect.width / 2) + (programRect.width / 2);
460450

@@ -464,13 +454,11 @@ export const navigateToProgramInGuide = async (channelId, programStart, programI
464454
behavior: 'smooth'
465455
});
466456

467-
// Wait for the smooth scroll to have an effect before opening details
468457
setTimeout(() => {
469458
console.log('[NOTIF_DEBUG] Calling openProgramDetails directly.');
470-
// Pass the re-queried programElement to ensure it's a live DOM node
471459
openProgramDetails(programElement);
472460

473461
programElement.classList.add('highlighted-search');
474462
setTimeout(() => { programElement.classList.remove('highlighted-search'); }, 2500);
475-
}, 300); // 300ms should be enough for the scroll animation to start
463+
}, 300);
476464
};

0 commit comments

Comments
 (0)