97 lines
2.8 KiB
TypeScript
97 lines
2.8 KiB
TypeScript
import { useCallback, useRef } from 'react';
|
|
import { useSession } from 'next-auth/react';
|
|
import { logger } from '@/lib/logger';
|
|
|
|
export interface NotificationItem {
|
|
id: string;
|
|
title: string;
|
|
message: string;
|
|
link?: string;
|
|
timestamp: Date;
|
|
metadata?: Record<string, any>;
|
|
}
|
|
|
|
export interface WidgetNotificationData {
|
|
source: 'email' | 'rocketchat' | 'leantime' | 'calendar';
|
|
count: number;
|
|
items?: NotificationItem[];
|
|
}
|
|
|
|
/**
|
|
* Hook to trigger notifications from widgets
|
|
* Use this when widgets detect new items (emails, messages, tasks, events)
|
|
*/
|
|
export function useWidgetNotification() {
|
|
const { data: session } = useSession();
|
|
const lastUpdateRef = useRef<Record<string, number>>({});
|
|
const DEBOUNCE_MS = 1000; // 1 second debounce per source
|
|
|
|
const triggerNotification = useCallback(async (data: WidgetNotificationData) => {
|
|
if (!session?.user?.id) {
|
|
logger.debug('[useWidgetNotification] No session, skipping notification');
|
|
return;
|
|
}
|
|
|
|
const { source, count, items } = data;
|
|
const now = Date.now();
|
|
const lastUpdate = lastUpdateRef.current[source] || 0;
|
|
|
|
// Debounce per source to avoid excessive API calls
|
|
if (now - lastUpdate < DEBOUNCE_MS) {
|
|
logger.debug('[useWidgetNotification] Debouncing notification', { source, count });
|
|
return;
|
|
}
|
|
lastUpdateRef.current[source] = now;
|
|
|
|
try {
|
|
logger.debug('[useWidgetNotification] Triggering notification update', {
|
|
source,
|
|
count,
|
|
itemsCount: items?.length || 0,
|
|
});
|
|
|
|
// Send notification data to the registry
|
|
const response = await fetch('/api/notifications/update', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'include',
|
|
body: JSON.stringify({
|
|
source,
|
|
count,
|
|
items: items?.map(item => ({
|
|
...item,
|
|
timestamp: item.timestamp.toISOString(),
|
|
})) || [],
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
logger.error('[useWidgetNotification] Failed to update notification', {
|
|
source,
|
|
status: response.status,
|
|
error: errorText,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Dispatch event for immediate UI update
|
|
window.dispatchEvent(new CustomEvent('notification-updated', {
|
|
detail: { source, count }
|
|
}));
|
|
|
|
logger.debug('[useWidgetNotification] Notification updated successfully', {
|
|
source,
|
|
count,
|
|
});
|
|
} catch (error) {
|
|
logger.error('[useWidgetNotification] Error updating notification', {
|
|
source,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
});
|
|
}
|
|
}, [session?.user?.id]);
|
|
|
|
return { triggerNotification };
|
|
}
|