Replace fetch with Axios in client

Replace `.then` with await syntax where possible.

GitLab: #142
Change-Id: I6c132f49f152afa7e20919a1c70c539f2ad54878
diff --git a/client/src/components/AccountPreferences.tsx b/client/src/components/AccountPreferences.tsx
index f0c5d31..2086f14 100644
--- a/client/src/components/AccountPreferences.tsx
+++ b/client/src/components/AccountPreferences.tsx
@@ -39,7 +39,6 @@
 import { useState } from 'react';
 
 import { useAuthContext } from '../contexts/AuthProvider';
-import { apiUrl } from '../utils/constants';
 import ConversationAvatar from './ConversationAvatar';
 import ConversationsOverviewCard from './ConversationsOverviewCard';
 import JamiIdCard from './JamiIdCard';
@@ -56,18 +55,8 @@
   },
 };
 
-type AccountPreferencesProps = {
-  // TODO: Remove account prop after migration to new server
-  account?: Account;
-};
-
-export default function AccountPreferences({ account: _account }: AccountPreferencesProps) {
-  const authContext = useAuthContext(true);
-  const account = _account ?? authContext?.account;
-  const token = authContext?.token;
-  if (!account || !token) {
-    throw new Error('Account not defined');
-  }
+export default function AccountPreferences() {
+  const { account, axiosInstance } = useAuthContext();
 
   const devices: string[][] = [];
   const accountDevices = account.getDevices();
@@ -82,40 +71,21 @@
 
   const [details, setDetails] = useState(account.getDetails());
 
-  const addModerator = () => {
+  const addModerator = async () => {
     if (defaultModeratorUri) {
-      fetch(new URL(`/default-moderators/${defaultModeratorUri}`, apiUrl), {
-        headers: {
-          Authorization: `Bearer ${token}`,
-        },
-        method: 'PUT',
-      });
+      await axiosInstance.put(`/default-moderators/${defaultModeratorUri}`);
       setDefaultModeratorUri('');
     }
   };
 
-  const removeModerator = (uri: string) =>
-    fetch(new URL(`/default-moderators/${uri}`, apiUrl), {
-      headers: {
-        Authorization: `Bearer ${token}`,
-      },
-      method: 'DELETE',
-    });
+  const removeModerator = async (uri: string) => await axiosInstance.delete(`/default-moderators/${uri}`);
 
-  const handleToggle = (key: keyof AccountDetails, value: boolean) => {
+  const handleToggle = async (key: keyof AccountDetails, value: boolean) => {
     console.log(`handleToggle ${key} ${value}`);
     const newDetails: Partial<AccountDetails> = {};
     newDetails[key] = value ? 'true' : 'false';
     console.log(newDetails);
-    fetch(new URL('/account', apiUrl), {
-      method: 'PATCH',
-      headers: {
-        Accept: 'application/json',
-        Authorization: `Bearer ${token}`,
-        'Content-Type': 'application/json',
-      },
-      body: JSON.stringify(newDetails),
-    });
+    await axiosInstance.patch('/account', newDetails);
     setDetails({ ...account.updateDetails(newDetails) });
   };
 
diff --git a/client/src/components/ContactList.jsx b/client/src/components/ContactList.jsx
index 3bc040b..578d3c9 100644
--- a/client/src/components/ContactList.jsx
+++ b/client/src/components/ContactList.jsx
@@ -23,7 +23,6 @@
 
 import { useAuthContext } from '../contexts/AuthProvider';
 import { useAppDispatch, useAppSelector } from '../redux/hooks';
-import { apiUrl } from '../utils/constants';
 import ConversationAvatar from './ConversationAvatar';
 
 const customStyles = {
@@ -38,7 +37,7 @@
 };
 
 export default function ContactList() {
-  const { token } = useAuthContext();
+  const { axiosInstance } = useAuthContext();
   const { accountId } = useAppSelector((state) => state.userInfo);
   const dispatch = useAppDispatch();
 
@@ -59,22 +58,19 @@
   const closeModalDetails = () => setModalDetailsIsOpen(false);
   const closeModalDelete = () => setModalDeleteIsOpen(false);
 
-  const getContactDetails = () => {
+  const getContactDetails = async () => {
     const controller = new AbortController();
-    fetch(new URL(`/contacts/${currentContact.id}`, apiUrl), {
-      signal: controller.signal,
-      headers: {
-        Authorization: `Bearer ${token}`,
-      },
-    })
-      .then((res) => res.json())
-      .then((result) => {
-        console.log('CONTACT LIST - DETAILS: ', result);
-      })
-      .catch((e) => console.log('ERROR GET CONTACT DETAILS: ', e));
+    try {
+      const data = await axiosInstance.get(`/contacts/${currentContact.id}`, {
+        signal: controller.signal,
+      });
+      console.log('CONTACT LIST - DETAILS: ', data);
+    } catch (e) {
+      console.log('ERROR GET CONTACT DETAILS: ', e);
+    }
   };
 
-  const removeOrBlock = (block = false) => {
+  const removeOrBlock = async (block = false) => {
     console.log('REMOVE');
     setBlockOrRemove(false);
     const controller = new AbortController();
@@ -82,33 +78,29 @@
     if (block) {
       url += '/block';
     }
-    fetch(new URL(url, apiUrl), {
-      signal: controller.signal,
-      method: block ? 'POST' : 'DELETE',
-      headers: {
-        Authorization: `Bearer ${token}`,
-      },
-    })
-      .then((res) => res.json())
-      .catch((e) => console.log(`ERROR ${block ? 'blocking' : 'removing'} CONTACT : `, e));
+    try {
+      await axiosInstance(url, {
+        signal: controller.signal,
+        method: block ? 'POST' : 'DELETE',
+      });
+    } catch (e) {
+      console.log(`ERROR ${block ? 'blocking' : 'removing'} CONTACT : `, e);
+    }
     closeModalDelete();
   };
 
   useEffect(() => {
     const controller = new AbortController();
-    fetch(new URL(`/contacts`, apiUrl), {
-      signal: controller.signal,
-      headers: {
-        Authorization: `Bearer ${token}`,
-      },
-    })
-      .then((res) => res.json())
-      .then((result) => {
-        console.log('CONTACTS: ', result);
-        setContacts(result);
+    axiosInstance
+      .get(`/contacts`, {
+        signal: controller.signal,
+      })
+      .then(({ data }) => {
+        console.log('CONTACTS: ', data);
+        setContacts(data);
       });
     return () => controller.abort();
-  }, [token]);
+  }, [axiosInstance]);
 
   return (
     <div className="rooms-list">
diff --git a/client/src/components/ConversationListItem.tsx b/client/src/components/ConversationListItem.tsx
index 5f10f6e..aeef7de 100644
--- a/client/src/components/ConversationListItem.tsx
+++ b/client/src/components/ConversationListItem.tsx
@@ -36,7 +36,6 @@
 import { useAuthContext } from '../contexts/AuthProvider';
 import { setRefreshFromSlice } from '../redux/appSlice';
 import { useAppDispatch } from '../redux/hooks';
-import { apiUrl } from '../utils/constants';
 import ConversationAvatar from './ConversationAvatar';
 import {
   AudioCallIcon,
@@ -89,7 +88,7 @@
 };
 
 export default function ConversationListItem({ conversation }: ConversationListItemProps) {
-  const { token } = useAuthContext();
+  const { axiosInstance } = useAuthContext();
   const { conversationId, contactId } = useParams();
   const dispatch = useAppDispatch();
 
@@ -115,47 +114,36 @@
   const closeModalDetails = () => setModalDetailsIsOpen(false);
   const closeModalDelete = () => setModalDeleteIsOpen(false);
 
-  const getContactDetails = () => {
+  const getContactDetails = async () => {
     const controller = new AbortController();
-    fetch(new URL(`/contacts/${userId}`, apiUrl), {
-      signal: controller.signal,
-      headers: {
-        Authorization: `Bearer ${token}`,
-      },
-    })
-      .then((res) => res.json())
-      .then((result) => {
-        console.log('CONTACT LIST - DETAILS: ', result);
-      })
-      .catch((e) => console.log('ERROR GET CONTACT DETAILS: ', e));
+    try {
+      const data = await axiosInstance.get(`/contacts/${userId}`, {
+        signal: controller.signal,
+      });
+      console.log('CONTACT LIST - DETAILS: ', data);
+    } catch (e) {
+      console.log('ERROR GET CONTACT DETAILS: ', e);
+    }
   };
 
-  const removeOrBlock = (block = false) => {
+  const removeOrBlock = async (block = false) => {
     setBlockOrRemove(false);
 
-    console.log('EEEH', conversation.getAccountId(), userId);
-
     const controller = new AbortController();
     let url = `/contacts/${userId}`;
     if (block) {
       url += '/block';
     }
-    fetch(new URL(url, apiUrl), {
-      signal: controller.signal,
-      method: block ? 'POST' : 'DELETE',
-      headers: {
-        Authorization: `Bearer ${token}`,
-      },
-    })
-      .then((res) => res.json())
-      .then(() => {
-        console.log('propre');
-        dispatch(setRefreshFromSlice());
-      })
-      .catch((e) => {
-        console.log(`ERROR ${block ? 'blocking' : 'removing'} CONTACT : `, e);
-        dispatch(setRefreshFromSlice());
+    try {
+      await axiosInstance(url, {
+        signal: controller.signal,
+        method: block ? 'POST' : 'DELETE',
       });
+      dispatch(setRefreshFromSlice());
+    } catch (e) {
+      console.error(`Error ${block ? 'blocking' : 'removing'} contact : `, e);
+      dispatch(setRefreshFromSlice());
+    }
     closeModalDelete();
   };
 
diff --git a/client/src/components/ConversationsOverviewCard.tsx b/client/src/components/ConversationsOverviewCard.tsx
index 8a73cc2..84d022d 100644
--- a/client/src/components/ConversationsOverviewCard.tsx
+++ b/client/src/components/ConversationsOverviewCard.tsx
@@ -21,10 +21,9 @@
 import { useNavigate } from 'react-router';
 
 import { useAuthContext } from '../contexts/AuthProvider';
-import { apiUrl } from '../utils/constants';
 
 export default function ConversationsOverviewCard() {
-  const { token, account } = useAuthContext();
+  const { axiosInstance, account } = useAuthContext();
   const navigate = useNavigate();
 
   const [conversationCount, setConversationCount] = useState<number | undefined>();
@@ -33,19 +32,16 @@
 
   useEffect(() => {
     const controller = new AbortController();
-    fetch(new URL('/conversations', apiUrl), {
-      headers: {
-        Authorization: `Bearer ${token}`,
-      },
-      signal: controller.signal,
-    })
-      .then((res) => res.json())
-      .then((result: Conversation[]) => {
-        console.log(result);
-        setConversationCount(result.length);
+    axiosInstance
+      .get<Conversation[]>('/conversations', {
+        signal: controller.signal,
+      })
+      .then(({ data }) => {
+        console.log(data);
+        setConversationCount(data.length);
       });
     return () => controller.abort(); // crash on React18
-  }, [token, accountId]);
+  }, [axiosInstance, accountId]);
 
   return (
     <Card onClick={() => navigate(`/`)}>
diff --git a/client/src/components/UsernameChooser.jsx b/client/src/components/UsernameChooser.jsx
index 3c1f584..77c1d73 100644
--- a/client/src/components/UsernameChooser.jsx
+++ b/client/src/components/UsernameChooser.jsx
@@ -17,8 +17,8 @@
  */
 import { SearchRounded } from '@mui/icons-material';
 import { InputAdornment, TextField } from '@mui/material';
+import axios from 'axios';
 import { useEffect, useState } from 'react';
-import usePromise from 'react-fetch-hook/usePromise';
 
 import { apiUrl } from '../utils/constants.js';
 
@@ -26,17 +26,29 @@
 
 export default function UsernameChooser({ setName, ...props }) {
   const [query, setQuery] = useState('');
+  const [isLoading, setIsLoading] = useState(true);
+  const [error, setError] = useState();
+  const [data, setData] = useState();
 
-  const { isLoading, data, error } = usePromise(
-    () =>
-      isInputValid(query)
-        ? fetch(new URL(`/ns/username/${query}`, apiUrl)).then((res) => {
-            if (res.status === 200) return res.json();
-            else throw res.status;
-          })
-        : new Promise((res, rej) => rej(400)),
-    [query]
-  );
+  useEffect(() => {
+    if (isInputValid(query)) {
+      setIsLoading(true);
+      axios
+        .get(`/ns/username/${query}`, {
+          baseURL: apiUrl,
+        })
+        .then((res) => {
+          setIsLoading(false);
+          if (res.status === 200) {
+            setData(res.data);
+          } else {
+            throw res.status;
+          }
+        });
+    } else {
+      setError(400);
+    }
+  }, [query]);
 
   useEffect(() => {
     if (!isLoading) {