feat: add guest notification insights

This commit is contained in:
Codex Agent
2025-11-12 19:31:13 +01:00
parent 642541c8fb
commit 2c412e3764
7 changed files with 440 additions and 7 deletions

View File

@@ -19,6 +19,8 @@ export type NotificationCenterValue = {
markAsRead: (id: number) => Promise<void>;
dismiss: (id: number) => Promise<void>;
eventToken: string;
lastFetchedAt: Date | null;
isOffline: boolean;
};
const NotificationCenterContext = React.createContext<NotificationCenterValue | null>(null);
@@ -30,6 +32,8 @@ export function NotificationCenterProvider({ eventToken, children }: { eventToke
const [loadingNotifications, setLoadingNotifications] = React.useState(true);
const etagRef = React.useRef<string | null>(null);
const fetchLockRef = React.useRef(false);
const [lastFetchedAt, setLastFetchedAt] = React.useState<Date | null>(null);
const [isOffline, setIsOffline] = React.useState<boolean>(typeof navigator !== 'undefined' ? !navigator.onLine : false);
const queueCount = React.useMemo(
() => items.filter((item) => item.status !== 'done').length,
@@ -59,14 +63,19 @@ export function NotificationCenterProvider({ eventToken, children }: { eventToke
if (!result.notModified) {
setNotifications(result.notifications);
setUnreadCount(result.unreadCount);
setLastFetchedAt(new Date());
}
etagRef.current = result.etag;
setIsOffline(false);
} catch (error) {
console.error('Failed to load guest notifications', error);
if (!options.silent) {
setNotifications([]);
setUnreadCount(0);
}
if (typeof navigator !== 'undefined' && !navigator.onLine) {
setIsOffline(true);
}
} finally {
fetchLockRef.current = false;
if (!options.silent) {
@@ -103,6 +112,19 @@ export function NotificationCenterProvider({ eventToken, children }: { eventToke
return () => window.clearInterval(interval);
}, [eventToken, loadNotifications]);
React.useEffect(() => {
const handleOnline = () => setIsOffline(false);
const handleOffline = () => setIsOffline(true);
window.addEventListener('online', handleOnline);
window.addEventListener('offline', handleOffline);
return () => {
window.removeEventListener('online', handleOnline);
window.removeEventListener('offline', handleOffline);
};
}, []);
const markAsRead = React.useCallback(
async (id: number) => {
if (!eventToken) {
@@ -199,6 +221,8 @@ export function NotificationCenterProvider({ eventToken, children }: { eventToke
markAsRead,
dismiss,
eventToken,
lastFetchedAt,
isOffline,
};
return (