"use client"; import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts"; import { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from "@/components/ui/chart"; export interface TimelineRow { bucket: number; sessionDeviceId: number; slotLabel: string; avgValue: number; maxValue: number; } const SERIES_COLORS = ["var(--chart-1)", "var(--chart-2)", "var(--chart-3)", "var(--chart-4)", "var(--chart-5)"]; // Chart config keys become raw CSS custom-property names (--color-), so // they must be safe identifiers - a user-chosen device display name isn't. // Use the numeric session_device_id as the key, slotLabel only as display text. function seriesKey(sessionDeviceId: number): string { return `device_${sessionDeviceId}`; } export function SessionTimelineChart({ timeline }: { timeline: TimelineRow[] }) { const series = [...new Map(timeline.map((r) => [r.sessionDeviceId, r.slotLabel])).entries()]; const buckets = [...new Set(timeline.map((r) => r.bucket))].sort((a, b) => a - b); const data = buckets.map((bucket) => { const row: Record = { bucket }; for (const [sessionDeviceId] of series) { const match = timeline.find((r) => r.bucket === bucket && r.sessionDeviceId === sessionDeviceId); row[seriesKey(sessionDeviceId)] = match ? Math.round(match.avgValue * 100) : 0; } return row; }); const config: ChartConfig = Object.fromEntries( series.map(([sessionDeviceId, slotLabel], i) => [ seriesKey(sessionDeviceId), { label: slotLabel, color: SERIES_COLORS[i % SERIES_COLORS.length] }, ]), ); if (timeline.length === 0) { return

No device activity recorded for this session.

; } return ( {series.map(([sessionDeviceId]) => ( ))} `${Math.round(v / 1000)}s`} tickLine={false} axisLine={false} className="bp-readout text-xs" /> } /> {series.map(([sessionDeviceId]) => ( ))} ); }