import React, { createContext, ReactNode, useCallback, useEffect, useMemo, useRef } from 'react'; import { logger } from 'matrix-js-sdk/lib/logger'; import { ClientWidgetApi } from 'matrix-widget-api'; import { Box } from 'folds'; import { useParams } from 'react-router-dom'; import { useCallState } from './CallProvider'; import { createVirtualWidget, SmallWidget, getWidgetData, getWidgetUrl, } from '../../../features/call/SmallWidget'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { useClientConfig } from '../../../hooks/useClientConfig'; import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize'; interface PersistentCallContainerProps { children: ReactNode; } export const PrimaryRefContext = createContext(null); export const BackupRefContext = createContext(null); export function PersistentCallContainer({ children }: PersistentCallContainerProps) { const primaryIframeRef = useRef(null); const primaryWidgetApiRef = useRef(null); const primarySmallWidgetRef = useRef(null); const backupIframeRef = useRef(null); const backupWidgetApiRef = useRef(null); const backupSmallWidgetRef = useRef(null); const { activeCallRoomId, viewedCallRoomId, isChatOpen, isCallActive, isPrimaryIframe, registerActiveClientWidgetApi, registerViewedClientWidgetApi, } = useCallState(); const mx = useMatrixClient(); const clientConfig = useClientConfig(); const screenSize = useScreenSizeContext(); const isMobile = screenSize === ScreenSize.Mobile; const { roomIdOrAlias: viewedRoomId } = useParams(); const isViewingActiveCall = useMemo( () => activeCallRoomId !== null && activeCallRoomId === viewedRoomId, [activeCallRoomId, viewedRoomId] ); /* eslint-disable no-param-reassign */ const setupWidget = useCallback( ( widgetApiRef: { current: ClientWidgetApi }, smallWidgetRef: { current: SmallWidget }, iframeRef: { current: { src: string } }, skipLobby: { toString: () => any } ) => { if (mx?.getUserId()) { if ( (activeCallRoomId !== viewedCallRoomId && isCallActive) || (activeCallRoomId && !isCallActive) || (!activeCallRoomId && viewedCallRoomId && !isCallActive) ) { const roomIdToSet = (skipLobby ? activeCallRoomId : viewedCallRoomId) ?? ''; if ( roomIdToSet && (roomIdToSet === primarySmallWidgetRef?.current?.roomId || roomIdToSet === backupSmallWidgetRef?.current?.roomId) ) return; const widgetId = `element-call-${roomIdToSet}-${Date.now()}`; const newUrl = getWidgetUrl( mx, roomIdToSet, clientConfig.elementCallUrl ?? '', widgetId, { skipLobby: skipLobby.toString(), returnToLobby: 'true', perParticipantE2EE: 'true', } ); if ( newUrl.toString() === primarySmallWidgetRef?.current?.url || newUrl.toString() === backupSmallWidgetRef?.current?.url ) return; if (iframeRef.current && iframeRef.current.src !== newUrl.toString()) { iframeRef.current.src = newUrl.toString(); } else if (iframeRef.current && !iframeRef.current.src) { iframeRef.current.src = newUrl.toString(); } const iframeElement = iframeRef.current; if (!iframeElement) { return; } const userId = mx.getUserId() ?? ''; const app = createVirtualWidget( mx, widgetId, userId, 'Element Call', 'm.call', newUrl, true, getWidgetData(mx, roomIdToSet, {}, { skipLobby: true }), roomIdToSet ); const smallWidget = new SmallWidget(app); smallWidgetRef.current = smallWidget; const widgetApiInstance = smallWidget.startMessaging(iframeElement); widgetApiRef.current = widgetApiInstance; if (skipLobby) { registerActiveClientWidgetApi(activeCallRoomId, widgetApiRef.current); } else { registerViewedClientWidgetApi(viewedCallRoomId, widgetApiRef.current); } widgetApiInstance.once('ready', () => { logger.info(`PersistentCallContainer: Widget for ${roomIdToSet} is ready.`); }); } } }, [ activeCallRoomId, mx, viewedCallRoomId, isCallActive, clientConfig.elementCallUrl, registerActiveClientWidgetApi, registerViewedClientWidgetApi, ] ); useEffect(() => { if ((activeCallRoomId && !viewedCallRoomId) || activeCallRoomId) setupWidget(primaryWidgetApiRef, primarySmallWidgetRef, primaryIframeRef, isPrimaryIframe); if ((!activeCallRoomId && viewedCallRoomId) || viewedCallRoomId) setupWidget(backupWidgetApiRef, backupSmallWidgetRef, backupIframeRef, !isPrimaryIframe); }, [ setupWidget, primaryWidgetApiRef, primarySmallWidgetRef, primaryIframeRef, backupWidgetApiRef, backupSmallWidgetRef, backupIframeRef, registerActiveClientWidgetApi, registerViewedClientWidgetApi, activeCallRoomId, viewedCallRoomId, isCallActive, isPrimaryIframe, ]); const memoizedIframeRef = useMemo(() => primaryIframeRef, [primaryIframeRef]); const memoizedBackupIframeRef = useMemo(() => backupIframeRef, [backupIframeRef]); return (