"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; import { useTranslations } from "next-intl"; import { Bell } from "lucide-react"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Badge } from "@/components/ui/badge"; import { cn } from "@/lib/utils"; type Notification = { id: string; type: "follow" | "comment" | "reply" | "reaction" | "rating" | "mention"; recipeId: string | null; commentId: string | null; read: boolean; createdAt: string; actorId: string; actorName: string; actorUsername: string | null; }; function notificationHref(n: Notification): string { if (n.type === "follow") return n.actorUsername ? `/u/${n.actorUsername}` : "#"; if (n.recipeId) return `/recipes/${n.recipeId}`; return "#"; } export function NotificationBell() { const t = useTranslations("notifications"); const [notifications, setNotifications] = useState([]); const [unreadCount, setUnreadCount] = useState(0); const [open, setOpen] = useState(false); async function load() { try { const res = await fetch("/api/v1/notifications"); if (!res.ok) return; const data = (await res.json()) as { notifications: Notification[]; unreadCount: number }; setNotifications(data.notifications); setUnreadCount(data.unreadCount); } catch { // silent — bell just stays at last known state } } useEffect(() => { void load(); const interval = setInterval(() => { void load(); }, 30_000); return () => clearInterval(interval); }, []); async function markAllRead() { setUnreadCount(0); setNotifications((prev) => prev.map((n) => ({ ...n, read: true }))); await fetch("/api/v1/notifications/read", { method: "POST" }); } return ( { setOpen(next); if (next) void load(); }}> }> {unreadCount > 0 && ( {unreadCount > 9 ? "9+" : unreadCount} )} {t("title")}
{t("title")} {unreadCount > 0 && ( )}
{notifications.length === 0 && (

{t("empty")}

)}
{notifications.map((n) => ( }>
{!n.read && } {t(n.type, { name: n.actorName })}
))}
); }