import { useEffect, useRef, useState } from "react" import { useNavigate } from "react-router-dom" import { Bell, BellOff, Info, AlertCircle, CheckCircle2, Megaphone, UserPlus, CreditCard, BookOpen, Video, ShieldAlert, MailOpen, Mail, CheckCheck, } from "lucide-react" import { Badge } from "../ui/badge" import { cn } from "../../lib/utils" import { SpinnerIcon } from "../ui/spinner-icon" import { useNotifications } from "../../hooks/useNotifications" import { getNotificationMessage, getNotificationTitle, type Notification } from "../../types/notification.types" const TYPE_CONFIG: Record = { announcement: { icon: Megaphone, color: "text-brand-600", bg: "bg-brand-100" }, system_alert: { icon: ShieldAlert, color: "text-amber-600", bg: "bg-amber-50" }, issue_created: { icon: AlertCircle, color: "text-red-500", bg: "bg-red-50" }, issue_status_updated: { icon: CheckCircle2, color: "text-sky-600", bg: "bg-sky-50" }, course_created: { icon: BookOpen, color: "text-indigo-600", bg: "bg-indigo-50" }, course_enrolled: { icon: BookOpen, color: "text-teal-600", bg: "bg-teal-50" }, sub_course_created: { icon: BookOpen, color: "text-violet-600", bg: "bg-violet-50" }, video_added: { icon: Video, color: "text-pink-600", bg: "bg-pink-50" }, user_deleted: { icon: UserPlus, color: "text-red-600", bg: "bg-red-50" }, admin_created: { icon: UserPlus, color: "text-brand-600", bg: "bg-brand-100" }, team_member_created: { icon: UserPlus, color: "text-emerald-600", bg: "bg-emerald-50" }, subscription_activated: { icon: CreditCard, color: "text-green-600", bg: "bg-green-50" }, payment_verified: { icon: CreditCard, color: "text-green-600", bg: "bg-green-50" }, knowledge_level_update: { icon: Info, color: "text-sky-600", bg: "bg-sky-50" }, assessment_assigned: { icon: BookOpen, color: "text-orange-600", bg: "bg-orange-50" }, } const DEFAULT_TYPE_CONFIG = { icon: Bell, color: "text-grayScale-500", bg: "bg-grayScale-100" } function formatTimestamp(ts: string) { const date = new Date(ts) const now = new Date() const diffMs = now.getTime() - date.getTime() const diffMin = Math.floor(diffMs / 60_000) const diffHr = Math.floor(diffMs / 3_600_000) const diffDay = Math.floor(diffMs / 86_400_000) if (diffMin < 1) return "Just now" if (diffMin < 60) return `${diffMin}m ago` if (diffHr < 24) return `${diffHr}h ago` if (diffDay < 7) return `${diffDay}d ago` return date.toLocaleDateString("en-US", { month: "short", day: "numeric", year: date.getFullYear() !== now.getFullYear() ? "numeric" : undefined, }) } function NotificationItem({ notification, onMarkRead, onMarkUnread, }: { notification: Notification onMarkRead: (id: string) => void onMarkUnread: (id: string) => void }) { const cfg = TYPE_CONFIG[notification.type] ?? DEFAULT_TYPE_CONFIG const Icon = cfg.icon return ( ) } export function NotificationDropdown() { const [open, setOpen] = useState(false) const containerRef = useRef(null) const navigate = useNavigate() const { notifications, unreadCount, loading, markOneRead, markOneUnread, markAllAsRead, } = useNotifications() // Click-outside handler useEffect(() => { function handleMouseDown(e: MouseEvent) { if (containerRef.current && !containerRef.current.contains(e.target as Node)) { setOpen(false) } } if (open) { document.addEventListener("mousedown", handleMouseDown) } return () => document.removeEventListener("mousedown", handleMouseDown) }, [open]) return (
{/* Bell button */} {/* Dropdown panel */} {open && (
{/* Header */}

Notifications

{unreadCount > 0 && ( {unreadCount} )}
{unreadCount > 0 && ( )}
{/* Body */}
{loading ? (
) : notifications.length === 0 ? (

No notifications

) : (
{notifications.map((n) => ( ))}
)}
{/* Footer */}
)}
) }