import { useState, useEffect } from 'react'; import { apiClient } from 'app'; import { Button } from '@/components/ui/button'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Phone, PhoneOff, Mic, MicOff, Volume2, X, Users, ChevronRight } from 'lucide-react'; import { toast } from 'sonner'; interface Participant { user_id: string; display_name: string; is_muted: boolean; is_speaking: boolean; } interface Props { tableId: string; currentUserId: string; isHost: boolean; players: Array<{ user_id: string; display_name?: string | null }>; } export default function VoicePanel({ tableId, currentUserId, isHost, players }: Props) { const [isOpen, setIsOpen] = useState(false); const [inCall, setInCall] = useState(false); const [participants, setParticipants] = useState([]); const [myMuted, setMyMuted] = useState(false); // Poll for voice participants every 2 seconds when in call useEffect(() => { if (!inCall) return; const fetchParticipants = async () => { try { const res = await apiClient.get_voice_participants({ table_id: tableId }); const data = await res.json(); setParticipants(data.participants || []); } catch (error) { console.error('Failed to fetch voice participants:', error); } }; fetchParticipants(); const interval = setInterval(fetchParticipants, 2000); return () => clearInterval(interval); }, [tableId, inCall]); const toggleCall = () => { setInCall(!inCall); if (!inCall) { setIsOpen(true); toast.success('Joined voice call'); } else { toast.success('Left voice call'); } }; const toggleMyMute = async () => { try { await apiClient.mute_player({ table_id: tableId, user_id: currentUserId, muted: !myMuted }); setMyMuted(!myMuted); toast.success(myMuted ? 'Unmuted' : 'Muted'); } catch (error) { toast.error('Failed to toggle mute'); } }; const mutePlayer = async (userId: string, muted: boolean) => { if (!isHost) return; try { await apiClient.mute_player({ table_id: tableId, user_id: userId, muted }); toast.success(`Player ${muted ? 'muted' : 'unmuted'}`); } catch (error) { toast.error('Failed to mute player'); } }; const muteAll = async () => { if (!isHost) return; try { await apiClient.update_table_voice_settings({ table_id: tableId, mute_all: true }); toast.success('All players muted'); } catch (error) { toast.error('Failed to mute all'); } }; // Floating call button when panel is closed if (!isOpen) { return ( ); } return (
{/* Header */}

Voice Call

{inCall && ( Live )}
{/* Participants List */} {!inCall && (

Join the voice call to see participants

)} {inCall && participants.length === 0 && (

Waiting for others to join...

)} {inCall && participants.length > 0 && (
{participants.map((participant) => { const isMe = participant.user_id === currentUserId; return (
{/* Avatar with speaking indicator */}
{(participant.display_name || participant.user_id).slice(0, 2).toUpperCase()}
{participant.is_speaking && ( )}
{/* Name */}

{participant.display_name || participant.user_id.slice(0, 8)} {isMe && ' (You)'}

{participant.is_speaking && (

Speaking...

)}
{/* Mute controls */}
{participant.is_muted ? ( ) : ( )} {isHost && !isMe && ( )}
); })}
)}
{/* Footer Controls */}
{/* Host controls */} {isHost && inCall && ( )} {/* Main call controls */}
{inCall && ( )}
); }