Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
78 lines
2.3 KiB
TypeScript
78 lines
2.3 KiB
TypeScript
/**
|
|
* useNotifications
|
|
*
|
|
* Source unique des notifications : la cloche, la page et tout futur écran
|
|
* lisent le même état.
|
|
*/
|
|
|
|
'use client';
|
|
|
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
import {
|
|
getUnreadNotificationCount,
|
|
listNotifications,
|
|
markAllNotificationsAsRead,
|
|
markNotificationAsRead,
|
|
} from '@/lib/api';
|
|
import type { NotificationResponse } from '@/types/api';
|
|
|
|
interface UseNotificationsOptions {
|
|
/** Ne remonter que les non-lues. Par défaut, tout, du plus récent au plus ancien. */
|
|
unreadOnly?: boolean;
|
|
/** Nombre maximum de notifications chargées. */
|
|
limit?: number;
|
|
/** Intervalle de rafraîchissement, en millisecondes. */
|
|
refetchInterval?: number;
|
|
}
|
|
|
|
export function useNotifications(options: UseNotificationsOptions = {}) {
|
|
const { unreadOnly = false, limit = 10, refetchInterval = 30000 } = options;
|
|
const queryClient = useQueryClient();
|
|
|
|
const list = useQuery({
|
|
queryKey: ['notifications', { unreadOnly, limit }],
|
|
queryFn: () => listNotifications(unreadOnly ? { isRead: false, limit } : { limit }),
|
|
refetchInterval,
|
|
refetchOnWindowFocus: true,
|
|
});
|
|
|
|
/**
|
|
* Le compteur vient du serveur.
|
|
*
|
|
* Il etait auparavant calcule sur la page chargee — dix elements — et ne
|
|
* pouvait donc jamais depasser dix, quel que soit le nombre reel de non-lues.
|
|
*/
|
|
const count = useQuery({
|
|
queryKey: ['notifications', 'unread-count'],
|
|
queryFn: getUnreadNotificationCount,
|
|
refetchInterval,
|
|
refetchOnWindowFocus: true,
|
|
});
|
|
|
|
const invalidate = () => queryClient.invalidateQueries({ queryKey: ['notifications'] });
|
|
|
|
const markAsReadMutation = useMutation({
|
|
mutationFn: markNotificationAsRead,
|
|
onSuccess: invalidate,
|
|
});
|
|
|
|
const markAllAsReadMutation = useMutation({
|
|
mutationFn: markAllNotificationsAsRead,
|
|
onSuccess: invalidate,
|
|
});
|
|
|
|
const notifications: NotificationResponse[] = list.data?.notifications ?? [];
|
|
|
|
return {
|
|
notifications,
|
|
total: list.data?.total ?? notifications.length,
|
|
unreadCount: count.data?.count ?? 0,
|
|
isLoading: list.isPending,
|
|
isError: list.isError,
|
|
refetch: list.refetch,
|
|
markAsRead: markAsReadMutation.mutate,
|
|
markAllAsRead: markAllAsReadMutation.mutate,
|
|
isMarkingAll: markAllAsReadMutation.isPending,
|
|
};
|
|
}
|