notifications.tsx (7392B)
1 "use client"; 2 3 import { Ban, Bell, Plus, X } from "lucide-react"; 4 import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover"; 5 import { ScrollArea } from "../ui/scroll-area"; 6 import { Button } from "../ui/button"; 7 import { useState } from "react"; 8 9 interface Notification { 10 id: string 11 type: string 12 title: string 13 message: string 14 timestamp: string 15 read: boolean 16 teamId?: string 17 } 18 19 export default function Notifications({ teamIdParam }: { teamIdParam?: string }) { 20 const [notifications, setNotifications] = useState<Notification[]>([ 21 { 22 id: "notif1", 23 type: "report", 24 title: "New report", 25 message: "A new message has been reported in #general", 26 timestamp: "2025-04-21T15:30:00Z", 27 read: false, 28 teamId: "team1", 29 }, 30 { 31 id: "notif2", 32 type: "ban", 33 title: "User banned", 34 message: "@spammer:matrix.org has been banned by @mod1:matrix.org", 35 timestamp: "2025-04-21T14:45:00Z", 36 read: false, 37 teamId: "team1", 38 }, 39 { 40 id: "notif3", 41 type: "invite", 42 title: "Team invitation", 43 message: "You've been invited to join the Support Team Bot", 44 timestamp: "2025-04-21T12:15:00Z", 45 read: true, 46 teamId: "team2", 47 }, 48 ]) 49 50 const teamNotifications = notifications.filter((n) => n.teamId === teamIdParam || !n.teamId) 51 const unreadCount = teamNotifications.filter((n) => !n.read).length 52 53 const markNotificationAsRead = (id: string) => { 54 setNotifications(notifications.map((n) => (n.id === id ? { ...n, read: true } : n))) 55 } 56 57 const clearAllNotifications = () => { 58 setNotifications(notifications.map((n) => ({ ...n, read: true }))) 59 } 60 61 const deleteNotification = (id: string) => { 62 setNotifications(notifications.filter((n) => n.id !== id)) 63 } 64 65 return ( 66 <> 67 {/* Notifications */} 68 < Popover > 69 <PopoverTrigger asChild> 70 <Button variant="ghost" size="icon" className="relative text-gray-400 hover:text-white"> 71 <Bell className="h-5 w-5" /> 72 {unreadCount > 0 && ( 73 <span className="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-red-500 text-[10px] font-medium text-white"> 74 {unreadCount} 75 </span> 76 )} 77 </Button> 78 </PopoverTrigger> 79 <PopoverContent className="w-80 p-0 bg-gray-900 border-gray-800"> 80 <div className="flex items-center justify-between border-b border-gray-800 p-3"> 81 <h3 className="font-medium">Notifications</h3> 82 <div className="flex items-center gap-1"> 83 <Button 84 variant="ghost" 85 size="sm" 86 className="h-7 px-2 text-xs text-gray-400 hover:text-white" 87 onClick={clearAllNotifications} 88 > 89 Clear all 90 </Button> 91 </div> 92 </div> 93 <ScrollArea className="h-[300px]"> 94 {teamNotifications.length > 0 ? ( 95 <div className="space-y-1 p-1"> 96 {teamNotifications.map((notification) => ( 97 <div 98 key={notification.id} 99 className={`flex items-start p-3 rounded-md ${notification.read ? "bg-gray-900" : "bg-gray-800"}`} 100 onClick={() => markNotificationAsRead(notification.id)} 101 > 102 <div 103 className={`rounded-full p-1.5 mr-3 ${notification.type === "report" 104 ? "bg-yellow-500/20" 105 : notification.type === "ban" 106 ? "bg-red-500/20" 107 : "bg-blue-500/20" 108 }`} 109 > 110 {notification.type === "report" ? ( 111 <Bell className="h-3.5 w-3.5 text-yellow-500" /> 112 ) : notification.type === "ban" ? ( 113 <Ban className="h-3.5 w-3.5 text-red-500" /> 114 ) : ( 115 <Plus className="h-3.5 w-3.5 text-blue-500" /> 116 )} 117 </div> 118 <div className="flex-1 min-w-0"> 119 <div className="flex items-center justify-between"> 120 <p className="text-sm font-medium">{notification.title}</p> 121 <Button 122 variant="ghost" 123 size="sm" 124 className="h-6 w-6 p-0 text-gray-500 hover:text-gray-300" 125 onClick={(e) => { 126 e.stopPropagation() 127 deleteNotification(notification.id) 128 }} 129 > 130 <X className="h-3 w-3" /> 131 <span className="sr-only">Dismiss</span> 132 </Button> 133 </div> 134 <p className="text-xs text-gray-400 line-clamp-2">{notification.message}</p> 135 <p className="text-xs text-gray-500 mt-1"> 136 {new Date(notification.timestamp).toLocaleString()} 137 </p> 138 </div> 139 </div> 140 ))} 141 </div> 142 ) : ( 143 <div className="flex flex-col items-center justify-center h-full p-6 text-center"> 144 <Bell className="h-8 w-8 text-gray-600 mb-2" /> 145 <p className="text-gray-400">No notifications</p> 146 </div> 147 )} 148 </ScrollArea> 149 </PopoverContent> 150 </Popover > 151 </> 152 ) 153 }