All files / src/hooks useNotifications.ts

100% Statements 26/26
100% Branches 5/5
100% Functions 16/16
100% Lines 26/26

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 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160                                                                                    2x         6x   2x                         2x       4x   1x                             2x 2x   2x 1x     1x                   2x           2x   2x   1x   1x                   2x           2x   2x   1x   1x                   2x           2x   2x 1x   1x        
/**
 * Notification React Query Hooks
 *
 * Story BAT-7 - Notifications API Consolidation
 *
 * React Query hooks for Notification feature:
 * - useNotifications: List query with filters, pagination (cache 2min)
 * - useUnreadCount: Unread count query (cache 1min)
 * - useMarkAsRead: Mark notification as read mutation
 * - useBatchMarkAsRead: Batch mark as read mutation
 * - useDeleteNotification: Delete notification mutation
 *
 * EventBridge Integration: Automatically fetches notifications triggered by domain events
 */
 
import {
  useQuery,
  useMutation,
  useQueryClient,
  type UseQueryResult,
  type UseMutationResult,
} from '@tanstack/react-query';
import { notificationApiClient } from '@/services/notificationApiClient';
import type {
  NotificationsResponse,
  NotificationFilters,
  MarkAsReadResponse,
  DeleteNotificationResponse,
} from '@/types/notification';
 
// ============================================================================
// Query Hooks
// ============================================================================
 
/**
 * useNotifications - Fetch paginated list of notifications
 * Cache: 2 minutes (notifications are volatile)
 *
 * @param filters - Username (required) and optional status/eventCode filters
 * @param pagination - Page number and limit
 * @param options - React Query options
 */
export const useNotifications = (
  filters: NotificationFilters,
  pagination: { page?: number; limit?: number } = {},
  options?: { enabled?: boolean }
): UseQueryResult<NotificationsResponse, Error> => {
  return useQuery({
    queryKey: ['notifications', filters, pagination],
    queryFn: () => notificationApiClient.getNotifications(filters, pagination),
    staleTime: 2 * 60 * 1000, // 2 minutes
    enabled: options?.enabled !== false && !!filters.username,
  });
};
 
/**
 * useUnreadCount - Fetch unread notification count
 * Cache: 1 minute (count changes frequently)
 *
 * @param username - Username of the user
 * @param options - React Query options
 */
export const useUnreadCount = (
  username: string | undefined,
  options?: { enabled?: boolean }
): UseQueryResult<number, Error> => {
  return useQuery({
    queryKey: ['notifications', 'unread-count', username],
    queryFn: () => notificationApiClient.getUnreadCount(username!),
    staleTime: 1 * 60 * 1000, // 1 minute
    enabled: options?.enabled !== false && !!username,
  });
};
 
// ============================================================================
// Mutation Hooks
// ============================================================================
 
/**
 * useMarkAsRead - Mark a single notification as read
 *
 * Automatically invalidates notification queries on success
 */
export const useMarkAsRead = (): UseMutationResult<MarkAsReadResponse, Error, string, unknown> => {
  const queryClient = useQueryClient();
 
  return useMutation({
    mutationFn: (notificationId: string) => notificationApiClient.markAsRead(notificationId),
    onSuccess: () => {
      // Invalidate all notification queries to refetch with updated data
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
    },
  });
};
 
/**
 * useBatchMarkAsRead - Mark multiple notifications as read
 *
 * Automatically invalidates notification queries on success
 */
export const useBatchMarkAsRead = (): UseMutationResult<
  MarkAsReadResponse,
  Error,
  string[],
  unknown
> => {
  const queryClient = useQueryClient();
 
  return useMutation({
    mutationFn: (notificationIds: string[]) =>
      notificationApiClient.batchMarkAsRead(notificationIds),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
    },
  });
};
 
/**
 * useDeleteNotification - Delete a single notification
 *
 * Automatically invalidates notification queries on success
 */
export const useDeleteNotification = (): UseMutationResult<
  DeleteNotificationResponse,
  Error,
  string,
  unknown
> => {
  const queryClient = useQueryClient();
 
  return useMutation({
    mutationFn: (notificationId: string) =>
      notificationApiClient.deleteNotification(notificationId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
    },
  });
};
 
/**
 * useBatchDeleteNotifications - Delete multiple notifications
 *
 * Automatically invalidates notification queries on success
 */
export const useBatchDeleteNotifications = (): UseMutationResult<
  DeleteNotificationResponse,
  Error,
  string[],
  unknown
> => {
  const queryClient = useQueryClient();
 
  return useMutation({
    mutationFn: (notificationIds: string[]) => notificationApiClient.batchDelete(notificationIds),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['notifications'] });
    },
  });
};