diff --git a/frontend/src/components/analytics/ActivityChart.tsx b/frontend/src/components/analytics/ActivityChart.tsx index 46ba582..5c1d853 100644 --- a/frontend/src/components/analytics/ActivityChart.tsx +++ b/frontend/src/components/analytics/ActivityChart.tsx @@ -1,4 +1,3 @@ -import { AreaChart, Area, XAxis, YAxis, Tooltip, ResponsiveContainer, Legend } from "recharts"; import type { HourlyBucket } from "../../api/analytics"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"; @@ -36,44 +35,46 @@ export function ActivityChart({ hourly, loading }: ActivityChartProps) { Distribusi pesan per jam berdasarkan status moderasi. - - - - - { - const v = typeof value === "number" ? value : String(value); - return [v, label(String(name))]; - }} - /> - - - - - - - +
+
+ Clean + Warned + Flagged + Error +
+
+ {data.map((bucket) => { + const total = Math.max(bucket.total, 1); + const clean = bucket.clean / total; + const warned = bucket.warned / total; + const flagged = bucket.flagged / total; + const error = bucket.error / total; + return ( +
+
+ {bucket.hour} + {bucket.total} pesan +
+
+
+
+
+
+
+
+ ); + })} +
+
); } -function label(key: string): string { - const map: Record = { clean: "Clean", warned: "Warned", flagged: "Flagged", error: "Error" }; - return map[key] ?? key; -} - function LoadingBox() { return ( - + Memuat data... @@ -84,7 +85,7 @@ function LoadingBox() { function EmptyBox({ text }: { text: string }) { return ( - + {text} diff --git a/frontend/src/components/analytics/TrendChart.tsx b/frontend/src/components/analytics/TrendChart.tsx index 99e6cf5..ed9e1d5 100644 --- a/frontend/src/components/analytics/TrendChart.tsx +++ b/frontend/src/components/analytics/TrendChart.tsx @@ -1,4 +1,3 @@ -import { LineChart, Line, XAxis, YAxis, Tooltip, ResponsiveContainer, Legend } from "recharts"; import type { TrendBucket } from "../../api/analytics"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"; @@ -32,39 +31,66 @@ export function TrendChart({ trend, loading }: TrendChartProps) { Volume pesan per hari dengan status moderasi. - - - d.slice(5)} /> - - { - const v = typeof value === "number" ? value : String(value); - return [v, label(String(name))]; - }} - labelFormatter={(l: unknown) => String(l)} - /> - - - - - - - +
+
+ Total + Clean + Warned + Flagged +
+
+ + + {Array.from({ length: 5 }, (_, index) => { + const y = (index / 4) * 100; + return ; + })} + + + + + + +
+ {data.map((item) => ( +
+ {item.date.slice(5)} +
+ ))} +
+
+
); } -function label(key: string): string { - const map: Record = { total: "Total", clean: "Clean", warned: "Warned", flagged: "Flagged" }; - return map[key] ?? key; +function TrendPath({ + data, + color, + strokeWidth, + keyName, +}: { + data: Array>; + color: string; + strokeWidth: number; + keyName: string; +}) { + const values = data.map((item) => Number(item[keyName] ?? 0)); + const maxValue = Math.max(...values, 1); + const points = values.map((value, index) => { + const x = data.length <= 1 ? 0 : (index / (data.length - 1)) * 100; + const y = 100 - (value / maxValue) * 90 - 5; + return `${x},${y}`; + }); + + return ; } function LoadingBox() { return ( - + Memuat data...