diff --git a/services/frontend/src/features/analytics/components/Heatmap.tsx b/services/frontend/src/features/analytics/components/Heatmap.tsx index fdd215f..1d40d47 100644 --- a/services/frontend/src/features/analytics/components/Heatmap.tsx +++ b/services/frontend/src/features/analytics/components/Heatmap.tsx @@ -1,4 +1,4 @@ -import { useMemo } from "react"; +import { useMemo, useState } from "react"; import type { HeatmapCell } from "../../../shared/api/client"; import { cn } from "../../../shared/lib/utils"; import { @@ -17,18 +17,22 @@ interface HeatmapProps { } export function Heatmap({ cells, loading }: HeatmapProps) { + const [tooltip, setTooltip] = useState<{ + day: string; + hour: string; + total: number; + clean: number; + warned: number; + flagged: number; + } | null>(null); + const maxCount = useMemo( () => Math.max(1, ...cells.map((c) => c.count)), [cells], ); - if (loading && !cells?.length) { - return ; - } - - if (!cells?.length) { - return ; - } + if (loading && !cells?.length) return ; + if (!cells?.length) return ; const cellMap = new Map(); for (const c of cells) cellMap.set(`${c.dayOfWeek}-${c.hour}`, c); @@ -38,13 +42,13 @@ export function Heatmap({ cells, loading }: HeatmapProps) { } function getHeatClass(intensity: number): string { - if (intensity === 0) return "bg-sky-50"; - if (intensity < 0.1) return "bg-sky-200/30"; - if (intensity < 0.2) return "bg-sky-300/30"; - if (intensity < 0.35) return "bg-sky-400/35"; - if (intensity < 0.5) return "bg-sky-400/55"; - if (intensity < 0.7) return "bg-primary/60"; - return "bg-primary/80"; + if (intensity === 0) return "bg-muted/20"; + if (intensity < 0.1) return "bg-primary/15"; + if (intensity < 0.2) return "bg-primary/25"; + if (intensity < 0.35) return "bg-primary/40"; + if (intensity < 0.5) return "bg-primary/55"; + if (intensity < 0.7) return "bg-primary/70"; + return "bg-primary/85"; } return ( @@ -54,14 +58,14 @@ export function Heatmap({ cells, loading }: HeatmapProps) { Heatmap Aktivitas - Hari × jam — area biru langit = lebih ramai. + Hari × jam — arahkan kursor ke sel untuk detail. - +
-
+
{/* Header row */} -
+
{Array.from({ length: 24 }, (_, h) => (
{/* Rows */} - {DAYS.map((day, d) => ( + {DAYS.map((dayLabel, d) => (
- {day} + {dayLabel}
{Array.from({ length: 24 }, (_, h) => { const intensity = getIntensity(d, h); const cell = cellMap.get(`${d}-${h}`); + const count = cell?.count ?? 0; return (
0 + ? "cursor-pointer hover:ring-2 hover:ring-primary/50 hover:scale-110" + : "", )} - title={`${day} ${h}:00 — ${cell?.count ?? 0} pesan`} + onMouseEnter={() => { + if (count > 0) { + setTooltip({ + day: dayLabel, + hour: `${h}:00`, + total: count, + clean: cell?.clean ?? 0, + warned: cell?.warned ?? 0, + flagged: cell?.flagged ?? 0, + }); + } + }} + onMouseLeave={() => setTooltip(null)} /> ); })} @@ -95,13 +115,51 @@ export function Heatmap({ cells, loading }: HeatmapProps) { ))}
+ + {/* Tooltip */} + {tooltip && ( +
+
+ {tooltip.day} {tooltip.hour} +
+
+
+ Total + + {tooltip.total} + +
+
+ Clean + {tooltip.clean} +
+
+ Warned + {tooltip.warned} +
+
+ Flagged + {tooltip.flagged} +
+
+
+ )} + {/* Legend */}
Sepi - - - - + + + + + Ramai
@@ -113,7 +171,7 @@ function LoadingBox() { return ( - + Memuat data...