NeahStable/hooks/use-email-notifications.ts

134 lines
4.6 KiB
TypeScript

import { useState, useEffect, useRef } from 'react';
import { Mail } from 'lucide-react';
import { OutlookNotificationData } from '@/components/outlook-notification';
/**
* Hook to manage email notifications and show Outlook-style notifications
*/
export function useEmailNotifications() {
const [emailNotification, setEmailNotification] = useState<OutlookNotificationData | null>(null);
const lastEmailIdsRef = useRef<Set<string>>(new Set());
const notificationQueueRef = useRef<OutlookNotificationData[]>([]);
const isShowingRef = useRef(false);
const isInitializedRef = useRef(false);
useEffect(() => {
// Listen for new emails via custom event
const handleNewEmails = (event: CustomEvent) => {
const emails = event.detail?.emails || [];
const accountMap = event.detail?.accountMap || new Map();
const previousCount = event.detail?.previousCount ?? -1;
const currentCount = event.detail?.currentCount ?? 0;
if (!emails || emails.length === 0) return;
// On first load, just store all email IDs without showing notifications
if (!isInitializedRef.current) {
console.log('[useEmailNotifications] Initializing - storing existing email IDs without notifications');
lastEmailIdsRef.current = new Set(emails.map((e: any) => e.id));
isInitializedRef.current = true;
return;
}
// Find new emails by comparing IDs (more reliable than count comparison)
// This works even if previousCount is -1 (first load after initialization)
const newEmails = emails
.filter((email: any) => {
const emailId = email.id;
return !lastEmailIdsRef.current.has(emailId) && !email.read;
})
.slice(0, 5); // Limit to 5 most recent new emails
// Update lastEmailIdsRef with all current emails
lastEmailIdsRef.current = new Set(emails.map((e: any) => e.id));
// If there are new unread emails, queue them for notification
// This works regardless of previousCount value
if (newEmails.length > 0) {
console.log('[useEmailNotifications] 📧 New emails detected:', {
newEmailsCount: newEmails.length,
previousCount,
currentCount,
newEmailIds: newEmails.map((e: any) => e.id),
});
newEmails.forEach((email: any) => {
const account = accountMap.get(email.accountId);
const notification: OutlookNotificationData = {
id: `email-${email.id}-${Date.now()}`,
source: 'email',
title: 'Courrier',
subtitle: 'Nouvel email',
message: `${email.subject || 'Sans objet'} - De ${email.fromName || email.from.split('@')[0]}`,
icon: Mail,
iconColor: 'text-green-600',
iconBgColor: 'bg-green-100',
borderColor: 'border-green-500',
link: '/courrier',
timestamp: new Date(email.date),
autoDismiss: 10000, // 10 seconds for emails
actions: [
{
label: 'Ouvrir',
onClick: () => {
window.location.href = '/courrier';
},
variant: 'default',
className: 'bg-green-600 hover:bg-green-700 text-white',
},
],
};
notificationQueueRef.current.push(notification);
});
// Show the first notification if none is currently showing
if (!isShowingRef.current && notificationQueueRef.current.length > 0) {
showNextNotification();
}
} else {
console.log('[useEmailNotifications] ⏭️ No new emails detected', {
previousCount,
currentCount,
totalEmails: emails.length,
lastEmailIdsCount: lastEmailIdsRef.current.size,
});
}
};
window.addEventListener('new-emails-detected', handleNewEmails as EventListener);
return () => {
window.removeEventListener('new-emails-detected', handleNewEmails as EventListener);
};
}, []);
const showNextNotification = () => {
if (notificationQueueRef.current.length === 0) {
isShowingRef.current = false;
return;
}
const nextNotification = notificationQueueRef.current.shift();
if (nextNotification) {
isShowingRef.current = true;
setEmailNotification(nextNotification);
}
};
const handleDismiss = () => {
setEmailNotification(null);
isShowingRef.current = false;
// Show next notification after a short delay
setTimeout(() => {
showNextNotification();
}, 500);
};
return {
emailNotification,
setEmailNotification: handleDismiss,
};
}