diff --git a/services/frontend/src/app/(dashboard)/voice/page.tsx b/services/frontend/src/app/(dashboard)/voice/page.tsx index 152cacf..b7f950c 100644 --- a/services/frontend/src/app/(dashboard)/voice/page.tsx +++ b/services/frontend/src/app/(dashboard)/voice/page.tsx @@ -148,7 +148,7 @@ export default function VoicePage() { )} - {tab === "activity" && } + {tab === "activity" && } ); } diff --git a/services/frontend/src/components/voice/activity-timeline.tsx b/services/frontend/src/components/voice/activity-timeline.tsx index 7ff2691..930dab7 100644 --- a/services/frontend/src/components/voice/activity-timeline.tsx +++ b/services/frontend/src/components/voice/activity-timeline.tsx @@ -1,22 +1,30 @@ "use client"; -import { - Bar, - BarChart, - ResponsiveContainer, - Tooltip, - XAxis, - YAxis, -} from "recharts"; +import { Mic, MicOff } from "lucide-react"; import { GlassCard } from "@/components/glass/card"; -import { useMounted } from "@/lib/hooks/use-mounted"; +import type { ActiveSpeaker } from "@/lib/types"; interface ActivityTimelineProps { - data?: { user: string; duration: number }[]; + data?: ActiveSpeaker[]; } +/** + * Voice Activity — live view of everyone currently in the monitored voice + * channel and whether they are speaking right now. + * + * Previously this rendered a Recharts bar chart fed from a `{user, duration}` + * prop that NO caller ever supplied, so the Activity tab always showed an + * empty, misleading chart. It now renders real live speaker state from the + * WebSocket (same source as the Connection tab's waveform). + */ export function VoiceActivityTimeline({ data = [] }: ActivityTimelineProps) { - const mounted = useMounted(); + const sorted = [...data].sort((a, b) => + a.speaking === b.speaking + ? String(a.username).localeCompare(b.username) + : a.speaking + ? -1 + : 1, + ); return ( @@ -24,54 +32,53 @@ export function VoiceActivityTimeline({ data = [] }: ActivityTimelineProps) { Voice Activity + + {sorted.length} speaker{sorted.length !== 1 ? "s" : ""} · live + - - {mounted ? ( - - - - - [ - `${(Number(value) / 60).toFixed(1)}m`, - "Duration", - ]} - /> - - - - ) : ( - - )} - + + {sorted.length === 0 ? ( + + + + No speakers in the monitored voice channel. + + + Connect to a voice channel to see live activity here. + + + ) : ( + + {sorted.map((s) => ( + + {s.speaking ? ( + + ) : ( + + )} + + {s.username} + + + {s.speaking ? "Speaking" : "Listening"} + + + ))} + + )} ); }
+ No speakers in the monitored voice channel. +
+ Connect to a voice channel to see live activity here. +