"use client"; import { Bell } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { useSession } from "@/lib/hooks/use-session"; import { NotificationDropdown } from "./NotificationDropdown"; interface Notification { notification_id: number; notification_type: string; title: string; message: string; is_read: boolean; related_id: number | null; created_at: string; } interface NotificationBellProps { userId?: number; className?: string; } export function NotificationBell({ userId, className }: NotificationBellProps) { const { user } = useSession(); const [unreadCount, setUnreadCount] = useState(0); const [notifications, setNotifications] = useState([]); const [isOpen, setIsOpen] = useState(false); const [_loading, setLoading] = useState(false); const rawUnreadRef = useRef(0); const baselineUnreadRef = useRef(0); const baselineLoadedRef = useRef(false); const storageKeyRef = useRef(null); const effectiveUserId = userId || user?.userId; // Buscar contagem de não lidas const persistBaseline = (value: number) => { baselineUnreadRef.current = value; if (typeof window !== "undefined" && storageKeyRef.current) { window.localStorage.setItem(storageKeyRef.current, String(value)); } }; const loadBaselineFromStorage = () => { if (typeof window === "undefined" || !storageKeyRef.current) { return undefined; } const stored = window.localStorage.getItem(storageKeyRef.current); if (!stored) return undefined; const parsed = Number.parseInt(stored, 10); if (Number.isNaN(parsed)) return undefined; return parsed; }; const fetchUnreadCount = async () => { if (!effectiveUserId) return; try { const res = await fetch("/api/notifications/unread-count"); if (res.ok) { const data = await res.json(); if (data.success) { rawUnreadRef.current = data.count; if (!baselineLoadedRef.current) { const storedBaseline = loadBaselineFromStorage(); if (storedBaseline !== undefined) { const normalized = Math.min(storedBaseline, data.count); persistBaseline(normalized); } else { persistBaseline(data.count); } baselineLoadedRef.current = true; } else if (data.count < baselineUnreadRef.current) { persistBaseline(data.count); } setUnreadCount(Math.max(0, data.count - baselineUnreadRef.current)); } } } catch (error) { console.error("Erro ao buscar contagem de notificações:", error); } }; // Buscar notificações recentes const fetchNotifications = async () => { if (!effectiveUserId) return; setLoading(true); try { const res = await fetch("/api/notifications?limit=10"); if (res.ok) { const data = await res.json(); if (data.success) { setNotifications(data.notifications || []); } } } catch (error) { console.error("Erro ao buscar notificações:", error); } finally { setLoading(false); } }; // Polling automático a cada 30 segundos useEffect(() => { if (!effectiveUserId) { return; } storageKeyRef.current = `notifications:lastBaseline:${effectiveUserId}`; const storedBaseline = loadBaselineFromStorage(); if (storedBaseline !== undefined) { baselineUnreadRef.current = storedBaseline; baselineLoadedRef.current = true; } else { baselineUnreadRef.current = 0; baselineLoadedRef.current = false; } }, [effectiveUserId, loadBaselineFromStorage]); useEffect(() => { if (!effectiveUserId) return; fetchUnreadCount(); fetchNotifications(); const interval = setInterval(() => { fetchUnreadCount(); if (isOpen) { fetchNotifications(); } }, 30000); // 30 segundos return () => clearInterval(interval); }, [effectiveUserId, isOpen, fetchNotifications, fetchUnreadCount]); // Atualizar quando abrir popover useEffect(() => { if (isOpen) { fetchNotifications(); persistBaseline(rawUnreadRef.current); setUnreadCount(0); } }, [isOpen, fetchNotifications, persistBaseline]); const handleMarkAsRead = async (notificationId: number) => { try { const res = await fetch(`/api/notifications/${notificationId}/read`, { method: "POST", }); if (res.ok) { // Atualizar estado local setNotifications((prev) => prev.map((n) => n.notification_id === notificationId ? { ...n, is_read: true } : n, ), ); // Atualizar contagem rawUnreadRef.current = Math.max(0, rawUnreadRef.current - 1); const newBaseline = Math.min( baselineUnreadRef.current, rawUnreadRef.current, ); persistBaseline(newBaseline); setUnreadCount((prev) => Math.max(0, prev - 1)); } } catch (error) { console.error("Erro ao marcar notificação como lida:", error); } }; if (!effectiveUserId) { return null; } return ( { setIsOpen(false); // Navegar para página de notificações (implementar depois) window.location.href = "/notifications"; }} /> ); }