draupnir4all-web

git clone git://archive.git.mtrnord.blog/MTRNord/draupnir4all-web.git
Log | Files | Refs | README | LICENSE

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 }