@@ -57,6 +57,7 @@ interface ChatSidebarProps {
5757 isPFATC ?: boolean ;
5858 unreadSessionCount ?: number ;
5959 unreadGlobalCount ?: number ;
60+ onVoiceStateChange ?: ( _inVoice : boolean ) => void ;
6061}
6162
6263export default function ChatSidebar ( {
@@ -71,6 +72,7 @@ export default function ChatSidebar({
7172 isPFATC = false ,
7273 unreadSessionCount = 0 ,
7374 unreadGlobalCount = 0 ,
75+ onVoiceStateChange,
7476} : ChatSidebarProps ) {
7577 const { user } = useAuth ( ) ;
7678 const { airports } = useData ( ) ;
@@ -141,6 +143,7 @@ export default function ChatSidebar({
141143 const [ talkingUsers , setTalkingUsers ] = useState < Set < string > > ( new Set ( ) ) ;
142144 const [ audioLevels , setAudioLevels ] = useState < Map < string , number > > ( new Map ( ) ) ;
143145 const [ isInVoice , setIsInVoice ] = useState ( false ) ;
146+ const [ voiceDevices , setVoiceDevices ] = useState < MediaDeviceInfo [ ] > ( [ ] ) ;
144147
145148 const voiceSocketRef = useRef < ReturnType <
146149 typeof createVoiceChatSocket
@@ -169,6 +172,10 @@ export default function ChatSidebar({
169172 const userVolumesRef = useRef ( userVolumes ) ;
170173 useEffect ( ( ) => { userVolumesRef . current = userVolumes ; } , [ userVolumes ] ) ;
171174
175+ useEffect ( ( ) => {
176+ onVoiceStateChange ?.( isInVoice ) ;
177+ } , [ isInVoice , onVoiceStateChange ] ) ;
178+
172179 const getConnectionIcon = ( ) => {
173180 if ( connectionState . connecting )
174181 return < Wifi className = "w-4 h-4 animate-pulse text-yellow-400" /> ;
@@ -737,7 +744,7 @@ export default function ChatSidebar({
737744 } , [ activeTab , open ] ) ;
738745
739746 useEffect ( ( ) => {
740- if ( ! sessionId || ! accessId || ! user || ! open ) return ;
747+ if ( ! sessionId || ! accessId || ! user ) return ;
741748
742749 voiceSocketRef . current = createVoiceChatSocket (
743750 sessionId ,
@@ -774,12 +781,14 @@ export default function ChatSidebar({
774781 } ) ;
775782 } ,
776783 ( ) => userVolumesRef . current ,
777- // onDevicesRefreshed — no-op here; VoiceChat manages its own device list
778- undefined
784+ ( devices : MediaDeviceInfo [ ] ) => setVoiceDevices ( devices ) ,
779785 ) ;
780786
781787 if ( voiceSocketRef . current ) {
782788 voiceSocketRef . current . socket . emit ( 'get-voice-users' ) ;
789+ voiceSocketRef . current . socket . on ( 'user-left-voice' , ( { userId : leftId } : { userId : string } ) => {
790+ setVoiceUsers ( ( prev ) => prev . filter ( ( u ) => u . userId !== leftId ) ) ;
791+ } ) ;
783792 }
784793
785794 return ( ) => {
@@ -788,12 +797,19 @@ export default function ChatSidebar({
788797 voiceSocketRef . current = null ;
789798 }
790799 setVoiceUsers ( [ ] ) ;
800+ setVoiceDevices ( [ ] ) ;
791801 setTalkingUsers ( new Set ( ) ) ;
792802 setConnectionState ( { connected : false , connecting : false , error : null } ) ;
793803 setIsInVoice ( false ) ;
794804 } ;
795805 // eslint-disable-next-line react-hooks/exhaustive-deps
796- } , [ sessionId , accessId , user , open ] ) ;
806+ } , [ sessionId , accessId , user ] ) ;
807+
808+ useEffect ( ( ) => {
809+ if ( open && voiceSocketRef . current ) {
810+ voiceSocketRef . current . socket . emit ( 'get-voice-users' ) ;
811+ }
812+ } , [ open ] ) ;
797813
798814 useEffect ( ( ) => {
799815 try {
@@ -1073,6 +1089,7 @@ export default function ChatSidebar({
10731089 setUserVolumes = { setUserVolumes }
10741090 talkingUsers = { talkingUsers }
10751091 audioLevels = { audioLevels }
1092+ externalDevices = { voiceDevices }
10761093 />
10771094 < div className = "shrink-0 relative mx-5 mb-5 mt-0 rounded-bl-3xl pt-8" >
10781095 < div
0 commit comments