"use client" import { useEffect, useState } from "react" import Link from "next/link" import { useRouter } from "next/navigation" import { Bell, CheckCheck, MessageSquare, Megaphone, PenTool, GraduationCap } from "lucide-react" import { Badge } from "@/shared/components/ui/badge" import { Button } from "@/shared/components/ui/button" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/shared/components/ui/dropdown-menu" import { ScrollArea } from "@/shared/components/ui/scroll-area" import { cn, formatDate } from "@/shared/lib/utils" import { getNotificationsAction, getUnreadNotificationCountAction, markAllNotificationsAsReadAction, markNotificationAsReadAction, } from "../actions" import type { Notification, NotificationType } from "@/modules/notifications/types" const TYPE_ICON: Record = { message: MessageSquare, announcement: Megaphone, homework: PenTool, grade: GraduationCap, } export function NotificationDropdown() { const router = useRouter() const [notifications, setNotifications] = useState([]) const [unreadCount, setUnreadCount] = useState(0) const [open, setOpen] = useState(false) useEffect(() => { let active = true const fetchNotifications = async () => { const res = await getNotificationsAction({ pageSize: 10 }) if (!active) return if (res.success && res.data) { setNotifications(res.data.items) } } const fetchUnreadCount = async () => { const res = await getUnreadNotificationCountAction() if (!active) return if (res.success && typeof res.data === "number") { setUnreadCount(res.data) } } void fetchNotifications() void fetchUnreadCount() // 每 30 秒轮询刷新通知和未读计数 const timer = setInterval(() => { void fetchNotifications() void fetchUnreadCount() }, 30_000) return () => { active = false clearInterval(timer) } }, []) const handleMarkAllRead = async () => { const res = await markAllNotificationsAsReadAction() if (res.success) { setNotifications((prev) => prev.map((n) => ({ ...n, isRead: true }))) setUnreadCount(0) router.refresh() } } const handleMarkRead = async (id: string) => { const res = await markNotificationAsReadAction(id) if (res.success) { setNotifications((prev) => prev.map((n) => (n.id === id ? { ...n, isRead: true } : n)) ) setUnreadCount((c) => Math.max(0, c - 1)) router.refresh() } } return ( Notifications {unreadCount > 0 ? ( ) : null} {notifications.length === 0 ? (
No notifications
) : ( notifications.map((n) => { const Icon = TYPE_ICON[n.type] ?? Bell return ( { if (!n.isRead) { e.preventDefault() handleMarkRead(n.id) } }} >
{!n.isRead ? ( ) : null} {n.title}
{n.content ? (

{n.content}

) : null} {formatDate(n.createdAt)}
) }) )}
View all notifications
) }