import { useState, useRef, useEffect } from 'react'; import { Bell, Clipboard, FileText, GraduationCap, GitGraph, Building2, Info, CheckCircle2, AlertCircle, AlertTriangle, Trash2, X } from 'lucide-react'; import { useAppDispatch, useAppSelector } from '@/hooks/redux-hooks'; import { markReadAsync, readAllAsync, fetchNotifications } from '@/store/notificationSlice'; import { formatDistanceToNow } from 'date-fns'; import { cn } from '@/lib/utils'; import { useNavigate } from 'react-router-dom'; import type { Notification, NotificationType, NotificationCategory } from '@/types/notification'; import { notificationService } from '@/services/notification-service'; import { showToast } from '@/utils/toast'; const getNotificationIcon = (category?: NotificationCategory, type?: NotificationType) => { switch (category) { case 'capa': return ; case 'document': return ; case 'training': return ; case 'workflow': return ; case 'supplier': return ; case 'system': return ; default: switch (type) { case 'success': return ; case 'warning': return ; case 'action_required': return ; default: return ; } } }; const getTypeColor = (type: NotificationType) => { switch (type) { case 'success': return 'text-green-500 bg-green-50'; case 'warning': return 'text-orange-500 bg-orange-50'; case 'action_required': return 'text-amber-500 bg-amber-50'; case 'escalation': return 'text-red-500 bg-red-50'; default: return 'text-blue-500 bg-blue-50'; } }; export const NotificationBell = () => { const [isOpen, setIsOpen] = useState(false); const dispatch = useAppDispatch(); const navigate = useNavigate(); const { notifications, unread_count } = useAppSelector((state) => state.notifications); const { roles } = useAppSelector((state) => state.auth); const dropdownRef = useRef(null); // Handle click outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { setIsOpen(false); } }; if (isOpen) { document.addEventListener('mousedown', handleClickOutside); } return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [isOpen]); const handleMarkAllRead = () => { dispatch(readAllAsync()); }; const handleNotificationClick = (notification: Notification) => { if (!notification.is_read) { dispatch(markReadAsync(notification.id)); } // Special handling for tasks as requested - redirect to My Tasks tab if (['workflow', 'training'].includes(notification.category || '')) { navigate('/tenant/tasks'); setIsOpen(false); return; } // Special handling for system as requested - redirect to Dashboard if (['system'].includes(notification.category || '')) { navigate('/tenant'); setIsOpen(false); return; } if (notification.action_url) { navigate(notification.action_url); } setIsOpen(false); }; const handleDismiss = async (e: React.MouseEvent, id: string) => { e.stopPropagation(); try { await notificationService.dismiss(id); dispatch(fetchNotifications({ limit: 20 })); showToast.success('Notification dismissed'); } catch (error) { showToast.error('Failed to dismiss notification'); } }; const handleDismissAll = async () => { try { await notificationService.dismissAll(); dispatch(fetchNotifications({ limit: 20 })); showToast.success('All notifications dismissed'); } catch (error) { showToast.error('Failed to dismiss all notifications'); } }; return (
{isOpen && (
{/* Header */}

Notifications

{unread_count > 0 && ( )}
{/* List */}
{notifications.length === 0 ? (

All caught up!

No notifications to show right now.

) : (
{notifications.map((notification) => (
handleNotificationClick(notification)} className={cn( "group relative px-4 py-4 hover:bg-gray-50 transition-colors cursor-pointer flex gap-3", !notification.is_read && "bg-blue-50/30" )} >
{getNotificationIcon(notification.category, notification.notification_type)}

{notification.title}

{formatDistanceToNow(new Date(notification.created_at), { addSuffix: true })}

{notification.message}

{notification.entity_name && (
{notification.entity_type?.replace('_', ' ')} {notification.entity_name}
)}
{/* Quick Actions */}
{/* Unread indicator dot */} {!notification.is_read && (
)}
))}
)}
{/* Footer */}
)}
); };