import { useEffect, useRef, useState, useCallback } from "react"; import { createPortal } from "react-dom"; import { useNotifications } from "../../../hooks/use-notifications"; import { useMobileViewport } from "../../../hooks/use-mobile-viewport"; import { NotificationItem } from "./notification-item"; import { Icon } from "../../icon"; interface NotificationCenterProps { isMobileTerminal?: boolean; } export function NotificationCenter({ isMobileTerminal = false, }: NotificationCenterProps) { const { notifications, unreadCount, markRead, markAllRead, clearAll, dismiss, refreshList, isDropdownOpen, setIsDropdownOpen, } = useNotifications(); const isMobile = useMobileViewport(); const bellRef = useRef(null); const dropdownRef = useRef(null); const [dropdownStyle, setDropdownStyle] = useState({}); const updatePosition = useCallback(() => { if (!bellRef.current) return; const rect = bellRef.current.getBoundingClientRect(); if (isMobile) { setDropdownStyle({ top: rect.bottom + 6, left: "1rem", right: "1rem", }); } else { setDropdownStyle({ top: rect.bottom + 6, right: window.innerWidth - rect.right, }); } }, [isMobile]); useEffect(() => { if (!isDropdownOpen) return; updatePosition(); const handleMouseDown = (e: MouseEvent) => { const target = e.target as Node; if ( dropdownRef.current && !dropdownRef.current.contains(target) && !bellRef.current?.contains(target) ) { setIsDropdownOpen(false); } }; const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Escape") { setIsDropdownOpen(false); } }; const handleResize = () => { updatePosition(); }; document.addEventListener("mousedown", handleMouseDown); document.addEventListener("keydown", handleKeyDown); window.addEventListener("resize", handleResize); return () => { document.removeEventListener("mousedown", handleMouseDown); document.removeEventListener("keydown", handleKeyDown); window.removeEventListener("resize", handleResize); }; }, [isDropdownOpen, setIsDropdownOpen, updatePosition]); useEffect(() => { if (isDropdownOpen) { void refreshList(); } }, [isDropdownOpen, refreshList]); if (isMobileTerminal) { return null; } const badgeText = unreadCount > 99 ? "99+" : String(unreadCount); return (
{isDropdownOpen && createPortal( <> {isMobile && (
setIsDropdownOpen(false)} aria-hidden="true" /> )}
Notifications
    {notifications.length === 0 ? (
  • No notifications
  • ) : ( notifications.map((n) => ( )) )}
{notifications.length > 0 && (
)}
, document.body, )}
); }