2025-04-17 02:31:34 -05:00
import React , {
createContext ,
useState ,
useContext ,
useMemo ,
useCallback ,
ReactNode ,
useEffect ,
} from 'react' ;
2025-04-15 22:14:43 -05:00
import { logger } from 'matrix-js-sdk/lib/logger' ;
2025-04-29 15:28:13 -05:00
import { WidgetApiToWidgetAction , WidgetApiAction , ClientWidgetApi } from 'matrix-widget-api' ;
2025-05-01 16:24:36 -05:00
import { useParams } from 'react-router-dom' ;
2025-05-24 19:31:43 -05:00
import { SmallWidget } from '../../../features/call/SmallWidget' ;
2025-04-17 02:31:34 -05:00
interface MediaStatePayload {
2025-04-29 15:28:13 -05:00
data ? : {
audio_enabled? : boolean ;
video_enabled? : boolean ;
} ;
2025-04-17 02:31:34 -05:00
}
const WIDGET_MEDIA_STATE_UPDATE_ACTION = 'io.element.device_mute' ;
2025-04-29 15:28:13 -05:00
const WIDGET_HANGUP_ACTION = 'im.vector.hangup' ;
2025-05-01 16:24:36 -05:00
const WIDGET_ON_SCREEN_ACTION = 'set_always_on_screen' ;
const WIDGET_JOIN_ACTION = 'io.element.join' ;
2025-05-25 16:29:55 -05:00
const WIDGET_TILE_UPDATE = 'io.element.tile_layout' ;
2025-04-15 22:14:43 -05:00
interface CallContextState {
activeCallRoomId : string | null ;
setActiveCallRoomId : ( roomId : string | null ) = > void ;
2025-05-10 20:41:57 -05:00
viewedCallRoomId : string | null ;
setViewedCallRoomId : ( roomId : string | null ) = > void ;
2025-05-25 16:34:55 -05:00
hangUp : ( room : string ) = > void ;
2025-04-29 15:28:13 -05:00
activeClientWidgetApi : ClientWidgetApi | null ;
2025-05-24 19:31:43 -05:00
activeClientWidget : SmallWidget | null ;
2025-04-29 15:28:13 -05:00
registerActiveClientWidgetApi : (
roomId : string | null ,
2025-05-24 19:31:43 -05:00
clientWidgetApi : ClientWidgetApi | null ,
clientWidget : SmallWidget
2025-04-29 15:28:13 -05:00
) = > void ;
2025-05-24 19:31:43 -05:00
viewedClientWidgetApi : ClientWidgetApi | null ;
viewedClientWidget : SmallWidget | null ;
2025-05-10 20:41:57 -05:00
registerViewedClientWidgetApi : (
roomId : string | null ,
2025-05-24 19:31:43 -05:00
clientWidgetApi : ClientWidgetApi | null ,
clientWidget : SmallWidget
2025-05-10 20:41:57 -05:00
) = > void ;
2025-04-15 22:14:43 -05:00
sendWidgetAction : < T = unknown > (
2025-04-16 19:49:11 -05:00
action : WidgetApiToWidgetAction | string ,
2025-04-15 22:14:43 -05:00
data : T
2025-04-16 19:49:11 -05:00
) = > Promise < void > ;
2025-04-17 02:31:34 -05:00
isAudioEnabled : boolean ;
isVideoEnabled : boolean ;
2025-04-18 03:01:44 -05:00
isChatOpen : boolean ;
2025-05-01 16:24:36 -05:00
isCallActive : boolean ;
2025-05-03 00:06:36 -05:00
isPrimaryIframe : boolean ;
2025-04-17 02:31:34 -05:00
toggleAudio : ( ) = > Promise < void > ;
toggleVideo : ( ) = > Promise < void > ;
2025-04-18 03:01:44 -05:00
toggleChat : ( ) = > Promise < void > ;
2025-05-03 00:06:36 -05:00
toggleIframe : ( ) = > Promise < void > ;
2025-04-15 22:14:43 -05:00
}
const CallContext = createContext < CallContextState | undefined > ( undefined ) ;
interface CallProviderProps {
children : ReactNode ;
}
2025-04-22 22:34:25 -04:00
const DEFAULT_AUDIO_ENABLED = true ;
2025-04-17 02:31:34 -05:00
const DEFAULT_VIDEO_ENABLED = false ;
2025-04-18 03:01:44 -05:00
const DEFAULT_CHAT_OPENED = false ;
2025-05-01 16:24:36 -05:00
const DEFAULT_CALL_ACTIVE = false ;
2025-05-10 20:41:57 -05:00
const DEFAULT_PRIMARY_IFRAME = true ;
2025-04-17 02:31:34 -05:00
2025-04-15 22:14:43 -05:00
export function CallProvider ( { children } : CallProviderProps ) {
const [ activeCallRoomId , setActiveCallRoomIdState ] = useState < string | null > ( null ) ;
2025-05-10 20:41:57 -05:00
const [ viewedCallRoomId , setViewedCallRoomIdState ] = useState < string | null > ( null ) ;
2025-04-29 15:28:13 -05:00
const [ activeClientWidgetApi , setActiveClientWidgetApiState ] = useState < ClientWidgetApi | null > (
null
) ;
2025-05-24 19:31:43 -05:00
const [ activeClientWidget , setActiveClientWidget ] = useState < SmallWidget | null > ( null ) ;
2025-05-10 20:41:57 -05:00
const [ activeClientWidgetApiRoomId , setActiveClientWidgetApiRoomId ] = useState < string | null > (
null
) ;
const [ viewedClientWidgetApi , setViewedClientWidgetApiState ] = useState < ClientWidgetApi | null > (
null
) ;
2025-05-24 19:31:43 -05:00
const [ viewedClientWidget , setViewedClientWidget ] = useState < SmallWidget | null > ( null ) ;
2025-05-10 20:41:57 -05:00
const [ viewedClientWidgetApiRoomId , setViewedClientWidgetApiRoomId ] = useState < string | null > (
null
) ;
2025-04-15 22:14:43 -05:00
2025-04-17 02:31:34 -05:00
const [ isAudioEnabled , setIsAudioEnabledState ] = useState < boolean > ( DEFAULT_AUDIO_ENABLED ) ;
const [ isVideoEnabled , setIsVideoEnabledState ] = useState < boolean > ( DEFAULT_VIDEO_ENABLED ) ;
2025-04-18 03:01:44 -05:00
const [ isChatOpen , setIsChatOpenState ] = useState < boolean > ( DEFAULT_CHAT_OPENED ) ;
2025-05-01 16:24:36 -05:00
const [ isCallActive , setIsCallActive ] = useState < boolean > ( DEFAULT_CALL_ACTIVE ) ;
2025-05-03 00:06:36 -05:00
const [ isPrimaryIframe , setIsPrimaryIframe ] = useState < boolean > ( DEFAULT_PRIMARY_IFRAME ) ;
2025-05-01 16:24:36 -05:00
const { roomIdOrAlias : viewedRoomId } = useParams < { roomIdOrAlias : string } > ( ) ;
2025-04-17 02:31:34 -05:00
const resetMediaState = useCallback ( ( ) = > {
logger . debug ( 'CallContext: Resetting media state to defaults.' ) ;
setIsAudioEnabledState ( DEFAULT_AUDIO_ENABLED ) ;
setIsVideoEnabledState ( DEFAULT_VIDEO_ENABLED ) ;
} , [ ] ) ;
2025-04-15 22:14:43 -05:00
const setActiveCallRoomId = useCallback (
( roomId : string | null ) = > {
2025-04-17 02:31:34 -05:00
logger . warn ( ` CallContext: Setting activeCallRoomId to ${ roomId } ` ) ;
const previousRoomId = activeCallRoomId ;
2025-04-15 22:14:43 -05:00
setActiveCallRoomIdState ( roomId ) ;
2025-04-17 02:31:34 -05:00
if ( roomId !== previousRoomId ) {
logger . debug ( ` CallContext: Active call room changed, resetting media state. ` ) ;
resetMediaState ( ) ;
}
2025-05-10 20:41:57 -05:00
if ( roomId === null || roomId !== activeClientWidgetApiRoomId ) {
2025-04-17 02:31:34 -05:00
logger . warn (
2025-04-29 15:28:13 -05:00
` CallContext: Clearing active clientWidgetApi because active room changed to ${ roomId } or was cleared. `
2025-04-15 22:14:43 -05:00
) ;
}
} ,
2025-05-10 20:41:57 -05:00
[ activeClientWidgetApiRoomId , resetMediaState , activeCallRoomId ]
) ;
const setViewedCallRoomId = useCallback (
( roomId : string | null ) = > {
logger . warn ( ` CallContext: Setting activeCallRoomId to ${ roomId } ` ) ;
setViewedCallRoomIdState ( roomId ) ;
} ,
[ setViewedCallRoomIdState ]
2025-04-16 19:49:11 -05:00
) ;
2025-04-15 22:14:43 -05:00
2025-04-29 15:28:13 -05:00
const setActiveClientWidgetApi = useCallback (
2025-05-24 19:31:43 -05:00
(
clientWidgetApi : ClientWidgetApi | null ,
clientWidget : SmallWidget | null ,
roomId : string | null
) = > {
2025-04-29 15:28:13 -05:00
setActiveClientWidgetApiState ( clientWidgetApi ) ;
2025-05-24 19:31:43 -05:00
setActiveClientWidget ( clientWidget ) ;
2025-05-10 20:41:57 -05:00
setActiveClientWidgetApiRoomId ( roomId ) ;
2025-04-29 15:28:13 -05:00
} ,
[ ]
) ;
2025-04-15 22:14:43 -05:00
2025-04-29 15:28:13 -05:00
const registerActiveClientWidgetApi = useCallback (
2025-05-24 19:31:43 -05:00
(
roomId : string | null ,
clientWidgetApi : ClientWidgetApi | null ,
clientWidget : SmallWidget | null
) = > {
2025-04-29 15:28:13 -05:00
if ( activeClientWidgetApi && activeClientWidgetApi !== clientWidgetApi ) {
logger . debug ( ` CallContext: Cleaning up listeners for previous clientWidgetApi instance. ` ) ;
2025-05-24 19:31:43 -05:00
//activeClientWidgetApi.removeAllListeners();
2025-04-17 02:31:34 -05:00
}
2025-04-29 15:28:13 -05:00
if ( roomId && clientWidgetApi ) {
logger . debug ( ` CallContext: Registering active clientWidgetApi for room ${ roomId } . ` ) ;
2025-05-24 19:31:43 -05:00
setActiveClientWidgetApi ( clientWidgetApi , clientWidget , roomId ) ;
2025-05-10 20:41:57 -05:00
} else if ( roomId === activeClientWidgetApiRoomId || roomId === null ) {
2025-05-24 19:31:43 -05:00
setActiveClientWidgetApi ( null , null , null ) ;
2025-04-17 02:31:34 -05:00
resetMediaState ( ) ;
2025-05-10 20:41:57 -05:00
}
} ,
[ activeClientWidgetApi , activeClientWidgetApiRoomId , setActiveClientWidgetApi , resetMediaState ]
) ;
const setViewedClientWidgetApi = useCallback (
2025-05-24 19:31:43 -05:00
(
clientWidgetApi : ClientWidgetApi | null ,
clientWidget : SmallWidget | null ,
roomId : string | null
) = > {
2025-05-10 20:41:57 -05:00
setViewedClientWidgetApiState ( clientWidgetApi ) ;
2025-05-24 19:31:43 -05:00
setViewedClientWidget ( clientWidget ) ;
2025-05-11 19:01:47 -05:00
setViewedClientWidgetApiRoomId ( roomId ) ;
2025-05-10 20:41:57 -05:00
} ,
[ ]
) ;
const registerViewedClientWidgetApi = useCallback (
2025-05-24 19:31:43 -05:00
(
roomId : string | null ,
clientWidgetApi : ClientWidgetApi | null ,
clientWidget : SmallWidget | null
) = > {
2025-05-10 20:41:57 -05:00
if ( viewedClientWidgetApi && viewedClientWidgetApi !== clientWidgetApi ) {
2025-05-22 17:41:16 -05:00
logger . debug ( ` CallContext: Cleaning up listeners for previous clientWidgetApi instance. ` ) ;
2025-05-10 20:41:57 -05:00
}
if ( roomId && clientWidgetApi ) {
2025-05-22 17:41:16 -05:00
logger . debug ( ` CallContext: Registering viewed clientWidgetApi for room ${ roomId } . ` ) ;
2025-05-24 19:31:43 -05:00
setViewedClientWidgetApi ( clientWidgetApi , clientWidget , roomId ) ;
2025-05-10 20:41:57 -05:00
} else if ( roomId === viewedClientWidgetApiRoomId || roomId === null ) {
2025-05-22 17:41:16 -05:00
logger . debug (
2025-05-11 17:55:04 -05:00
` CallContext: Clearing viewed clientWidgetApi for room ${ viewedClientWidgetApiRoomId } . `
2025-05-10 20:41:57 -05:00
) ;
2025-05-24 19:31:43 -05:00
setViewedClientWidgetApi ( null , null , null ) ;
2025-04-15 22:14:43 -05:00
}
} ,
2025-05-10 20:41:57 -05:00
[ viewedClientWidgetApi , viewedClientWidgetApiRoomId , setViewedClientWidgetApi ]
2025-04-15 22:14:43 -05:00
) ;
2025-05-25 16:29:55 -05:00
const hangUp = useCallback (
2025-05-25 16:34:55 -05:00
( nextRoom : string ) = > {
2025-05-25 16:29:55 -05:00
setIsCallActive ( false ) ;
if ( typeof nextRoom !== 'string' ) {
2025-05-25 21:29:53 -05:00
if ( activeCallRoomId && viewedCallRoomId === activeCallRoomId ) {
2025-05-25 16:29:55 -05:00
setIsPrimaryIframe ( ! isPrimaryIframe ) ;
2025-05-25 23:16:37 -05:00
} else {
if ( viewedCallRoomId !== viewedRoomId ) setViewedCallRoomId ( activeCallRoomId ) ;
2025-05-25 16:29:55 -05:00
}
2025-05-25 21:29:53 -05:00
logger . error ( ` ${ activeCallRoomId } ${ viewedCallRoomId } ` ) ;
2025-05-25 16:29:55 -05:00
} else if ( viewedCallRoomId !== null ) {
setIsPrimaryIframe ( ! isPrimaryIframe ) ;
2025-05-25 21:29:53 -05:00
} else if ( activeCallRoomId ) setViewedCallRoomId ( nextRoom ) ;
2025-05-25 16:29:55 -05:00
setActiveClientWidgetApi ( null , null , null ) ;
setActiveCallRoomId ( null ) ;
2025-05-24 19:31:43 -05:00
2025-05-25 16:29:55 -05:00
logger . debug ( ` CallContext: Hang up called. ` ) ;
activeClientWidgetApi ? . transport . send ( ` ${ WIDGET_HANGUP_ACTION } ` , { } ) ;
} ,
[
activeCallRoomId ,
activeClientWidgetApi ? . transport ,
isPrimaryIframe ,
setActiveCallRoomId ,
setActiveClientWidgetApi ,
setViewedCallRoomId ,
viewedCallRoomId ,
2025-05-25 23:16:37 -05:00
viewedRoomId ,
2025-05-25 16:29:55 -05:00
]
) ;
2025-05-23 16:34:44 -05:00
2025-04-17 02:31:34 -05:00
useEffect ( ( ) = > {
2025-05-21 21:14:31 -05:00
if ( ! activeCallRoomId && ! viewedCallRoomId ) {
2025-04-17 02:31:34 -05:00
return ;
}
const handleHangup = ( ev : CustomEvent ) = > {
2025-04-29 15:28:13 -05:00
ev . preventDefault ( ) ;
2025-05-21 21:14:31 -05:00
if ( ev . detail . widgetId === activeClientWidgetApi ? . widget . id ) {
activeClientWidgetApi ? . transport . reply ( ev . detail , { } ) ;
2025-05-25 16:29:55 -05:00
/*
if (viewedRoomId === activeCallRoomId) {
if (viewedCallRoomId !== activeCallRoomId) {
setViewedCallRoomId(activeCallRoomId);
setIsPrimaryIframe(!isPrimaryIframe);
} else {
setIsPrimaryIframe(!isPrimaryIframe);
}
setViewedClientWidgetApi(viewedClientWidgetApi, viewedClientWidget, viewedCallRoomId);
}
*/
// setActiveClientWidgetApi(null, null, null);
// setActiveCallRoomId(null);
// setIsCallActive(false);
2025-05-21 21:14:31 -05:00
}
2025-05-24 19:31:43 -05:00
logger . debug (
2025-04-17 02:31:34 -05:00
` CallContext: Received hangup action from widget in room ${ activeCallRoomId } . ` ,
ev
) ;
} ;
const handleMediaStateUpdate = ( ev : CustomEvent < MediaStatePayload > ) = > {
ev . preventDefault ( ) ;
logger . debug (
` CallContext: Received media state update from widget in room ${ activeCallRoomId } : ` ,
ev . detail
) ;
2025-05-22 17:41:16 -05:00
/* eslint-disable camelcase */
const { audio_enabled , video_enabled } = ev . detail . data ? ? { } ;
2025-04-22 00:27:31 -04:00
if ( typeof audio_enabled === 'boolean' && audio_enabled !== isAudioEnabled ) {
logger . debug ( ` CallContext: Updating audio enabled state from widget: ${ audio_enabled } ` ) ;
setIsAudioEnabledState ( audio_enabled ) ;
2025-04-17 02:31:34 -05:00
}
2025-04-22 00:27:31 -04:00
if ( typeof video_enabled === 'boolean' && video_enabled !== isVideoEnabled ) {
logger . debug ( ` CallContext: Updating video enabled state from widget: ${ video_enabled } ` ) ;
setIsVideoEnabledState ( video_enabled ) ;
2025-04-17 02:31:34 -05:00
}
2025-05-22 17:41:16 -05:00
/* eslint-enable camelcase */
2025-04-17 02:31:34 -05:00
} ;
2025-05-01 16:24:36 -05:00
const handleOnScreenStateUpdate = ( ev : CustomEvent ) = > {
ev . preventDefault ( ) ;
2025-05-10 20:41:57 -05:00
if ( isPrimaryIframe ) {
activeClientWidgetApi ? . transport . reply ( ev . detail , { } ) ;
} else {
viewedClientWidgetApi ? . transport . reply ( ev . detail , { } ) ;
}
2025-05-01 16:24:36 -05:00
} ;
2025-05-25 16:29:55 -05:00
const handleOnTileLayout = ( ev : CustomEvent ) = > {
ev . preventDefault ( ) ;
if ( isPrimaryIframe ) {
activeClientWidgetApi ? . transport . reply ( ev . detail , { } ) ;
} else {
viewedClientWidgetApi ? . transport . reply ( ev . detail , { } ) ;
}
} ;
2025-05-01 16:24:36 -05:00
const handleJoin = ( ev : CustomEvent ) = > {
ev . preventDefault ( ) ;
2025-05-23 13:57:01 -05:00
const setViewedAsActive = ( ) = > {
2025-05-24 19:31:43 -05:00
setActiveClientWidgetApi ( viewedClientWidgetApi , viewedClientWidget , viewedCallRoomId ) ;
2025-05-23 13:57:01 -05:00
setActiveCallRoomIdState ( viewedCallRoomId ) ;
setIsPrimaryIframe ( ! isPrimaryIframe ) ;
setIsCallActive ( true ) ;
} ;
2025-05-11 17:55:04 -05:00
activeClientWidgetApi ? . transport . reply ( ev . detail , { } ) ;
2025-05-25 23:16:37 -05:00
if ( ev . detail . widgetId === activeClientWidgetApi ? . widget . id ) {
setIsCallActive ( true ) ;
return ;
}
2025-05-23 13:21:40 -05:00
if ( activeClientWidgetApi ) {
2025-05-25 16:29:55 -05:00
if ( isCallActive && viewedClientWidgetApi && viewedCallRoomId ) {
2025-05-23 13:21:40 -05:00
activeClientWidgetApi ? . removeAllListeners ( ) ;
activeClientWidgetApi ? . transport . send ( WIDGET_HANGUP_ACTION , { } ) . then ( ( ) = > {
2025-05-23 13:57:01 -05:00
setViewedAsActive ( ) ;
2025-05-25 21:29:53 -05:00
setViewedCallRoomIdState ( null ) ;
setViewedClientWidgetApi ( null , null , null ) ;
2025-05-23 13:21:40 -05:00
} ) ;
} else {
2025-05-21 21:14:31 -05:00
setIsCallActive ( true ) ;
2025-05-23 13:21:40 -05:00
}
2025-05-25 22:01:57 -05:00
} else if ( viewedCallRoomId !== viewedRoomId ) {
setIsCallActive ( true ) ;
2025-05-11 19:24:13 -05:00
} else {
2025-05-23 13:57:01 -05:00
setViewedAsActive ( ) ;
2025-05-03 00:06:36 -05:00
}
2025-05-01 16:24:36 -05:00
} ;
2025-04-29 15:28:13 -05:00
logger . debug (
` CallContext: Setting up listeners for clientWidgetApi in room ${ activeCallRoomId } `
) ;
2025-05-10 20:41:57 -05:00
activeClientWidgetApi ? . on ( ` action: ${ WIDGET_HANGUP_ACTION } ` , handleHangup ) ;
activeClientWidgetApi ? . on ( ` action: ${ WIDGET_MEDIA_STATE_UPDATE_ACTION } ` , handleMediaStateUpdate ) ;
2025-05-25 16:29:55 -05:00
viewedClientWidgetApi ? . on ( ` action: ${ WIDGET_TILE_UPDATE } ` , handleOnTileLayout ) ;
2025-05-10 20:41:57 -05:00
activeClientWidgetApi ? . on ( ` action: ${ WIDGET_ON_SCREEN_ACTION } ` , handleOnScreenStateUpdate ) ;
activeClientWidgetApi ? . on ( ` action: ${ WIDGET_JOIN_ACTION } ` , handleJoin ) ;
viewedClientWidgetApi ? . on ( ` action: ${ WIDGET_JOIN_ACTION } ` , handleJoin ) ;
viewedClientWidgetApi ? . on ( ` action: ${ WIDGET_MEDIA_STATE_UPDATE_ACTION } ` , handleMediaStateUpdate ) ;
2025-05-25 16:29:55 -05:00
viewedClientWidgetApi ? . on ( ` action: ${ WIDGET_TILE_UPDATE } ` , handleOnTileLayout ) ;
2025-05-10 20:41:57 -05:00
viewedClientWidgetApi ? . on ( ` action: ${ WIDGET_ON_SCREEN_ACTION } ` , handleOnScreenStateUpdate ) ;
viewedClientWidgetApi ? . on ( ` action: ${ WIDGET_HANGUP_ACTION } ` , handleHangup ) ;
2025-05-25 23:16:37 -05:00
} , [
activeClientWidgetApi ,
activeCallRoomId ,
activeClientWidgetApiRoomId ,
hangUp ,
isChatOpen ,
isAudioEnabled ,
isVideoEnabled ,
isCallActive ,
viewedRoomId ,
viewedClientWidgetApi ,
isPrimaryIframe ,
viewedCallRoomId ,
setViewedClientWidgetApi ,
setActiveClientWidgetApi ,
viewedClientWidget ,
setViewedCallRoomId ,
] ) ;
2025-04-17 02:31:34 -05:00
2025-04-15 22:14:43 -05:00
const sendWidgetAction = useCallback (
2025-04-16 19:49:11 -05:00
async < T = unknown , > ( action : WidgetApiToWidgetAction | string , data : T ) : Promise < void > = > {
2025-04-29 15:28:13 -05:00
if ( ! activeClientWidgetApi ) {
2025-04-15 22:14:43 -05:00
logger . warn (
2025-04-29 15:28:13 -05:00
` CallContext: Cannot send action ' ${ action } ', no active API clientWidgetApi registered. `
2025-04-15 22:14:43 -05:00
) ;
2025-04-29 15:28:13 -05:00
return Promise . reject ( new Error ( 'No active call clientWidgetApi' ) ) ;
2025-04-15 22:14:43 -05:00
}
2025-05-10 20:41:57 -05:00
if ( ! activeClientWidgetApiRoomId || activeClientWidgetApiRoomId !== activeCallRoomId ) {
2025-04-29 15:28:13 -05:00
logger . debug (
2025-05-10 20:41:57 -05:00
` CallContext: Cannot send action ' ${ action } ', clientWidgetApi room ( ${ activeClientWidgetApiRoomId } ) does not match active call room ( ${ activeCallRoomId } ). Stale clientWidgetApi? `
2025-04-15 22:14:43 -05:00
) ;
2025-04-29 15:28:13 -05:00
return Promise . reject ( new Error ( 'Mismatched active call clientWidgetApi' ) ) ;
2025-04-15 22:14:43 -05:00
}
2025-05-22 23:14:24 -05:00
logger . debug (
` CallContext: Sending action ' ${ action } ' via active clientWidgetApi (room: ${ activeClientWidgetApiRoomId } ) with data: ` ,
data
) ;
await activeClientWidgetApi . transport . send ( action as WidgetApiAction , data ) ;
2025-04-15 22:14:43 -05:00
} ,
2025-05-10 20:41:57 -05:00
[ activeClientWidgetApi , activeCallRoomId , activeClientWidgetApiRoomId ]
2025-04-15 22:14:43 -05:00
) ;
2025-04-17 02:31:34 -05:00
const toggleAudio = useCallback ( async ( ) = > {
const newState = ! isAudioEnabled ;
logger . debug ( ` CallContext: Toggling audio. New state: enabled= ${ newState } ` ) ;
setIsAudioEnabledState ( newState ) ;
try {
2025-05-01 16:24:36 -05:00
await sendWidgetAction ( WIDGET_MEDIA_STATE_UPDATE_ACTION , {
2025-04-22 00:27:31 -04:00
audio_enabled : newState ,
video_enabled : isVideoEnabled ,
2025-04-17 02:31:34 -05:00
} ) ;
logger . debug ( ` CallContext: Successfully sent audio toggle action. ` ) ;
} catch ( error ) {
setIsAudioEnabledState ( ! newState ) ;
throw error ;
}
} , [ isAudioEnabled , isVideoEnabled , sendWidgetAction ] ) ;
const toggleVideo = useCallback ( async ( ) = > {
const newState = ! isVideoEnabled ;
logger . debug ( ` CallContext: Toggling video. New state: enabled= ${ newState } ` ) ;
setIsVideoEnabledState ( newState ) ;
try {
2025-05-01 16:24:36 -05:00
await sendWidgetAction ( WIDGET_MEDIA_STATE_UPDATE_ACTION , {
2025-04-22 00:27:31 -04:00
audio_enabled : isAudioEnabled ,
video_enabled : newState ,
2025-04-17 02:31:34 -05:00
} ) ;
logger . debug ( ` CallContext: Successfully sent video toggle action. ` ) ;
} catch ( error ) {
setIsVideoEnabledState ( ! newState ) ;
throw error ;
}
} , [ isVideoEnabled , isAudioEnabled , sendWidgetAction ] ) ;
2025-04-18 03:01:44 -05:00
const toggleChat = useCallback ( async ( ) = > {
const newState = ! isChatOpen ;
2025-04-22 22:29:07 -04:00
setIsChatOpenState ( newState ) ;
2025-04-18 03:01:44 -05:00
} , [ isChatOpen ] ) ;
2025-05-03 00:06:36 -05:00
const toggleIframe = useCallback ( async ( ) = > {
const newState = ! isPrimaryIframe ;
setIsPrimaryIframe ( newState ) ;
} , [ isPrimaryIframe ] ) ;
2025-04-15 22:14:43 -05:00
const contextValue = useMemo < CallContextState > (
( ) = > ( {
activeCallRoomId ,
setActiveCallRoomId ,
2025-05-10 20:41:57 -05:00
viewedCallRoomId ,
setViewedCallRoomId ,
2025-04-15 22:14:43 -05:00
hangUp ,
2025-04-29 15:28:13 -05:00
activeClientWidgetApi ,
registerActiveClientWidgetApi ,
2025-05-24 19:31:43 -05:00
activeClientWidget ,
viewedClientWidgetApi ,
2025-05-10 20:41:57 -05:00
registerViewedClientWidgetApi ,
2025-05-24 19:31:43 -05:00
viewedClientWidget ,
2025-04-15 22:14:43 -05:00
sendWidgetAction ,
2025-04-18 03:01:44 -05:00
isChatOpen ,
2025-04-17 02:31:34 -05:00
isAudioEnabled ,
isVideoEnabled ,
2025-05-02 02:35:51 -05:00
isCallActive ,
2025-05-03 00:06:36 -05:00
isPrimaryIframe ,
2025-04-17 02:31:34 -05:00
toggleAudio ,
toggleVideo ,
2025-04-18 03:01:44 -05:00
toggleChat ,
2025-05-03 00:06:36 -05:00
toggleIframe ,
2025-04-15 22:14:43 -05:00
} ) ,
[
activeCallRoomId ,
setActiveCallRoomId ,
2025-05-10 20:41:57 -05:00
viewedCallRoomId ,
setViewedCallRoomId ,
2025-04-15 22:14:43 -05:00
hangUp ,
2025-04-29 15:28:13 -05:00
activeClientWidgetApi ,
registerActiveClientWidgetApi ,
2025-05-24 19:31:43 -05:00
activeClientWidget ,
viewedClientWidgetApi ,
2025-05-10 20:41:57 -05:00
registerViewedClientWidgetApi ,
2025-05-24 19:31:43 -05:00
viewedClientWidget ,
2025-04-15 22:14:43 -05:00
sendWidgetAction ,
2025-04-22 00:27:31 -04:00
isChatOpen ,
2025-04-17 02:31:34 -05:00
isAudioEnabled ,
isVideoEnabled ,
2025-05-02 02:35:51 -05:00
isCallActive ,
2025-05-03 00:06:36 -05:00
isPrimaryIframe ,
2025-04-17 02:31:34 -05:00
toggleAudio ,
toggleVideo ,
2025-04-22 00:27:31 -04:00
toggleChat ,
2025-05-03 00:06:36 -05:00
toggleIframe ,
2025-04-15 22:14:43 -05:00
]
) ;
return < CallContext.Provider value = { contextValue } > { children } < / CallContext.Provider > ;
}
export function useCallState ( ) : CallContextState {
const context = useContext ( CallContext ) ;
if ( context === undefined ) {
throw new Error ( 'useCallState must be used within a CallProvider' ) ;
}
return context ;
}