Files
Novault-Frontend-web/src/hooks/useNotifications.tsx

95 lines
3.2 KiB
TypeScript
Raw Normal View History

import React, { useState, useEffect, useCallback, createContext, useContext } from 'react';
import { notificationService, type Notification } from '../services/notificationService';
interface NotificationContextType {
notifications: Notification[];
unreadCount: number;
loading: boolean;
markAsRead: (id: number) => Promise<void>;
markAllAsRead: () => Promise<void>;
refreshNotifications: () => Promise<void>;
}
const NotificationContext = createContext<NotificationContextType | undefined>(undefined);
export const NotificationProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [notifications, setNotifications] = useState<Notification[]>([]);
const [unreadCount, setUnreadCount] = useState<number>(0);
const [loading, setLoading] = useState<boolean>(false);
const fetchNotifications = useCallback(async () => {
try {
// Fetch unread count
const countRes = await notificationService.getUnreadCount();
if (countRes.success) {
setUnreadCount(countRes.data.count);
}
// Fetch latest notifications (page 1, 10 items)
// You might want to load more on demand, but this is initial state
const listRes = await notificationService.getNotifications(1, 10);
if (listRes.success) {
setNotifications(listRes.data.notifications);
}
} catch (error) {
console.error('Failed to fetch notifications:', error);
}
}, []);
const refreshNotifications = useCallback(async () => {
setLoading(true);
await fetchNotifications();
setLoading(false);
}, [fetchNotifications]);
// Initial fetch and polling
useEffect(() => {
fetchNotifications();
const interval = setInterval(fetchNotifications, 60000); // Poll every minute
return () => clearInterval(interval);
}, [fetchNotifications]);
const markAsRead = useCallback(async (id: number) => {
try {
await notificationService.markAsRead(id);
// Optimistic update
setNotifications(prev => prev.map(n => n.id === id ? { ...n, is_read: true } : n));
setUnreadCount(prev => Math.max(0, prev - 1));
} catch (error) {
console.error('Failed to mark as read:', error);
}
}, []);
const markAllAsRead = useCallback(async () => {
try {
await notificationService.markAllAsRead();
// Optimistic update
setNotifications(prev => prev.map(n => ({ ...n, is_read: true })));
setUnreadCount(0);
} catch (error) {
console.error('Failed to mark all as read:', error);
}
}, []);
return (
<NotificationContext.Provider value={{
notifications,
unreadCount,
loading,
markAsRead,
markAllAsRead,
refreshNotifications
}}>
{children}
</NotificationContext.Provider>
);
};
export const useNotifications = () => {
const context = useContext(NotificationContext);
if (!context) {
throw new Error('useNotifications must be used within a NotificationProvider');
}
return context;
};