"use client"; import { Headphones, Loader2, Radio, RadioOff } from "lucide-react"; import { useEffect, useState } from "react"; import { SignalField } from "@/components/three"; import { WebGLGuard } from "@/components/three/webgl-guard"; import { StaticFallback } from "@/components/three/static-fallback"; import { StaggerGroup, StaggerItem } from "@/components/motion/stagger"; import { Button } from "@/components/primitives/button"; import { Badge } from "@/components/primitives/badge"; import { Select } from "@/components/primitives/select"; import { SpeakerWaveform } from "@/components/voice/speaker-waveform"; import { SessionRibbon } from "@/components/charts/session-ribbon"; import { ActiveSpeakersPanel } from "@/components/voice/active-speakers-panel"; import { MicControl } from "@/components/voice/mic-control"; import { ListenControl } from "@/components/voice/listen-control"; import { useGuilds, useSpeakers, useVoiceChannels, useVoiceConnect, useVoiceDisconnect, useVoiceListen, useVoiceStatus, } from "@/hooks"; import type { VoiceStatus } from "@/lib/types"; import { useWebSocket } from "@/lib/ws/context"; export default function VoiceView({ initialStatus }: { initialStatus?: VoiceStatus }) { const ws = useWebSocket(); const [selectedGuild, setSelectedGuild] = useState(""); const [selectedChannel, setSelectedChannel] = useState(""); // Live connection status — SWR revalidates on connect/disconnect (the // useVoiceConnect/Disconnect actions invalidate the "voice-status" key), // so this reflects real-time state instead of the static SSR snapshot. const { data: status } = useVoiceStatus(initialStatus); const { speakers, subscribe } = useSpeakers(status?.activeSpeakers ?? []); const { data: guilds = [] } = useGuilds(); const { data: voiceChannels = [] } = useVoiceChannels(selectedGuild); const connect = useVoiceConnect(); const disconnect = useVoiceDisconnect(); const listen = useVoiceListen(ws); useEffect(() => { const unsub = subscribe(ws); return unsub; }, [subscribe, ws]); const active = speakers.filter((s) => s.speaking); const connected = status?.connected ?? false; const handleGuildChange = (e: React.ChangeEvent) => { const g = e.target.value; setSelectedGuild(g); setSelectedChannel(""); }; return (
{/* Connection bar with guild + voice channel pickers */}
{connected ? "Connected" : "Disconnected"} {connected && status?.activeChannelName && ( {status.activeChannelName} )}
{!connected ? (
) : ( )}
{/* Stage hero */}
} > 0 ? 0.6 : 0.2} className="absolute inset-0" />
listen.toggle(on)} levels={listen.levels} /> listen.toggle(on)} volume={75} onVolume={listen.setVolume} /> {/* Activity timeline */}

Live session timeline

({ id: s.userId, label: s.username, value: s.speaking ? 3 : 1, tone: s.speaking ? "signal" : "neutral", }))} />
); }