import { useMutation, useQueryClient, type QueryKey } from '@tanstack/react-query'; import type { Paginated } from '@/lib/api/types'; import { notificationKeys } from '../keys'; import { notificationsApi } from '../apis'; import type { AppNotification } from '../types'; interface MarkReadContext { prevCount?: number; prevLists: Array<[QueryKey, Paginated | undefined]>; } /** * Mark one notification read — **optimistic** (phase §3.4): flip `isRead` across every cached list page and * decrement the cached unread count at once (so the row de-emphasises and the bell badge drops instantly), * roll both back on error, and invalidate on settle (no full refetch on the happy path). The count only * decrements when the notification was actually unread, so re-opening a read one never underflows. */ export function useMarkNotificationRead() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (notificationId) => notificationsApi.markRead(notificationId), onMutate: async (notificationId) => { await queryClient.cancelQueries({ queryKey: notificationKeys.all }); const prevCount = queryClient.getQueryData(notificationKeys.unreadCount()); const prevLists = queryClient.getQueriesData>({ queryKey: notificationKeys.lists() }); const wasUnread = prevLists.some(([, data]) => data?.items.some((n) => n.id === notificationId && !n.isRead), ); queryClient.setQueriesData>({ queryKey: notificationKeys.lists() }, (data) => data ? { ...data, items: data.items.map((n) => (n.id === notificationId ? { ...n, isRead: true } : n)) } : data, ); if (wasUnread && typeof prevCount === 'number') { queryClient.setQueryData(notificationKeys.unreadCount(), Math.max(0, prevCount - 1)); } return { prevCount, prevLists }; }, onError: (_err, _id, context) => { if (context?.prevCount !== undefined) queryClient.setQueryData(notificationKeys.unreadCount(), context.prevCount); context?.prevLists.forEach(([key, data]) => queryClient.setQueryData(key, data)); }, onSettled: () => { queryClient.invalidateQueries({ queryKey: notificationKeys.lists() }); queryClient.invalidateQueries({ queryKey: notificationKeys.unreadCount() }); }, }); }