Pages corrections widget

This commit is contained in:
alma 2026-01-16 17:24:36 +01:00
parent 430940cc12
commit ed9dadd77a
7 changed files with 164 additions and 116 deletions

View File

@ -117,28 +117,33 @@ export function CalendarWidget() {
if (currentEventCount !== lastEventCountRef.current) { if (currentEventCount !== lastEventCountRef.current) {
lastEventCountRef.current = currentEventCount; lastEventCountRef.current = currentEventCount;
// Prepare notification items // Always prepare notification items (even if count hasn't changed)
const notificationItems = upcomingEvents.map(event => ({ const notificationItems = upcomingEvents.map(event => ({
id: event.id, id: event.id,
title: event.title, title: event.title,
message: event.isAllDay message: event.isAllDay
? `Aujourd'hui (toute la journée)` ? `Aujourd'hui (toute la journée)`
: `Le ${format(event.start, 'dd/MM à HH:mm', { locale: fr })}`, : `Le ${format(event.start, 'dd/MM à HH:mm', { locale: fr })}`,
link: '/agenda', link: '/agenda',
timestamp: event.start, timestamp: event.start,
metadata: { metadata: {
calendarId: event.calendarId, calendarId: event.calendarId,
calendarName: event.calendarName, calendarName: event.calendarName,
isAllDay: event.isAllDay, isAllDay: event.isAllDay,
}, },
})); }));
// Trigger notification update // Always trigger notification update to keep count fresh in Redis
await triggerNotification({ // This ensures the count doesn't expire even if it hasn't changed
source: 'calendar', await triggerNotification({
count: currentEventCount, source: 'calendar',
items: notificationItems, count: currentEventCount,
}); items: notificationItems,
});
// Update last count reference
if (currentEventCount !== lastEventCountRef.current) {
lastEventCountRef.current = currentEventCount;
} }
setEvents(upcomingEvents.slice(0, 5)); // Keep only 5 for display setEvents(upcomingEvents.slice(0, 5)); // Keep only 5 for display

View File

@ -195,36 +195,38 @@ export function Email() {
lastUnreadCountRef.current = currentUnreadCount; lastUnreadCountRef.current = currentUnreadCount;
isInitializedRef.current = true; isInitializedRef.current = true;
} else { } else {
// Trigger notification if count changed or new emails detected // Update count if it changed
if (currentUnreadCount !== lastUnreadCountRef.current || hasNewEmails) { if (currentUnreadCount !== lastUnreadCountRef.current) {
const previousCount = lastUnreadCountRef.current;
lastUnreadCountRef.current = currentUnreadCount; lastUnreadCountRef.current = currentUnreadCount;
}
// Prepare notification items (unread emails only, max 10) }
const notificationItems = transformedEmails
.filter(e => !e.read) // Always prepare notification items (unread emails only, max 10)
.slice(0, 10) const notificationItems = transformedEmails
.map(email => { .filter(e => !e.read)
const account = accountMap.get((email as any).accountId); .slice(0, 10)
return { .map(email => {
id: email.id, const account = accountMap.get((email as any).accountId);
title: email.subject || 'Sans objet', return {
message: `De ${email.fromName || email.from.split('@')[0]}`, id: email.id,
link: '/courrier', title: email.subject || 'Sans objet',
timestamp: new Date(email.date), message: `De ${email.fromName || email.from.split('@')[0]}`,
metadata: { link: '/courrier',
accountId: (email as any).accountId, timestamp: new Date(email.date),
accountEmail: account?.email, metadata: {
}, accountId: (email as any).accountId,
}; accountEmail: account?.email,
}); },
};
});
// Trigger notification update (for badge) // Always trigger notification update to keep count fresh in Redis
await triggerNotification({ // This ensures the count doesn't expire even if it hasn't changed
source: 'email', await triggerNotification({
count: currentUnreadCount, source: 'email',
items: notificationItems, count: currentUnreadCount,
}); items: notificationItems,
});
// Dispatch event for Outlook-style notifications (for new emails detected by ID) // Dispatch event for Outlook-style notifications (for new emails detected by ID)
if (hasNewEmails) { if (hasNewEmails) {

View File

@ -218,40 +218,44 @@ export function Duties() {
// Calculate current task count // Calculate current task count
const currentTaskCount = sortedTasks.length; const currentTaskCount = sortedTasks.length;
// Trigger notification if count changed // Always trigger notification to keep the count fresh in Redis
if (currentTaskCount !== lastTaskCountRef.current) { // This prevents the count from expiring if it hasn't changed
const shouldUpdate = currentTaskCount !== lastTaskCountRef.current || lastTaskCountRef.current === -1;
if (shouldUpdate) {
lastTaskCountRef.current = currentTaskCount; lastTaskCountRef.current = currentTaskCount;
// Prepare notification items (max 10)
const notificationItems = sortedTasks
.slice(0, 10)
.map(task => ({
id: task.id.toString(),
title: task.headline,
message: task.dateToFinish
? `Due: ${formatDate(task.dateToFinish)}`
: 'Tâche en retard',
link: (task as any).source === 'twenty-crm'
? (task as any).url
: `https://agilite.slm-lab.net/tickets/showTicket/${task.id.replace('twenty-', '')}`,
timestamp: task.dateToFinish
? new Date(task.dateToFinish)
: new Date(),
metadata: {
source: (task as any).source || 'leantime',
projectName: task.projectName,
status: task.status,
},
}));
// Trigger notification update
await triggerNotification({
source: 'leantime',
count: currentTaskCount,
items: notificationItems,
});
} }
// Prepare notification items (max 10)
const notificationItems = sortedTasks
.slice(0, 10)
.map(task => ({
id: task.id.toString(),
title: task.headline,
message: task.dateToFinish
? `Due: ${formatDate(task.dateToFinish)}`
: 'Tâche en retard',
link: (task as any).source === 'twenty-crm'
? (task as any).url
: `https://agilite.slm-lab.net/tickets/showTicket/${task.id.replace('twenty-', '')}`,
timestamp: task.dateToFinish
? new Date(task.dateToFinish)
: new Date(),
metadata: {
source: (task as any).source || 'leantime',
projectName: task.projectName,
status: task.status,
},
}));
// Always trigger notification update to keep count fresh in Redis
// This ensures the count doesn't expire even if it hasn't changed
await triggerNotification({
source: 'leantime',
count: currentTaskCount,
items: notificationItems,
});
setTasks(sortedTasks); setTasks(sortedTasks);
// Dispatch event for Outlook-style notifications (when tasks are due) // Dispatch event for Outlook-style notifications (when tasks are due)

View File

@ -27,12 +27,21 @@ export const NotificationBadge = memo(function NotificationBadge({ className }:
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
const [manualFetchAttempted, setManualFetchAttempted] = useState(false); const [manualFetchAttempted, setManualFetchAttempted] = useState(false);
console.log('[NOTIFICATION_BADGE] Auth status:', status); console.log('[NOTIFICATION_BADGE] 📊 Notification state:', {
console.log('[NOTIFICATION_BADGE] Session:', session ? 'exists' : 'null'); authStatus: status,
console.log('[NOTIFICATION_BADGE] Current notification count:', notificationCount); hasSession: !!session,
console.log('[NOTIFICATION_BADGE] Current notifications:', notifications.length > 0 ? `${notifications.length} loaded` : 'none loaded'); totalUnread: notificationCount.unread,
console.log('[NOTIFICATION_BADGE] Loading state:', loading); total: notificationCount.total,
console.log('[NOTIFICATION_BADGE] Error state:', error); sources: Object.keys(notificationCount.sources || {}).map(source => ({
source,
unread: notificationCount.sources[source]?.unread || 0,
total: notificationCount.sources[source]?.total || 0,
})),
hasUnread: notificationCount.unread > 0,
notificationsLoaded: notifications.length,
loading,
error: error || null,
});
// Manual fetch function with error handling // Manual fetch function with error handling
const manualFetch = async () => { const manualFetch = async () => {

View File

@ -96,32 +96,34 @@ export function Parole() {
lastUnreadCountRef.current = currentUnreadCount; lastUnreadCountRef.current = currentUnreadCount;
isInitializedRef.current = true; isInitializedRef.current = true;
} else { } else {
// Si le count a changé ou nouveaux messages détectés, déclencher notification // Update count if it changed
if (currentUnreadCount !== lastUnreadCountRef.current || hasNewMessages) { if (currentUnreadCount !== lastUnreadCountRef.current) {
const previousCount = lastUnreadCountRef.current;
lastUnreadCountRef.current = currentUnreadCount; lastUnreadCountRef.current = currentUnreadCount;
}
// Préparer les items pour les notifications (messages, max 10) }
const notificationItems = data.messages
.slice(0, 10) // Always prepare notification items (messages, max 10)
.map((msg: any) => ({ const notificationItems = data.messages
id: msg.id, .slice(0, 10)
title: msg.sender.name || msg.sender.username, .map((msg: any) => ({
message: msg.text || msg.message || '', id: msg.id,
link: '/parole', title: msg.sender.name || msg.sender.username,
timestamp: new Date(msg.rawTimestamp || msg.timestamp), message: msg.text || msg.message || '',
metadata: { link: '/parole',
roomName: msg.roomName, timestamp: new Date(msg.rawTimestamp || msg.timestamp),
roomType: msg.roomType, metadata: {
}, roomName: msg.roomName,
})); roomType: msg.roomType,
},
}));
// Déclencher notification update (for badge) // Always trigger notification update to keep count fresh in Redis
await triggerNotification({ // This ensures the count doesn't expire even if it hasn't changed
source: 'rocketchat', await triggerNotification({
count: currentUnreadCount, source: 'rocketchat',
items: notificationItems, count: currentUnreadCount,
}); items: notificationItems,
});
// Dispatch event for Outlook-style notifications (for new messages detected by ID) // Dispatch event for Outlook-style notifications (for new messages detected by ID)
if (hasNewMessages) { if (hasNewMessages) {

View File

@ -58,7 +58,14 @@ export function useNotifications() {
); );
if (isMountedRef.current) { if (isMountedRef.current) {
console.log('[useNotifications] Received notification count:', data); console.log('[useNotifications] Received notification count:', {
total: data.total,
unread: data.unread,
sources: Object.keys(data.sources || {}).map(source => ({
source,
count: data.sources[source]?.unread || 0,
})),
});
setNotificationCount(data); setNotificationCount(data);
} }
} catch (err: any) { } catch (err: any) {

View File

@ -20,7 +20,7 @@ export class NotificationRegistry {
private static COUNT_CACHE_KEY = (userId: string) => `notifications:count:${userId}`; private static COUNT_CACHE_KEY = (userId: string) => `notifications:count:${userId}`;
private static ITEMS_CACHE_KEY = (userId: string, source: string) => private static ITEMS_CACHE_KEY = (userId: string, source: string) =>
`notifications:items:${userId}:${source}`; `notifications:items:${userId}:${source}`;
private static COUNT_CACHE_TTL = 30; // 30 seconds (aligned with refresh interval) private static COUNT_CACHE_TTL = 300; // 5 minutes (increased to prevent premature expiration)
private static ITEMS_CACHE_TTL = 300; // 5 minutes for items private static ITEMS_CACHE_TTL = 300; // 5 minutes for items
public static getInstance(): NotificationRegistry { public static getInstance(): NotificationRegistry {
@ -72,12 +72,31 @@ export class NotificationRegistry {
total: previousSourceCount + count, total: previousSourceCount + count,
unread: previousSourceCount + count, unread: previousSourceCount + count,
}; };
logger.debug('[NOTIFICATION_REGISTRY] Call count incremented', {
source,
previousCount: previousSourceCount,
newCount: currentCount.sources[source].unread,
});
} else { } else {
// For regular updates, set the count (widgets send their total) // For regular updates, set the count (widgets send their total)
currentCount.sources[source] = { // Only update if the new count is different or if we're setting it for the first time
total: count, if (count !== previousSourceCount || !currentCount.sources[source]) {
unread: count, currentCount.sources[source] = {
}; total: count,
unread: count,
};
logger.debug('[NOTIFICATION_REGISTRY] Count updated', {
source,
previousCount: previousSourceCount,
newCount: count,
});
} else {
// Count hasn't changed, but refresh the TTL to keep it alive
logger.debug('[NOTIFICATION_REGISTRY] Count unchanged, refreshing TTL', {
source,
count,
});
}
} }
// Recalculate total // Recalculate total