Decouple client from server

Add Vite dependency and remove server side rendering to make it
possible to run the client independently.
Remove webpack config, replace with the `Vite` build tool.

GitLab: #55
Change-Id: I3a05d2e86cf6cb0ab91e77b3696f393132137575
diff --git a/client/src/components/ContactList.jsx b/client/src/components/ContactList.jsx
new file mode 100644
index 0000000..2aee98b
--- /dev/null
+++ b/client/src/components/ContactList.jsx
@@ -0,0 +1,199 @@
+/*
+ * 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 { Person } from '@mui/icons-material';
+import { ListItem, ListItemAvatar, ListItemText } from '@mui/material';
+import List from '@mui/material/List';
+import { useEffect, useState } from 'react';
+import Modal from 'react-modal';
+
+import authManager from '../AuthManager';
+import { useAppDispatch, useAppSelector } from '../redux/hooks';
+import ConversationAvatar from './ConversationAvatar';
+
+const customStyles = {
+  content: {
+    top: '50%',
+    left: '50%',
+    right: 'auto',
+    bottom: 'auto',
+    marginRight: '-50%',
+    transform: 'translate(-50%, -50%)',
+  },
+};
+
+export default function ContactList() {
+  const { accountId, accountObject } = useAppSelector((state) => state.app);
+  const dispatch = useAppDispatch();
+
+  const [contacts, setContacts] = useState([]);
+  const [currentContact, setCurrentContact] = useState({});
+
+  const [modalIsOpen, setIsOpen] = useState(false);
+  const [modalDetailsIsOpen, setModalDetailsIsOpen] = useState(false);
+  const [modalDeleteIsOpen, setModalDeleteIsOpen] = useState(false);
+  const [blockOrRemove, setBlockOrRemove] = useState(true);
+
+  const openModal = () => setIsOpen(true);
+  const openModalDetails = () => setModalDetailsIsOpen(true);
+  const openModalDelete = () => setModalDeleteIsOpen(true);
+
+  const closeModal = () => setIsOpen(false);
+
+  const closeModalDetails = () => setModalDetailsIsOpen(false);
+  const closeModalDelete = () => setModalDeleteIsOpen(false);
+
+  const getContactDetails = () => {
+    const controller = new AbortController();
+    authManager
+      .fetch(`/api/accounts/${accountId}/contacts/details/${currentContact.id}`, {
+        signal: controller.signal,
+      })
+      .then((res) => res.json())
+      .then((result) => {
+        console.log('CONTACT LIST - DETAILS: ', result);
+      })
+      .catch((e) => console.log('ERROR GET CONTACT DETAILS: ', e));
+  };
+
+  const removeOrBlock = (typeOfRemove) => {
+    console.log('REMOVE');
+    setBlockOrRemove(false);
+    const controller = new AbortController();
+    authManager
+      .fetch(`/api/accounts/${accountId}/contacts/${typeOfRemove}/${currentContact.id}`, {
+        signal: controller.signal,
+        method: 'DELETE',
+      })
+      .then((res) => res.json())
+      .catch((e) => console.log(`ERROR ${typeOfRemove}ing CONTACT : `, e));
+    closeModalDelete();
+  };
+
+  useEffect(() => {
+    const controller = new AbortController();
+    authManager
+      .fetch(`/api/accounts/${accountId}/contacts`, {
+        signal: controller.signal,
+      })
+      .then((res) => res.json())
+      .then((result) => {
+        console.log('CONTACTS: ', result);
+        setContacts(result);
+      });
+    return () => controller.abort();
+  }, [accountId, blockOrRemove]);
+
+  return (
+    <div className="rooms-list">
+      <Modal
+        isOpen={modalIsOpen}
+        //   onAfterOpen={afterOpenModal}
+        onRequestClose={closeModal}
+        style={customStyles}
+        contentLabel="Example Modal"
+      >
+        {/* <h2 ref={(_subtitle) => (subtitle = _subtitle)}>Hello</h2> */}
+        <button onClick={closeModal}>close</button>
+
+        {/* <div>
+            <Person /> Démarrer appel vidéo
+          </div>
+          <br />
+
+          <div>
+            <Person /> Démarrer appel audio
+          </div> */}
+        <br />
+
+        <div
+          onClick={() => {
+            console.log('open dialog Supprimer: ');
+            setBlockOrRemove(false);
+            closeModal();
+            openModalDelete();
+          }}
+        >
+          <Person /> Supprimer contact
+        </div>
+        <br />
+
+        <div
+          onClick={() => {
+            console.log('open dialog BLOCK: ');
+            setBlockOrRemove(true);
+            closeModal();
+            openModalDelete();
+          }}
+        >
+          <Person /> Bloquer le contact
+        </div>
+        <br />
+
+        <div
+          onClick={() => {
+            console.log('open details contact for: ');
+            closeModal();
+            openModalDetails();
+            getContactDetails();
+          }}
+        >
+          <Person /> Détails du contact
+        </div>
+      </Modal>
+      <Modal
+        isOpen={modalDeleteIsOpen}
+        //   onAfterOpen={afterOpenModalDetails}
+        onRequestClose={closeModalDelete}
+        style={customStyles}
+        contentLabel="Merci de confirmer"
+      >
+        Voulez vous vraiment {blockOrRemove ? 'bloquer' : 'supprimer'} ce contact?
+        <br />
+        {blockOrRemove ? (
+          <button onClick={() => removeOrBlock('block')}>Bloquer</button>
+        ) : (
+          <button onClick={() => removeOrBlock('remove')}>Supprimer</button>
+        )}
+        <button onClick={closeModalDelete}>Annuler</button>
+      </Modal>
+
+      <List>
+        {contacts?.map((contact) => (
+          <ListItem
+            button
+            alignItems="flex-start"
+            key={contact.id}
+            // selected={isSelected}
+            onClick={() => {
+              setCurrentContact(contact);
+              openModal();
+            }}
+          >
+            <ListItemAvatar>
+              <ConversationAvatar
+              // displayName={conversation.getDisplayNameNoFallback()}
+              // displayName={`${contact.id}`}
+              />
+            </ListItemAvatar>
+            <ListItemText primary={contact.id} secondary={contact.id} />
+          </ListItem>
+        ))}
+      </List>
+    </div>
+  );
+}