draupnir4all-web

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

page.tsx (8317B)


      1 import { listBots } from "@/lib/api";
      2 import { User } from "@/lib/auth";
      3 import { cookies } from "next/headers";
      4 import SettingsLayout from "../settingsLayout";
      5 import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
      6 import { Button } from "@/components/ui/button";
      7 import { LogOut, Settings, UserPlus } from "lucide-react";
      8 import { Label } from "@/components/ui/label";
      9 import { Input } from "@/components/ui/input";
     10 import { ScrollArea } from "@/components/ui/scroll-area";
     11 import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
     12 import { Badge } from "@/components/ui/badge";
     13 import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
     14 
     15 export default async function MembersSettingsPage({
     16     searchParams,
     17 }: {
     18     searchParams: Promise<{ [key: string]: string | string[] | undefined }>
     19 }) {
     20     const teamIdParam = (await searchParams).team as string | undefined;
     21     const cookieStore = await cookies()
     22     const session: User = JSON.parse(cookieStore.get("d4all_session")?.value || "{}")
     23     if (!session.token) {
     24         return <div className="flex h-screen w-full items-center justify-center">Loading...</div>
     25     }
     26     const listData = await listBots(session.matrixId, session.token);
     27 
     28     if (!listData) {
     29         return <div className="flex h-screen w-full items-center justify-center">Loading...</div>
     30     }
     31 
     32     const selectedBot = listData.bots.find((team) => team.id === teamIdParam) ?? listData.bots[0];
     33     if (!selectedBot) {
     34         // TODO: Redirect to register page?
     35         return <div className="flex h-screen w-full items-center justify-center">Loading...</div>
     36     }
     37     // TODO: get teams from the API
     38     // @ts-expect-error - members is not a property of the data yet
     39     selectedBot.members = []
     40 
     41     return (
     42         <SettingsLayout currentTab={"members"} listData={listData} selectedBot={selectedBot} teamIdParam={teamIdParam}>
     43             <div className="flex items-center justify-between">
     44                 <h3 className="text-sm font-medium text-gray-400">Team Members</h3>
     45                 <Dialog>
     46                     <DialogTrigger asChild>
     47                         <Button size="sm" className="bg-purple-600 text-white hover:bg-purple-700">
     48                             <UserPlus className="mr-2 h-4 w-4" />
     49                             Invite Member
     50                         </Button>
     51                     </DialogTrigger>
     52                     <DialogContent className="bg-gray-950 border-gray-800">
     53                         <DialogHeader>
     54                             <DialogTitle>Invite Team Member</DialogTitle>
     55                             <DialogDescription className="text-gray-400">
     56                                 Invite a Matrix user to join your moderation team
     57                             </DialogDescription>
     58                         </DialogHeader>
     59                         <div className="space-y-4 py-4">
     60                             <div className="space-y-2">
     61                                 <Label htmlFor="invite-matrix-id">Matrix ID</Label>
     62                                 <Input
     63                                     id="invite-matrix-id"
     64                                     placeholder="@user:matrix.org"
     65                                     className="bg-gray-900 border-gray-800"
     66                                 />
     67                             </div>
     68                             <div className="space-y-2">
     69                                 <Label htmlFor="invite-role">Role</Label>
     70                                 <select
     71                                     id="invite-role"
     72                                     className="w-full rounded-md border border-gray-800 bg-gray-900 px-3 py-2 text-sm"
     73                                 >
     74                                     <option value="moderator">Moderator</option>
     75                                     <option value="viewer">Viewer (Read-only)</option>
     76                                 </select>
     77                             </div>
     78                         </div>
     79                         <DialogFooter>
     80                             <Button
     81                                 variant="outline"
     82                                 className="border-gray-700 text-gray-400 hover:bg-gray-900 hover:text-gray-300"
     83                             >
     84                                 Cancel
     85                             </Button>
     86                             <Button className="bg-purple-600 text-white hover:bg-purple-700">
     87                                 Send Invitation
     88                             </Button>
     89                         </DialogFooter>
     90                     </DialogContent>
     91                 </Dialog>
     92             </div>
     93 
     94             <ScrollArea className="h-[300px] rounded-md border border-gray-800">
     95                 <div className="p-4 space-y-3">
     96                     {/* @ts-expect-error - members is not yet a thing */}
     97                     {selectedBot.members.map((member) => (
     98                         <div key={member.id} className="flex items-center justify-between p-3 rounded-md bg-gray-900">
     99                             <div className="flex items-center gap-3">
    100                                 <Avatar className="h-10 w-10 border border-gray-800">
    101                                     <AvatarImage src={member.avatar || ""} />
    102                                     <AvatarFallback className="bg-gray-800 text-gray-400">
    103                                         {member.name.substring(1, 3).toUpperCase()}
    104                                     </AvatarFallback>
    105                                 </Avatar>
    106                                 <div>
    107                                     <p className="font-medium">{member.name}</p>
    108                                     <div className="flex items-center gap-2">
    109                                         <Badge
    110                                             className={
    111                                                 member.role === "owner"
    112                                                     ? "bg-purple-900/50 text-purple-300"
    113                                                     : "bg-blue-900/50 text-blue-300"
    114                                             }
    115                                         >
    116                                             {member.role}
    117                                         </Badge>
    118                                         <span className="text-xs text-gray-500">
    119                                             Joined {new Date(member.joined).toLocaleDateString()}
    120                                         </span>
    121                                     </div>
    122                                 </div>
    123                             </div>
    124                             {member.role !== "owner" && (
    125                                 <DropdownMenu>
    126                                     <DropdownMenuTrigger asChild>
    127                                         <Button variant="ghost" size="sm" className="h-8 w-8 p-0">
    128                                             <span className="sr-only">Open menu</span>
    129                                             <Settings className="h-4 w-4" />
    130                                         </Button>
    131                                     </DropdownMenuTrigger>
    132                                     <DropdownMenuContent align="end" className="bg-gray-900 border-gray-800">
    133                                         <DropdownMenuItem className="text-yellow-400 focus:text-yellow-400 focus:bg-yellow-900/20">
    134                                             <Settings className="mr-2 h-4 w-4" />
    135                                             Change Role
    136                                         </DropdownMenuItem>
    137                                         <DropdownMenuItem className="text-red-400 focus:text-red-400 focus:bg-red-900/20">
    138                                             <LogOut className="mr-2 h-4 w-4" />
    139                                             Remove from Team
    140                                         </DropdownMenuItem>
    141                                     </DropdownMenuContent>
    142                                 </DropdownMenu>
    143                             )}
    144                         </div>
    145                     ))}
    146                 </div>
    147             </ScrollArea>
    148         </SettingsLayout>
    149     )
    150 }