/** * useNotifications Hook - Platform-aware notifications management * Uses Firebase abstraction layer for cross-platform support */ import { useState, useEffect, useCallback } from 'react'; import { collection } from '../firebase'; import { NotificationService } from '../services/notificationService'; import { useGlobalLoading } from './useGlobalLoading'; export interface UseNotificationsReturn { notifications: any[]; loading: boolean; error: string | null; unreadCount: number; markAsRead: (notificationId: string) => Promise; markAllAsRead: () => Promise; refreshNotifications: () => void; } export function useNotifications(uid: string | null): UseNotificationsReturn { const [notifications, setNotifications] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const { withLoading } = useGlobalLoading(); // Calculate unread count const unreadCount = notifications.filter(notification => !notification.read).length; // Mark single notification as read const markAsRead = async (notificationId: string): Promise => { try { const result = await withLoading(() => NotificationService.markAsRead(notificationId)); if (result.success) { // Update local state setNotifications(prev => prev.map(notification => notification.id === notificationId ? { ...notification, read: true, updatedAt: new Date() } : notification ) ); } else { setError(result.error || 'Failed to mark notification as read'); } } catch (err) { console.error('Error marking notification as read:', err); setError('Failed to mark notification as read'); } }; // Mark all notifications as read const markAllAsRead = async (): Promise => { try { // Update all notifications in local state setNotifications(prev => prev.map(notification => ({ ...notification, read: true, updatedAt: new Date() })) ); // Update in Firestore const unreadNotifications = notifications.filter(n => !n.read); const updatePromises = unreadNotifications.map(notification => notification.id ? withLoading(() => NotificationService.markAsRead(notification.id)) : Promise.resolve({ success: true }) ); await Promise.all(updatePromises); } catch (err) { console.error('Error marking all notifications as read:', err); setError('Failed to mark all notifications as read'); } }; // Refresh notifications const [refreshKey, setRefreshKey] = useState(0); const refreshNotifications = useCallback((): void => { setLoading(true); setError(null); }, []); useEffect(() => { let isMounted = true; const fetchNotifications = async () => { if (!uid) { if (isMounted) { setNotifications([]); setLoading(false); setError(null); } return; } if (isMounted) { setLoading(true); setError(null); } try { const notificationsCollection = collection('notifications'); const snapshot = await withLoading(async () => { return await notificationsCollection .where('userId', '==', uid) .orderBy('createdAt', 'desc') .get(); }) as any; const notificationsData: any[] = []; if (snapshot && snapshot.forEach) { snapshot.forEach((docData: any) => { const data = docData.data(); notificationsData.push({ id: docData.id, ...data, }); }); } if (isMounted) { setNotifications(notificationsData); setLoading(false); setError(null); } } catch (err) { console.error('Error fetching notifications:', err); if (isMounted) { setError('Failed to fetch notifications'); setLoading(false); } } }; void fetchNotifications(); return () => { isMounted = false; }; }, [uid, refreshKey, withLoading]); return { notifications, loading, error, unreadCount, markAsRead, markAllAsRead, refreshNotifications, }; }