blob: 89fb450aa3399961a625ceaabb9da32162b544b0 [file] [log] [blame]
simonf929a362022-11-18 16:53:45 -05001/*
2 * Copyright (C) 2022 Savoir-faire Linux Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public
15 * License along with this program. If not, see
16 * <https://www.gnu.org/licenses/>.
17 */
18import { Conversation, WebSocketMessageType } from 'jami-web-common';
19import { createContext, useCallback, useContext, useEffect, useState } from 'react';
20import { useNavigate } from 'react-router-dom';
21
22import LoadingPage from '../components/Loading';
23import { useUrlParams } from '../hooks/useUrlParams';
24import { ConversationRouteParams } from '../router';
25import { useConversationQuery } from '../services/Conversation';
26import { WithChildren } from '../utils/utils';
27import { useAuthContext } from './AuthProvider';
28import { WebSocketContext } from './WebSocketProvider';
29
30interface IConversationProvider {
31 conversationId: string;
32 conversation: Conversation;
33
34 beginCall: () => void;
35}
36
37export const ConversationContext = createContext<IConversationProvider>(undefined!);
38
39export default ({ children }: WithChildren) => {
40 const {
41 urlParams: { conversationId },
42 } = useUrlParams<ConversationRouteParams>();
43 const { account, accountId } = useAuthContext();
44 const webSocket = useContext(WebSocketContext);
45 const [isLoading, setIsLoading] = useState(false);
46 const [isError, setIsError] = useState(false);
47 const [conversation, setConversation] = useState<Conversation | undefined>();
48 const navigate = useNavigate();
49
50 const conversationQuery = useConversationQuery(conversationId);
51
52 useEffect(() => {
53 if (conversationQuery.isSuccess) {
54 const conversation = Conversation.from(accountId, conversationQuery.data);
55 setConversation(conversation);
56 }
57 }, [accountId, conversationQuery.isSuccess, conversationQuery.data]);
58
59 useEffect(() => {
60 setIsLoading(conversationQuery.isLoading);
61 }, [conversationQuery.isLoading]);
62
63 useEffect(() => {
64 setIsError(conversationQuery.isError);
65 }, [conversationQuery.isError]);
66
67 const beginCall = useCallback(() => {
68 if (!webSocket || !conversation) {
69 throw new Error('Could not begin call');
70 }
71
72 // TODO: Could we move this logic to the server? The client could make a single request with the conversationId, and the server is tasked with sending all the individual requests to the members of the conversation
73 for (const member of conversation.getMembers()) {
74 const callBegin = {
75 from: account.getId(),
76 to: member.contact.getUri(),
77 message: {
78 conversationId,
79 },
80 };
81
82 console.info('Sending CallBegin', callBegin);
83 webSocket.send(WebSocketMessageType.CallBegin, callBegin);
84 }
85
86 navigate(`/conversation/${conversationId}/call?role=caller`);
87 }, [conversationId, webSocket, conversation, account, navigate]);
88
89 useEffect(() => {
90 if (!conversation || !webSocket) {
91 return;
92 }
93 webSocket.send(WebSocketMessageType.ConversationView, { accountId, conversationId });
94 }, [accountId, conversation, conversationId, webSocket]);
95
96 if (isLoading) {
97 return <LoadingPage />;
98 }
99 if (isError || !conversation || !conversationId) {
100 return <div>Error loading conversation: {conversationId}</div>;
101 }
102
103 return (
104 <ConversationContext.Provider
105 value={{
106 conversationId,
107 conversation,
108 beginCall,
109 }}
110 >
111 {children}
112 </ConversationContext.Provider>
113 );
114};