Transform CallProvider into 'CallManager' hook, review WebSocket messages for calls
- These changes allowed to remove more cascading effects. It is now possible to reactivate StrictMode. Downside is we lost the 'optional context' of CallProvider: the call logic will be loaded even if there is no call.
- The WebSocket messages have been changed so the client does not have to know the conversation members before a call. Previously, the client had to fetch the conversation members for a call, which was causing cascading effects.
- Accidentally, moving the handling of conversation members to the server added some logic for calls with more than two participants, but it is still not ready to work.
* CallProvider.tsx will be renamed in next commit in order to make it easier to track its file history
Change-Id: Iae711009adafce065ac3defc1c91c7ca0f37898c
diff --git a/client/src/contexts/CallManagerProvider.tsx b/client/src/contexts/CallManagerProvider.tsx
index ec68765..8f44a1b 100644
--- a/client/src/contexts/CallManagerProvider.tsx
+++ b/client/src/contexts/CallManagerProvider.tsx
@@ -15,117 +15,28 @@
* License along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
-import { CallBegin, ConversationInfos, WebSocketMessageType } from 'jami-web-common';
-import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
-import { useTranslation } from 'react-i18next';
-import { useNavigate } from 'react-router-dom';
-
import { RemoteVideoOverlay } from '../components/VideoOverlay';
+import { createOptionalContext } from '../hooks/createOptionalContext';
import { useUrlParams } from '../hooks/useUrlParams';
-import { ConversationMember } from '../models/conversation-member';
import { ConversationRouteParams } from '../router';
-import { useConversationInfosQuery, useMembersQuery } from '../services/conversationQueries';
-import { SetState, WithChildren } from '../utils/utils';
-import { AlertSnackbarContext } from './AlertSnackbarProvider';
-import CallProvider, { CallRole } from './CallProvider';
-import { useWebSocketContext } from './WebSocketProvider';
+import { WithChildren } from '../utils/utils';
+import { ICallManager, useCallManager } from './CallProvider';
-export type CallData = {
- conversationId: string;
- role: CallRole;
- withVideoOn?: boolean;
-};
-
-type ICallManagerContext = {
- callData: CallData | undefined;
- callConversationInfos: ConversationInfos | undefined;
- callMembers: ConversationMember[] | undefined;
- startCall: SetState<CallData | undefined>;
- exitCall: () => void;
-};
-
-const defaultCallManagerContext: ICallManagerContext = {
- callData: undefined,
- callConversationInfos: undefined,
- callMembers: undefined,
- startCall: () => {},
- exitCall: () => {},
-};
-
-export const CallManagerContext = createContext<ICallManagerContext>(defaultCallManagerContext);
-CallManagerContext.displayName = 'CallManagerContext';
+const optionalCallManagerContext = createOptionalContext<ICallManager>('CallManagerContext');
+export const useCallManagerContext = optionalCallManagerContext.useOptionalContext;
export default ({ children }: WithChildren) => {
- const [callData, setCallData] = useState<CallData>();
- const { setAlertContent } = useContext(AlertSnackbarContext);
- const webSocket = useWebSocketContext();
- const navigate = useNavigate();
- const { data: conversationInfos } = useConversationInfosQuery(callData?.conversationId);
- const { data: members } = useMembersQuery(callData?.conversationId);
const { urlParams } = useUrlParams<ConversationRouteParams>();
- const { t } = useTranslation();
+ const callManager = useCallManager();
- const failStartCall = useCallback(() => {
- throw new Error('Cannot start call: Already in a call');
- }, []);
-
- const startCall = !callData ? setCallData : failStartCall;
-
- const exitCall = useCallback(() => {
- if (!callData) {
- return;
- }
-
- setCallData(undefined);
- // TODO: write in chat that the call ended
- }, [callData]);
-
- useEffect(() => {
- const callBeginListener = ({ conversationId, withVideoOn }: CallBegin) => {
- if (callData) {
- // TODO: Currently, we display a notification if already in a call.
- // In the future, we should handle receiving a call while already in another.
- setAlertContent({
- messageI18nKey: 'missed_incoming_call',
- messageI18nContext: { conversationId },
- severity: 'info',
- alertOpen: true,
- });
- return;
- }
-
- startCall({ conversationId: conversationId, role: 'receiver', withVideoOn });
- navigate(`/conversation/${conversationId}`);
- };
-
- webSocket.bind(WebSocketMessageType.CallBegin, callBeginListener);
-
- return () => {
- webSocket.unbind(WebSocketMessageType.CallBegin, callBeginListener);
- };
- }, [webSocket, navigate, startCall, callData, setAlertContent, t]);
-
- const value = useMemo(
- () => ({
- startCall,
- callData,
- callConversationInfos: conversationInfos,
- callMembers: members,
- exitCall,
- }),
- [startCall, callData, conversationInfos, members, exitCall]
- );
+ const { callData } = callManager;
return (
- <>
- <CallManagerContext.Provider value={value}>
- <CallProvider>
- {callData && callData.conversationId !== urlParams.conversationId && (
- <RemoteVideoOverlay callConversationId={callData.conversationId} />
- )}
- {children}
- </CallProvider>
- </CallManagerContext.Provider>
- </>
+ <optionalCallManagerContext.Context.Provider value={callManager}>
+ {callData && callData.conversationId !== urlParams.conversationId && (
+ <RemoteVideoOverlay callConversationId={callData.conversationId} />
+ )}
+ {children}
+ </optionalCallManagerContext.Context.Provider>
);
};