import React, { useState, useRef, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { Bell, Mail, CheckCheck, ChevronRight, Inbox, Clock, Sparkles, } from 'lucide-react'; import { useInAppNotifications } from '../../hooks/useInAppNotifications'; import { formatDate } from '../../lib/formatters'; import { stripMarkdown } from '../../lib/markdownUtils'; export const NotificationBell: React.FC = () => { const navigate = useNavigate(); const { top5Unread, unreadCount, markAsRead, markAllAsRead } = useInAppNotifications(); const [isOpen, setIsOpen] = useState(false); const leaveTimerRef = useRef(null); const containerRef = useRef(null); // Clear timer on unmount useEffect(() => { return () => { if (leaveTimerRef.current) { window.clearTimeout(leaveTimerRef.current); } }; }, []); const handleMouseEnter = () => { if (leaveTimerRef.current) { window.clearTimeout(leaveTimerRef.current); leaveTimerRef.current = null; } setIsOpen(true); }; const handleMouseLeave = () => { leaveTimerRef.current = window.setTimeout(() => { setIsOpen(false); }, 250); }; const handleNotificationClick = async (id: number | string) => { await markAsRead(id); setIsOpen(false); navigate(`/inbox?id=${id}`); }; const handleViewAll = () => { setIsOpen(false); navigate('/inbox'); }; // Format relative timestamp const getRelativeTime = (dateStr?: string) => { if (!dateStr) return ''; try { const now = new Date(); const date = new Date(dateStr); const diffMs = now.getTime() - date.getTime(); const diffMins = Math.floor(diffMs / (1000 * 60)); const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); if (diffMins < 1) return 'Just now'; if (diffMins < 60) return `${diffMins}m ago`; if (diffHours < 24) return `${diffHours}h ago`; if (diffDays < 7) return `${diffDays}d ago`; return formatDate(dateStr); } catch { return ''; } }; return (
{/* Bell Button */} {/* Floating Hover Popover */} {isOpen && (
{/* Popover Header */}

In-App Notifications

{unreadCount > 0 && ( {unreadCount} unread )}
{unreadCount > 0 && ( )}
{/* Top 5 Notifications List */}
{top5Unread.length === 0 ? (

All caught up!

No unread in-app notifications at this time.

) : ( top5Unread.map(item => { const relativeTime = getRelativeTime(item.createdAt); return (
handleNotificationClick(item.id)} className="p-3.5 hover:bg-slate-800/60 transition cursor-pointer group flex items-start gap-3 relative" > {/* Unread Accent Indicator */}

{item.subject || 'In-App Notification'}

{relativeTime && ( {relativeTime} )}

{stripMarkdown(item.message || 'No additional message content.')}

{item.destination && (

{item.destination}

)}
); }) )}
{/* Popover Footer: Open Inbox */}
)}
); };