import { useTranslation } from "react-i18next"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { Bell, Check, CheckCheck, Trash2, X } from "lucide-react"; import { api, type AppNotification } from "../lib/api"; import { useLiveQuery } from "../lib/useLiveQuery"; // The durable, server-backed notification center (inbox phase 1). It COEXISTS with the // client-side transient bell in the nav rail: the bell is a quick peek at recent toasts kept // in localStorage, this is the full, filterable, clearable history synced from the server. const POLL_MS = 8000; function relativeTime(iso: string | null, t: (k: string, o?: any) => string): string { if (!iso) return ""; const then = new Date(iso).getTime(); const secs = Math.max(0, Math.round((Date.now() - then) / 1000)); // Reuse the bell's relative-time strings (notifications.time.*) — same format, no dupes. if (secs < 60) return t("notifications.time.justNow"); const mins = Math.round(secs / 60); if (mins < 60) return t("notifications.time.minutes", { count: mins }); const hours = Math.round(mins / 60); if (hours < 24) return t("notifications.time.hours", { count: hours }); const days = Math.round(hours / 24); return t("notifications.time.days", { count: days }); } export default function NotificationsPanel() { const { t } = useTranslation(); const qc = useQueryClient(); const q = useLiveQuery<{ items: AppNotification[]; total: number }>( ["notifications"], () => api.notifications(), { intervalMs: POLL_MS } ); const items = q.data?.items ?? []; // Any mutation refreshes both the list and the nav badge's unread count. const refresh = () => { qc.invalidateQueries({ queryKey: ["notifications"] }); qc.invalidateQueries({ queryKey: ["notif-unread"] }); }; const readMut = useMutation({ mutationFn: api.markNotificationRead, onSuccess: refresh }); const readAllMut = useMutation({ mutationFn: api.markAllNotificationsRead, onSuccess: refresh }); const dismissMut = useMutation({ mutationFn: api.dismissNotification, onSuccess: refresh }); const clearMut = useMutation({ mutationFn: api.clearNotifications, onSuccess: refresh }); const hasUnread = items.some((n) => !n.read); return (