Fix add contact and create MessengerProvider
Move all messenger logic and state from `Messenger.tsx` to a new context `MessengerProvider.tsx`.
Improve add contact logic to use a state in `MessengerContext` for the newContactId instead of a URL parameter. Remove `add-contact` route.
Improve messenger routing.
Fix remove contact.
GitLab: #171
Change-Id: Iea641deb12dbd339d03eff683b41834123a516ab
diff --git a/client/src/contexts/MessengerProvider.tsx b/client/src/contexts/MessengerProvider.tsx
new file mode 100644
index 0000000..f92a6d7
--- /dev/null
+++ b/client/src/contexts/MessengerProvider.tsx
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 Savoir-faire Linux Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this program. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+import { Contact, Conversation, ConversationMessage, WebSocketMessageType } from 'jami-web-common';
+import React, { createContext, ReactNode, useContext, useEffect, useState } from 'react';
+
+import { setRefreshFromSlice } from '../redux/appSlice';
+import { useAppDispatch, useAppSelector } from '../redux/hooks';
+import { SetState } from '../utils/utils';
+import { useAuthContext } from './AuthProvider';
+import { WebSocketContext } from './WebSocketProvider';
+
+export interface IMessengerContext {
+ conversations: Conversation[] | undefined;
+
+ setSearchQuery: SetState<string | undefined>;
+
+ searchResult: Conversation | undefined;
+
+ newContactId: string | undefined;
+ setNewContactId: SetState<string | undefined>;
+}
+
+const defaultMessengerContext: IMessengerContext = {
+ conversations: undefined,
+ newContactId: undefined,
+ setNewContactId: () => {},
+ setSearchQuery: () => {},
+ searchResult: undefined,
+};
+
+export const MessengerContext = createContext<IMessengerContext>(defaultMessengerContext);
+
+export default ({ children }: { children: ReactNode }) => {
+ const { refresh } = useAppSelector((state) => state.userInfo);
+ const dispatch = useAppDispatch();
+ const { accountId, axiosInstance } = useAuthContext();
+ const webSocket = useContext(WebSocketContext);
+
+ const [conversations, setConversations] = useState<Conversation[] | undefined>(undefined);
+ const [searchQuery, setSearchQuery] = useState<string>();
+ const [searchResult, setSearchResults] = useState<Conversation | undefined>(undefined);
+ const [newContactId, setNewContactId] = useState<string>();
+
+ useEffect(() => {
+ const controller = new AbortController();
+ axiosInstance
+ .get<Conversation[]>('/conversations', {
+ signal: controller.signal,
+ })
+ .then(({ data }) => {
+ setConversations(Object.values(data).map((c) => Conversation.from(accountId, c)));
+ });
+ // return () => controller.abort()
+ }, [axiosInstance, accountId, refresh]);
+
+ useEffect(() => {
+ if (!webSocket) {
+ return;
+ }
+
+ const conversationMessageListener = (_data: ConversationMessage) => {
+ dispatch(setRefreshFromSlice());
+ };
+
+ webSocket.bind(WebSocketMessageType.ConversationMessage, conversationMessageListener);
+
+ return () => {
+ webSocket.unbind(WebSocketMessageType.ConversationMessage, conversationMessageListener);
+ };
+ }, [webSocket, dispatch]);
+
+ useEffect(() => {
+ if (!searchQuery) return;
+ const controller = new AbortController();
+ // TODO: Type properly https://git.jami.net/savoirfairelinux/jami-web/-/issues/92
+ axiosInstance
+ .get<{ state: number; address: string; username: string }>(`/ns/username/${searchQuery}`, {
+ signal: controller.signal,
+ })
+ .then(({ data }) => {
+ const contact = new Contact(data.address);
+ contact.setRegisteredName(data.username);
+ setSearchResults(contact ? Conversation.fromSingleContact(accountId, contact) : undefined);
+ })
+ .catch(() => {
+ setSearchResults(undefined);
+ });
+ // return () => controller.abort() // crash on React18
+ }, [accountId, searchQuery, axiosInstance]);
+
+ return (
+ <MessengerContext.Provider
+ value={{
+ conversations,
+ setSearchQuery,
+ searchResult,
+ newContactId,
+ setNewContactId,
+ }}
+ >
+ {children}
+ </MessengerContext.Provider>
+ );
+};