All files / src/hooks/useNotifications useNotifications.ts

100% Statements 25/25
100% Branches 6/6
100% Functions 12/12
100% Lines 25/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125                                                                          1x 13x 12x           1x 1x     1x           1x 1x     1x           1x 1x 1x                         19x   19x               19x 1x     1x         19x       1x         19x       1x       19x     1x 1x 1x      
/**
 * useNotifications Hook
 * Story 1.17, Task 5b: React Query hook for notifications
 *
 * Fetches and caches notifications with mutations for marking as read/delete.
 * Uses React Query for server state management with 1-minute stale time.
 */
 
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import apiClient from '@/services/api/apiClient';
 
interface Notification {
  id: string;
  type: string;
  title: string;
  message: string;
  timestamp: string;
  isRead: boolean;
  actionUrl: string;
  priority: string;
}
 
interface NotificationsResponse {
  notifications: Notification[];
  unreadCount: number;
  totalCount: number;
  hasMore: boolean;
}
 
interface UseNotificationsOptions {
  enabled?: boolean;
  staleTime?: number;
}
 
/**
 * Fetch unread notifications
 */
const fetchNotifications = async (): Promise<NotificationsResponse> => {
  const response = await apiClient.get('/notifications?status=unread&limit=10');
  return response.data;
};
 
/**
 * Mark notification(s) as read
 */
const markAsReadMutation = async (notificationIds: string[]) => {
  const response = await apiClient.put('/notifications/read', {
    notificationIds,
  });
  return response.data;
};
 
/**
 * Mark all notifications as read
 */
const markAllAsReadMutation = async () => {
  const response = await apiClient.put('/notifications/read', {
    markAll: true,
  });
  return response.data;
};
 
/**
 * Delete a notification
 */
const deleteNotificationMutation = async (id: string) => {
  const response = await apiClient.delete(`/notifications/${id}`);
  return response.data;
};
 
/**
 * Custom hook to fetch and manage notifications
 *
 * @param options - Query options
 * @returns React Query result with notifications data and mutation functions
 *
 * @example
 * const { data, unreadCount, markAsRead, markAllAsRead, deleteNotification } = useNotifications();
 */
export function useNotifications(options?: UseNotificationsOptions) {
  const queryClient = useQueryClient();
 
  const query = useQuery({
    queryKey: ['notifications'],
    queryFn: fetchNotifications,
    staleTime: options?.staleTime ?? 1000 * 60, // 1 minute default
    enabled: options?.enabled ?? true,
  });
 
  // Mutation for marking single notification as read
  const markAsReadMut = useMutation({
    mutationFn: (notificationId: string) => markAsReadMutation([notificationId]),
    onSuccess: () => {
      // Invalidate and refetch notifications after marking as read
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
    },
  });
 
  // Mutation for marking all notifications as read
  const markAllAsReadMut = useMutation({
    mutationFn: markAllAsReadMutation,
    onSuccess: () => {
      // Invalidate and refetch notifications after marking all as read
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
    },
  });
 
  // Mutation for deleting a notification
  const deleteNotificationMut = useMutation({
    mutationFn: deleteNotificationMutation,
    onSuccess: () => {
      // Invalidate and refetch notifications after deletion
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
    },
  });
 
  return {
    ...query,
    unreadCount: query.data?.unreadCount ?? 0,
    markAsRead: (id: string) => markAsReadMut.mutateAsync(id),
    markAllAsRead: () => markAllAsReadMut.mutateAsync(),
    deleteNotification: (id: string) => deleteNotificationMut.mutateAsync(id),
  };
}