draupnir4all-web

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

page.tsx (19430B)


      1 import { ChevronDown, Users } from "lucide-react"
      2 import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
      3 import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
      4 import { Heatmap } from "@/components/analytics/heatmap"
      5 import { BannedServerData, generateHeatmapData, getBannedServersConfig, getMonthlyActivityConfig, getReportTypesConfig, getRoomActivityConfig, MonthlyActivityData, ReportTypeData, RoomActivityData } from "@/components/analytics/chart-configs";
      6 import { PlotlyChart } from "@/components/analytics/plotly-chart";
      7 import { Button } from "@/components/ui/button";
      8 import Link from "next/link";
      9 import InfoCardWithTrend from "@/components/analytics/info-card-with-trend";
     10 import LayoutWrapper from "@/components/dashboard/layoutWrapper";
     11 import { cookies } from "next/headers"
     12 import { User } from "@/lib/auth"
     13 import { listBots } from "@/lib/api"
     14 import TabNavigation from "@/components/dashboard/tab-navigation";
     15 import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
     16 
     17 // Mock data for charts
     18 const roomActivityData: RoomActivityData[] = [
     19     { name: "#general:matrix.org", reports: 42, bans: 15 },
     20     { name: "#support:matrix.org", reports: 28, bans: 9 },
     21     { name: "#community:matrix.org", reports: 17, bans: 5 },
     22     { name: "#development:matrix.org", reports: 8, bans: 2 },
     23     { name: "#random:matrix.org", reports: 5, bans: 1 },
     24 ]
     25 
     26 const reportTypesData: ReportTypeData[] = [
     27     { id: 1, label: "Spam", value: 45, color: "#f97316" },
     28     { id: 2, label: "Harassment", value: 32, color: "#ef4444" },
     29     { id: 3, label: "Inappropriate Content", value: 28, color: "#ec4899" },
     30     { id: 4, label: "Scam", value: 15, color: "#f59e0b" },
     31     { id: 5, label: "Other", value: 10, color: "#6366f1" },
     32 ]
     33 
     34 const bannedServersData: BannedServerData[] = [
     35     { label: "spam.org", value: 28, secondaryLabel: "28 users" },
     36     { label: "scam.net", value: 17, secondaryLabel: "17 users" },
     37     { label: "badactor.io", value: 12, secondaryLabel: "12 users" },
     38     { label: "malicious.com", value: 9, secondaryLabel: "9 users" },
     39     { label: "troll.xyz", value: 7, secondaryLabel: "7 users" },
     40 ]
     41 
     42 // Enhanced monthly activity data with more realistic patterns
     43 const monthlyActivityData: MonthlyActivityData[] = [
     44     { month: "Jan", reports: 24, bans: 8, year: 2025 },
     45     { month: "Feb", reports: 32, bans: 12, year: 2025 },
     46     { month: "Mar", reports: 45, bans: 18, year: 2025 },
     47     { month: "Apr", reports: 38, bans: 15, year: 2025 },
     48     { month: "May", reports: 29, bans: 11, year: 2025 },
     49     { month: "Jun", reports: 35, bans: 14, year: 2025 },
     50     { month: "Jul", reports: 42, bans: 17, year: 2025 },
     51     { month: "Aug", reports: 50, bans: 22, year: 2025 },
     52     { month: "Sep", reports: 43, bans: 19, year: 2025 },
     53     { month: "Oct", reports: 37, bans: 16, year: 2025 },
     54     { month: "Nov", reports: 31, bans: 13, year: 2025 },
     55     { month: "Dec", reports: 28, bans: 10, year: 2025 },
     56 ]
     57 
     58 
     59 export default async function AnalyticsDashboard({
     60     searchParams,
     61 }: {
     62     searchParams: Promise<{ [key: string]: string | string[] | undefined }>
     63 }) {
     64     const params = await searchParams;
     65     const teamIdParam = params.team as string | undefined;
     66     const timeRange = (params.timeRange as string | undefined) ?? "year"
     67     const heatmapType = (params.heatmapType as string | undefined) ?? "reports"
     68     const cookieStore = await cookies()
     69     const session: User = JSON.parse(cookieStore.get("d4all_session")?.value ?? "{}")
     70     if (!session.token) {
     71         return <div className="flex h-screen w-full items-center justify-center">Loading...</div>
     72     }
     73     const listData = await listBots(session.matrixId, session.token);
     74 
     75     if (!listData) {
     76         return <div className="flex h-screen w-full items-center justify-center">Loading...</div>
     77     }
     78 
     79     const selectedBot = listData.bots.find((team) => team.id === teamIdParam) ?? listData.bots[0];
     80     if (!selectedBot) {
     81         // TODO: Redirect to register page?
     82         return <div className="flex h-screen w-full items-center justify-center">Loading...</div>
     83     }
     84 
     85     // Generate mock data
     86     const reportsHeatmapData = generateHeatmapData(1.5, 42)
     87     const bansHeatmapData = generateHeatmapData(1, 123)
     88 
     89     // Get chart configurations
     90     const roomActivityConfig = getRoomActivityConfig(roomActivityData)
     91     const reportTypesConfig = getReportTypesConfig(reportTypesData)
     92     const monthlyActivityConfig = getMonthlyActivityConfig(monthlyActivityData)
     93     const bannedServersConfig = getBannedServersConfig(bannedServersData)
     94 
     95 
     96     const reportChangePercent = 12
     97 
     98     return (
     99         <LayoutWrapper listData={listData} activeTab="analytics" teamIdParam={teamIdParam}>
    100             <TabNavigation selectedBot={selectedBot} currentTab="analytics" />
    101             <div className="space-y-4">
    102                 <div className="flex items-center  justify-end">
    103                     <DropdownMenu>
    104                         <DropdownMenuTrigger asChild>
    105                             <Button variant="outline" className="h-8 w-[120px] bg-gray-900 border border-gray-800 text-gray-400 rounded-md flex items-center justify-between">
    106                                 <span>{timeRange.charAt(0).toUpperCase() + timeRange.slice(1)}</span>
    107                                 <ChevronDown className="ml-2 h-4 w-4" />
    108                             </Button>
    109                         </DropdownMenuTrigger>
    110                         <DropdownMenuContent className="flex flex-col gap-1 w-56 bg-gray-900 border-gray-800">
    111                             <DropdownMenuItem asChild>
    112                                 <Link
    113                                     href={`/dashboard/analytics?team=${teamIdParam}&timeRange=month&heatmapType=${heatmapType}`}
    114                                     className={timeRange === "month" ? "bg-gray-800 text-white" : "text-gray-400 hover:bg-gray-800"}
    115                                 >
    116                                     Past Month
    117                                 </Link>
    118                             </DropdownMenuItem>
    119                             <DropdownMenuItem asChild>
    120                                 <Link
    121                                     href={`/dashboard/analytics?team=${teamIdParam}&timeRange=quarter&heatmapType=${heatmapType}`}
    122                                     className={timeRange === "quarter" ? "bg-gray-800 text-white" : "text-gray-400 hover:bg-gray-800"}
    123                                 >
    124                                     Past Quarter
    125                                 </Link>
    126                             </DropdownMenuItem>
    127                             <DropdownMenuItem asChild>
    128                                 <Link
    129                                     href={`/dashboard/analytics?team=${teamIdParam}&timeRange=year&heatmapType=${heatmapType}`}
    130                                     className={timeRange === "year" ? "bg-gray-800 text-white" : "text-gray-400 hover:bg-gray-800"}
    131                                 >
    132                                     Past Year
    133                                 </Link>
    134                             </DropdownMenuItem>
    135                             <DropdownMenuItem asChild>
    136                                 <Link
    137                                     href={`/dashboard/analytics?team=${teamIdParam}&timeRange=all&heatmapType=${heatmapType}`}
    138                                     className={timeRange === "all" ? "bg-gray-800 text-white" : "text-gray-400 hover:bg-gray-800"}
    139                                 >
    140                                     All Time
    141                                 </Link>
    142                             </DropdownMenuItem>
    143                         </DropdownMenuContent>
    144                     </DropdownMenu>
    145                 </div>
    146 
    147                 <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
    148                     <InfoCardWithTrend title="Total Reports" changePercent={12} value={247} trendColorOverride={reportChangePercent > 0 ? "text-red-400" : "text-green-400"} />
    149                     <InfoCardWithTrend title="Bans Issued" changePercent={5} value={98} />
    150                     <InfoCardWithTrend title="Unique Reporters" changePercent={8} value={42} />
    151                     <InfoCardWithTrend title="Avg. Response Time" changePercent={-15} value="1.4h" />
    152                 </div>
    153 
    154                 <Card className="border-gray-800 bg-gray-950">
    155                     <CardHeader>
    156                         <div className="flex items-center justify-between">
    157                             <div>
    158                                 <CardTitle>Activity Heatmap</CardTitle>
    159                                 <CardDescription className="text-gray-400">
    160                                     Visualization of moderation activity over time
    161                                 </CardDescription>
    162                             </div>
    163                             <Tabs value={heatmapType}>
    164                                 <TabsList className="bg-gray-900">
    165                                     <TabsTrigger value="reports" className="text-xs" asChild>
    166                                         <Link
    167                                             href={`/dashboard/analytics?team=${teamIdParam}&timeRange=${timeRange}&heatmapType=reports`}>
    168                                             Reports
    169                                         </Link>
    170                                     </TabsTrigger>
    171                                     <TabsTrigger value="bans" className="text-xs" asChild>
    172                                         <Link
    173                                             href={`/dashboard/analytics?team=${teamIdParam}&timeRange=${timeRange}&heatmapType=bans`}>
    174                                             Bans
    175                                         </Link>
    176                                     </TabsTrigger>
    177                                 </TabsList>
    178                             </Tabs>
    179                         </div>
    180                     </CardHeader>
    181                     <CardContent className="overflow-hidden">
    182                         <Heatmap
    183                             data={heatmapType === "reports" ? reportsHeatmapData : bansHeatmapData}
    184                             title={`${heatmapType === "reports" ? "Reports Activity" : "Ban Actions"} (Past Year)`}
    185                             colorIntensityLabel={heatmapType === "reports" ? "reports" : "bans"}
    186                         />
    187                     </CardContent>
    188                 </Card>
    189 
    190                 <div className="grid gap-4 md:grid-cols-2">
    191                     <Card className="border-gray-800 bg-gray-950">
    192                         <CardHeader>
    193                             <CardTitle>Room Activity</CardTitle>
    194                             <CardDescription className="text-gray-400">Reports and bans by room</CardDescription>
    195                         </CardHeader>
    196                         <CardContent>
    197                             <PlotlyChart data={roomActivityConfig.data} layout={roomActivityConfig.layout} />
    198                         </CardContent>
    199                     </Card>
    200 
    201                     <Card className="border-gray-800 bg-gray-950">
    202                         <CardHeader>
    203                             <CardTitle>Report Types</CardTitle>
    204                             <CardDescription className="text-gray-400">Distribution of report reasons</CardDescription>
    205                         </CardHeader>
    206                         <CardContent>
    207                             <PlotlyChart data={reportTypesConfig.data} layout={reportTypesConfig.layout} />
    208                         </CardContent>
    209                     </Card>
    210                 </div>
    211 
    212                 <div className="grid gap-4 md:grid-cols-2">
    213                     <Card className="border-gray-800 bg-gray-950">
    214                         <CardHeader>
    215                             <CardTitle>Monthly Activity</CardTitle>
    216                             <CardDescription className="text-gray-400">Reports and bans over the past year</CardDescription>
    217                         </CardHeader>
    218                         <CardContent>
    219                             <PlotlyChart data={monthlyActivityConfig.data} layout={monthlyActivityConfig.layout} />
    220                         </CardContent>
    221                     </Card>
    222 
    223                     <Card className="border-gray-800 bg-gray-950">
    224                         <CardHeader>
    225                             <CardTitle>Most Banned Servers</CardTitle>
    226                             <CardDescription className="text-gray-400">Servers with the most banned users</CardDescription>
    227                         </CardHeader>
    228                         <CardContent>
    229                             <PlotlyChart data={bannedServersConfig.data} layout={bannedServersConfig.layout} />
    230                             <div className="mt-4 flex items-center justify-center">
    231                                 <Button variant="outline" size="sm" className="border-gray-800 text-gray-400 hover:text-white" asChild>
    232                                     <Link href={`/dashboard/bans?team=${selectedBot.id}&heatmapType=${heatmapType}&timeRange=${timeRange}`}>
    233                                         <Users className="mr-2 h-4 w-4" />
    234                                         View All Banned Servers
    235                                     </Link>
    236                                 </Button>
    237                             </div>
    238                         </CardContent>
    239                     </Card>
    240                 </div>
    241 
    242                 <Card className="border-gray-800 bg-gray-950">
    243                     <CardHeader>
    244                         <CardTitle>Moderation Efficiency</CardTitle>
    245                         <CardDescription className="text-gray-400">
    246                             Key performance indicators for your moderation team
    247                         </CardDescription>
    248                     </CardHeader>
    249                     <CardContent>
    250                         <div className="grid gap-4 md:grid-cols-3">
    251                             <div className="space-y-2">
    252                                 <h3 className="text-sm font-medium text-gray-400">Average Response Time</h3>
    253                                 <div className="flex items-end gap-2">
    254                                     <span className="text-2xl font-bold">1.4h</span>
    255                                     <span className="text-xs text-green-400">-15% from last month</span>
    256                                 </div>
    257                                 <p className="text-xs text-gray-400">Time between report creation and moderator action</p>
    258                             </div>
    259 
    260                             <div className="space-y-2">
    261                                 <h3 className="text-sm font-medium text-gray-400">Resolution Rate</h3>
    262                                 <div className="flex items-end gap-2">
    263                                     <span className="text-2xl font-bold">92%</span>
    264                                     <span className="text-xs text-green-400">+3% from last month</span>
    265                                 </div>
    266                                 <p className="text-xs text-gray-400">Percentage of reports that were resolved</p>
    267                             </div>
    268 
    269                             <div className="space-y-2">
    270                                 <h3 className="text-sm font-medium text-gray-400">Moderator Activity</h3>
    271                                 <div className="flex items-end gap-2">
    272                                     <span className="text-2xl font-bold">4.2</span>
    273                                     <span className="text-xs text-gray-400">actions per day</span>
    274                                 </div>
    275                                 <p className="text-xs text-gray-400">Average number of moderation actions per day</p>
    276                             </div>
    277                         </div>
    278 
    279                         <div className="mt-6">
    280                             <h3 className="mb-2 text-sm font-medium text-gray-400">Moderator Performance</h3>
    281                             <div className="space-y-3">
    282                                 <div className="flex items-center gap-3">
    283                                     <div className="flex h-8 w-8 items-center justify-center rounded-full bg-purple-900 text-xs font-medium">
    284                                         AM
    285                                     </div>
    286                                     <div className="flex-1">
    287                                         <div className="flex items-center justify-between">
    288                                             <span className="text-sm">@admin:matrix.org</span>
    289                                             <span className="text-xs text-gray-400">42 actions</span>
    290                                         </div>
    291                                         <div className="mt-1 h-1.5 w-full overflow-hidden rounded-full bg-gray-900">
    292                                             <div className="h-full rounded-full bg-purple-600" style={{ width: "85%" }}></div>
    293                                         </div>
    294                                     </div>
    295                                 </div>
    296 
    297                                 <div className="flex items-center gap-3">
    298                                     <div className="flex h-8 w-8 items-center justify-center rounded-full bg-blue-900 text-xs font-medium">
    299                                         M1
    300                                     </div>
    301                                     <div className="flex-1">
    302                                         <div className="flex items-center justify-between">
    303                                             <span className="text-sm">@mod1:matrix.org</span>
    304                                             <span className="text-xs text-gray-400">36 actions</span>
    305                                         </div>
    306                                         <div className="mt-1 h-1.5 w-full overflow-hidden rounded-full bg-gray-900">
    307                                             <div className="h-full rounded-full bg-blue-600" style={{ width: "72%" }}></div>
    308                                         </div>
    309                                     </div>
    310                                 </div>
    311 
    312                                 <div className="flex items-center gap-3">
    313                                     <div className="flex h-8 w-8 items-center justify-center rounded-full bg-green-900 text-xs font-medium">
    314                                         M2
    315                                     </div>
    316                                     <div className="flex-1">
    317                                         <div className="flex items-center justify-between">
    318                                             <span className="text-sm">@mod2:matrix.org</span>
    319                                             <span className="text-xs text-gray-400">28 actions</span>
    320                                         </div>
    321                                         <div className="mt-1 h-1.5 w-full overflow-hidden rounded-full bg-gray-900">
    322                                             <div className="h-full rounded-full bg-green-600" style={{ width: "56%" }}></div>
    323                                         </div>
    324                                     </div>
    325                                 </div>
    326                             </div>
    327                         </div>
    328                     </CardContent>
    329                 </Card>
    330             </div>
    331         </LayoutWrapper>
    332     )
    333 }