Pages corrections widget
This commit is contained in:
parent
430940cc12
commit
ed9dadd77a
@ -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
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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 () => {
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user