From 7797c776394c3a911cb514132bc395fe65b89711 Mon Sep 17 00:00:00 2001 From: alma Date: Fri, 16 Jan 2026 10:22:28 +0100 Subject: [PATCH] Notifications corrections --- hooks/use-task-notifications.ts | 60 ++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/hooks/use-task-notifications.ts b/hooks/use-task-notifications.ts index 63f33d3..6576f93 100644 --- a/hooks/use-task-notifications.ts +++ b/hooks/use-task-notifications.ts @@ -82,7 +82,7 @@ export function useTaskNotifications() { }); // Helper function to parse date correctly (handles Leantime dates with Z) - const parseTaskDate = (dateStr: string | null): Date | null => { + const parseTaskDate = (dateStr: string | null, taskId?: string, taskTitle?: string): Date | null => { if (!dateStr) return null; // Leantime dates with 'Z' are actually local time stored as UTC @@ -93,7 +93,7 @@ export function useTaskNotifications() { const utcDate = new Date(dateStr); // Extract components from UTC date and create local date // This assumes the UTC date actually represents local time - return new Date( + const parsedDate = new Date( utcDate.getUTCFullYear(), utcDate.getUTCMonth(), utcDate.getUTCDate(), @@ -102,6 +102,23 @@ export function useTaskNotifications() { utcDate.getUTCSeconds(), utcDate.getUTCMilliseconds() ); + + console.log('[useTaskNotifications] 📅 Parsing Leantime date (Z -> local)', { + taskId, + taskTitle, + rawDate: dateStr, + utcComponents: { + year: utcDate.getUTCFullYear(), + month: utcDate.getUTCMonth() + 1, + day: utcDate.getUTCDate(), + hour: utcDate.getUTCHours(), + minute: utcDate.getUTCMinutes(), + }, + parsedLocal: parsedDate.toLocaleString('fr-FR', { timeZone: 'Europe/Paris' }), + parsedISO: parsedDate.toISOString(), + }); + + return parsedDate; } else if (dateStr.includes('T')) { // ISO format without Z - treat as local time return new Date(dateStr); @@ -132,7 +149,7 @@ export function useTaskNotifications() { } // Parse the notification date - const notificationDate = parseTaskDate(task.dateToFinish); + const notificationDate = parseTaskDate(task.dateToFinish, task.id, task.headline); if (!notificationDate || isNaN(notificationDate.getTime())) { console.log('[useTaskNotifications] ⏭️ Task has no valid date', { @@ -148,24 +165,43 @@ export function useTaskNotifications() { const timeUntilNotificationMinutes = Math.round(timeUntilNotification / 1000 / 60); const timeUntilNotificationSeconds = Math.round(timeUntilNotification / 1000); - // Notification window: within 2 minutes of the notification time (1 minute before to 1 minute after) - // This allows catching tasks that are due now or just became due - const notificationWindow = 60 * 1000; // 1 minute - const inNotificationWindow = - timeUntilNotification >= -notificationWindow && - timeUntilNotification <= notificationWindow; + // Check if task is due today + const today = new Date(); + const isDueToday = + notificationDate.getFullYear() === today.getFullYear() && + notificationDate.getMonth() === today.getMonth() && + notificationDate.getDate() === today.getDate(); + + // Notification window logic: + // - For tasks due today but already past due: notify if within 24 hours after due time + // - For tasks due today but not yet due: notify if within ±1 minute of due time + // - For future tasks: notify if within ±1 minute of due time + let inNotificationWindow = false; + + if (isDueToday && timeUntilNotification < 0) { + // Task is due today but already past due - notify if within 24 hours after + const hoursPastDue = Math.abs(timeUntilNotificationMinutes) / 60; + inNotificationWindow = hoursPastDue <= 24; + } else { + // Task is due today (not yet due) or future - notify if within ±1 minute + const notificationWindow = 60 * 1000; // 1 minute + inNotificationWindow = + timeUntilNotification >= -notificationWindow && + timeUntilNotification <= notificationWindow; + } console.log('[useTaskNotifications] ⏰ Checking task', { id: task.id, title: task.headline, source: task.source, rawDate: task.dateToFinish, - notificationDateLocal: notificationDate.toLocaleString('fr-FR'), - notificationDateISO: notificationDate.toISOString(), - nowLocal: now.toLocaleString('fr-FR'), + parsedDateLocal: notificationDate.toLocaleString('fr-FR', { timeZone: 'Europe/Paris' }), + parsedDateISO: notificationDate.toISOString(), + nowLocal: now.toLocaleString('fr-FR', { timeZone: 'Europe/Paris' }), nowISO: now.toISOString(), timeUntilNotificationMinutes, timeUntilNotificationSeconds, + isDueToday, inWindow: inNotificationWindow, });