'use client'; import { useMemo, useState } from 'react'; import { useTranslations } from 'next-intl'; import { Bell, CheckCheck } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { PageHeader } from '@/components/ui/PageHeader'; import { EmptyState, ErrorState, Skeleton } from '@/components/ui/states'; import { NotificationRow } from '@/components/notifications/notification-row'; import { useNotificationLabels } from '@/components/notifications/use-notification-labels'; import { notificationKind, type NotificationKind, } from '@/components/notifications/notification-kind'; import { useNotifications } from '@/hooks/useNotifications'; import { cn } from '@/lib/utils'; import type { NotificationResponse } from '@/types/api'; /** Familles proposées au filtre, dans l'ordre où elles comptent au quotidien. */ const FILTERS = ['all', 'unread', 'booking', 'account', 'system'] as const; type Filter = (typeof FILTERS)[number]; const PAGE_SIZE = 50; /** * Toutes les notifications. * * Cette page existait déjà mais n'était liée de nulle part : « Voir tout » * ouvrait un panneau latéral qui rejouait le menu. Elle est désormais la seule * destination, et partage ses lignes avec la cloche — une notification se * présente pareil où qu'on la lise. */ export default function NotificationsPage() { const t = useTranslations('components.notifications'); const [filter, setFilter] = useState('all'); const { notifications, unreadCount, isLoading, isError, refetch, markAsRead, markAllAsRead, isMarkingAll, } = useNotifications({ limit: PAGE_SIZE }); const labels = useNotificationLabels(); const visible = useMemo(() => { if (filter === 'all') return notifications; if (filter === 'unread') return notifications.filter(n => !n.read); return notifications.filter(n => matchesKind(n, filter)); }, [notifications, filter]); const countFor = (value: Filter) => { if (value === 'all') return notifications.length; if (value === 'unread') return unreadCount; return notifications.filter(n => matchesKind(n, value)).length; }; return ( <> 0 && ( ) } tabs={
{FILTERS.map(value => { const active = filter === value; const count = countFor(value); return ( ); })}
} />
{isLoading ? ( ) : isError ? ( refetch()} /> ) : visible.length === 0 ? ( setFilter('all')}> {t('filters.all')} ) } /> ) : (
    {visible.map(notification => (
  • !n.read && markAsRead(n.id)} />
  • ))}
)}
); } /** `document` et `rate` se rangent avec les réservations : c'est le même dossier. */ function matchesKind(notification: NotificationResponse, filter: Filter): boolean { const kind = notificationKind(notification.type); const family: Record, NotificationKind[]> = { booking: ['booking', 'document', 'rate'], account: ['account'], system: ['system'], }; return family[filter as Exclude].includes(kind); }