Convert ConversationListItem to TypeScript

GitLab: #30

Change-Id: I01f1c9382a02e9ebec50dfb48c010ed2c7337515
diff --git a/client/src/components/ConversationListItem.tsx b/client/src/components/ConversationListItem.tsx
new file mode 100644
index 0000000..bab36b0
--- /dev/null
+++ b/client/src/components/ConversationListItem.tsx
@@ -0,0 +1,424 @@
+/*
+ * 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 { Box, ListItem, ListItemAvatar, ListItemText, Stack, StackProps, Typography } from '@mui/material';
+import { Conversation } from 'jami-web-common';
+import { QRCodeCanvas } from 'qrcode.react';
+import { MouseEvent, useState } from 'react';
+import Modal from 'react-modal';
+import { useNavigate, useParams } from 'react-router-dom';
+
+import authManager from '../AuthManager';
+import { setRefreshFromSlice } from '../redux/appSlice';
+import { useAppDispatch } from '../redux/hooks';
+import ConversationAvatar from './ConversationAvatar';
+import { RemoveContactIcon, VideoCallIcon } from './SvgIcon';
+import { AudioCallIcon, BlockContactIcon, ContactDetailsIcon, CrossIcon, MessageIcon } from './SvgIcon';
+
+const customStyles: Modal.Styles = {
+  content: {
+    // right: "auto",
+    // bottom: "auto",
+    // // marginRight: "-50%",
+    // transform: "translate(-50%, -50%)",
+    // padding: "16px"
+
+    // top: "1364px",
+    left: '94px',
+    width: '180px',
+    height: '262px',
+    background: '#FFFFFF 0% 0% no-repeat padding-box',
+    boxShadow: '3px 3px 7px #00000029',
+    borderRadius: '5px 20px 20px 20px',
+    opacity: '1',
+
+    textAlign: 'left',
+    font: 'normal normal normal 12px/26px Ubuntu',
+    letterSpacing: '0px',
+    color: '#000000',
+  },
+};
+
+const cancelStyles: Modal.Styles = {
+  content: {
+    left: '94px',
+    width: '300px',
+    height: '220px',
+    background: '#FFFFFF 0% 0% no-repeat padding-box',
+    boxShadow: '3px 3px 7px #00000029',
+    borderRadius: '20px',
+    opacity: '1',
+
+    textAlign: 'left',
+    font: 'normal normal normal 12px/26px Ubuntu',
+    letterSpacing: '0px',
+    color: '#000000',
+  },
+};
+
+const contactDetailsStyles: Modal.Styles = {
+  content: {
+    left: '94px',
+    width: '450px',
+    height: '450px',
+    background: '#FFFFFF 0% 0% no-repeat padding-box',
+    boxShadow: '3px 3px 7px #00000029',
+    borderRadius: '20px',
+    opacity: '1',
+
+    textAlign: 'left',
+    font: 'normal normal normal 12px/26px Ubuntu',
+    letterSpacing: '0px',
+    color: '#000000',
+  },
+};
+
+const stackStyles: StackProps = {
+  flexDirection: 'row',
+  marginBottom: '4px',
+  spacing: '40px',
+  flex: 1,
+  alignItems: 'center',
+};
+
+const iconTextStyle = {
+  marginRight: '10px',
+};
+
+const iconColor = '#005699';
+
+type ConversationListItemProps = {
+  conversation: Conversation;
+};
+
+export default function ConversationListItem({ conversation }: ConversationListItemProps) {
+  const { conversationId, contactId } = useParams();
+  const dispatch = useAppDispatch();
+
+  const pathId = conversationId || contactId;
+  const isSelected = conversation.getDisplayUri() === pathId;
+  const navigate = useNavigate();
+
+  const [modalIsOpen, setIsOpen] = useState(false);
+  const [modalDetailsIsOpen, setModalDetailsIsOpen] = useState(false);
+  const [modalDeleteIsOpen, setModalDeleteIsOpen] = useState(false);
+  const [blockOrRemove, setBlockOrRemove] = useState(true);
+  const [userId, setUserId] = useState(conversation?.getFirstMember()?.contact.getUri());
+  const [isSwarm, setIsSwarm] = useState('true');
+
+  const openModal = (e: MouseEvent<HTMLDivElement>) => {
+    e.preventDefault();
+    console.log(e);
+    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/${conversation.getAccountId()}/contacts/details/${userId}`, {
+        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: 'block' | 'remove') => {
+    console.log(typeOfRemove);
+    setBlockOrRemove(false);
+
+    console.log('EEEH', typeOfRemove, conversation.getAccountId(), userId);
+
+    const controller = new AbortController();
+    authManager
+      .fetch(`/api/accounts/${conversation.getAccountId()}/contacts/${typeOfRemove}/${userId}`, {
+        signal: controller.signal,
+        method: 'DELETE',
+      })
+      .then((res) => res.json())
+      .then((result) => {
+        console.log('propre');
+        dispatch(setRefreshFromSlice());
+      })
+      .catch((e) => {
+        console.log(`ERROR ${typeOfRemove}ing CONTACT : `, e);
+        dispatch(setRefreshFromSlice());
+      });
+    closeModalDelete();
+  };
+
+  const uri = conversation.getId() ? `conversation/${conversation.getId()}` : `addContact/${userId}`;
+  return (
+    <div onContextMenu={openModal}>
+      <div>
+        <Modal
+          isOpen={modalIsOpen}
+          //   onAfterOpen={afterOpenModal}
+          onRequestClose={closeModal}
+          style={customStyles}
+          contentLabel="Example Modal"
+        >
+          <Stack
+            onClick={() => {
+              navigate(`/account/${conversation.getAccountId()}/${uri}`);
+              closeModal();
+            }}
+            {...stackStyles}
+          >
+            <div style={{ ...iconTextStyle }}>
+              <MessageIcon style={{ color: iconColor }} />
+            </div>
+            Message
+          </Stack>
+          <Stack {...stackStyles}>
+            <div style={{ ...iconTextStyle }}>
+              <AudioCallIcon style={{ color: iconColor }} />
+            </div>
+            Démarrer appel audio
+          </Stack>
+
+          <Stack {...stackStyles}>
+            <div style={{ ...iconTextStyle }}>
+              <VideoCallIcon style={{ color: iconColor }} />
+            </div>
+            Démarrer appel vidéo
+          </Stack>
+
+          <Stack
+            {...stackStyles}
+            onClick={() => {
+              navigate(`/account/${conversation.getAccountId()}/`);
+              closeModal();
+            }}
+          >
+            <div style={{ ...iconTextStyle }}>
+              <CrossIcon style={{ color: iconColor }} />
+            </div>
+            Fermer la conversation
+          </Stack>
+
+          <Stack
+            onClick={() => {
+              console.log('open details contact for: ');
+              closeModal();
+              openModalDetails();
+              getContactDetails();
+            }}
+            {...stackStyles}
+          >
+            <div style={{ ...iconTextStyle }}>
+              <ContactDetailsIcon style={{ color: iconColor }} />
+            </div>
+            Détails de la conversation
+          </Stack>
+
+          <Stack
+            onClick={() => {
+              setBlockOrRemove(true);
+              closeModal();
+              openModalDelete();
+            }}
+            {...stackStyles}
+          >
+            <div style={{ ...iconTextStyle }}>
+              <BlockContactIcon style={{ color: iconColor }} />
+            </div>
+            Bloquer le contact
+          </Stack>
+
+          <Stack
+            onClick={() => {
+              setBlockOrRemove(false);
+              closeModal();
+              openModalDelete();
+            }}
+            {...stackStyles}
+          >
+            <div style={{ ...iconTextStyle }}>
+              <RemoveContactIcon style={{ color: iconColor }} />
+            </div>
+            Supprimer contact
+          </Stack>
+        </Modal>
+      </div>
+
+      <div>
+        <Modal
+          isOpen={modalDetailsIsOpen}
+          onRequestClose={closeModalDetails}
+          style={contactDetailsStyles}
+          contentLabel="Détails contact"
+        >
+          <Stack direction={'row'} alignContent="flex-end">
+            <Stack direction={'column'}>
+              <div style={{ height: '100px' }}>
+                <ConversationAvatar displayName={conversation.getDisplayNameNoFallback()} />
+              </div>
+
+              <div
+                style={{
+                  fontSize: '20px',
+                  marginBottom: '20px',
+                  height: '20px',
+                }}
+              >
+                Informations
+              </div>
+
+              <Typography variant="caption">Nom d&apos;utilisateur</Typography>
+              <div style={{ height: '20px' }} />
+              <Typography variant="caption">Identifiant </Typography>
+              <div style={{ height: '20px' }} />
+
+              <div
+                style={{
+                  flex: 1,
+                  height: '150px',
+                  flexDirection: 'column',
+                  // alignSelf: "flex-end",
+                }}
+              >
+                <Typography variant="caption">Code QR</Typography>
+              </div>
+
+              <Typography variant="caption">est un swarm </Typography>
+            </Stack>
+
+            <Stack direction={'column'}>
+              <div
+                style={{
+                  fontWeight: 'bold',
+                  fontSize: '20px',
+                  height: '100px',
+                }}
+              >
+                {conversation.getDisplayNameNoFallback() + '(resolved name)'}
+              </div>
+
+              <div
+                style={{
+                  height: '40px',
+                }}
+              />
+              <Typography variant="caption">
+                <div style={{ fontWeight: 'bold' }}>{conversation.getDisplayNameNoFallback()}</div>
+              </Typography>
+
+              <div style={{ height: '20px' }} />
+
+              <Typography variant="caption">
+                <div style={{ fontWeight: 'bold' }}> {userId}</div>
+              </Typography>
+
+              <div style={{ height: '20px' }} />
+
+              <div>
+                <QRCodeCanvas size={40} value={`${userId}`} />
+              </div>
+
+              <Typography variant="caption">
+                <div style={{ fontWeight: 'bold' }}> {isSwarm}</div>
+              </Typography>
+            </Stack>
+          </Stack>
+          <div
+            onClick={closeModalDetails}
+            style={{
+              width: '100px',
+              borderStyle: 'solid',
+              textAlign: 'center',
+              borderRadius: '5px',
+              marginLeft: '150px',
+              marginTop: '10px',
+            }}
+          >
+            <Typography variant="caption">Fermer</Typography>
+          </div>
+        </Modal>
+      </div>
+
+      <div>
+        <Modal
+          isOpen={modalDeleteIsOpen}
+          onRequestClose={closeModalDelete}
+          style={cancelStyles}
+          contentLabel="Merci de confirmer"
+        >
+          <Typography variant="h4">Merci de confirmer</Typography>
+          <Stack direction={'column'} justifyContent="space-around" spacing={'75px'}>
+            <div style={{ textAlign: 'center', marginTop: '10%' }}>
+              <Typography variant="body2">
+                Voulez vous vraiment {blockOrRemove ? 'bloquer' : 'supprimer'} ce contact?
+              </Typography>
+            </div>
+
+            <Stack direction={'row'} top={'25px'} alignSelf="center" spacing={1}>
+              <Box
+                onClick={() => {
+                  if (blockOrRemove) removeOrBlock('block');
+                  else removeOrBlock('remove');
+                }}
+                style={{
+                  width: '100px',
+                  textAlign: 'center',
+                  borderStyle: 'solid',
+                  borderColor: 'red',
+                  borderRadius: '10px',
+                  color: 'red',
+                }}
+              >
+                {blockOrRemove ? 'Bloquer' : 'Supprimer'}
+              </Box>
+              <Box
+                onClick={closeModalDelete}
+                style={{
+                  width: '100px',
+                  textAlign: 'center',
+                  paddingLeft: '12px',
+                  paddingRight: '12px',
+                  borderStyle: 'solid',
+                  borderRadius: '10px',
+                }}
+              >
+                Annuler
+              </Box>
+            </Stack>
+          </Stack>
+        </Modal>
+      </div>
+
+      <ListItem
+        button
+        alignItems="flex-start"
+        selected={isSelected}
+        onClick={() => navigate(`/account/${conversation.getAccountId()}/${uri}`)}
+      >
+        <ListItemAvatar>
+          <ConversationAvatar displayName={conversation.getDisplayNameNoFallback()} />
+        </ListItemAvatar>
+        <ListItemText primary={conversation.getDisplayName()} secondary={conversation.getDisplayUri()} />
+      </ListItem>
+    </div>
+  );
+}