blob: 9a928e742833a6673529048efbbb7ba53b7eda22 [file] [log] [blame]
simon575c9402022-10-25 16:21:40 -04001/*
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 */
simon1170c322022-10-31 14:51:31 -040018import {
19 Box,
20 ListItem,
21 ListItemAvatar,
22 ListItemIcon,
23 ListItemText,
24 Menu,
25 MenuItem,
26 Stack,
27 Typography,
28} from '@mui/material';
simon575c9402022-10-25 16:21:40 -040029import { Conversation } from 'jami-web-common';
30import { QRCodeCanvas } from 'qrcode.react';
31import { MouseEvent, useState } from 'react';
simon1170c322022-10-31 14:51:31 -040032import { Trans } from 'react-i18next';
simon575c9402022-10-25 16:21:40 -040033import Modal from 'react-modal';
34import { useNavigate, useParams } from 'react-router-dom';
35
36import authManager from '../AuthManager';
37import { setRefreshFromSlice } from '../redux/appSlice';
38import { useAppDispatch } from '../redux/hooks';
39import ConversationAvatar from './ConversationAvatar';
simon1170c322022-10-31 14:51:31 -040040import { CancelIcon, RemoveContactIcon, VideoCallIcon } from './SvgIcon';
41import { AudioCallIcon, BlockContactIcon, ContactDetailsIcon, MessageIcon } from './SvgIcon';
simon575c9402022-10-25 16:21:40 -040042
43const cancelStyles: Modal.Styles = {
44 content: {
45 left: '94px',
46 width: '300px',
47 height: '220px',
48 background: '#FFFFFF 0% 0% no-repeat padding-box',
49 boxShadow: '3px 3px 7px #00000029',
50 borderRadius: '20px',
51 opacity: '1',
52
53 textAlign: 'left',
54 font: 'normal normal normal 12px/26px Ubuntu',
55 letterSpacing: '0px',
56 color: '#000000',
57 },
58};
59
60const contactDetailsStyles: Modal.Styles = {
61 content: {
62 left: '94px',
63 width: '450px',
64 height: '450px',
65 background: '#FFFFFF 0% 0% no-repeat padding-box',
66 boxShadow: '3px 3px 7px #00000029',
67 borderRadius: '20px',
68 opacity: '1',
69
70 textAlign: 'left',
71 font: 'normal normal normal 12px/26px Ubuntu',
72 letterSpacing: '0px',
73 color: '#000000',
74 },
75};
76
simon575c9402022-10-25 16:21:40 -040077const iconColor = '#005699';
78
79type ConversationListItemProps = {
80 conversation: Conversation;
81};
82
83export default function ConversationListItem({ conversation }: ConversationListItemProps) {
84 const { conversationId, contactId } = useParams();
85 const dispatch = useAppDispatch();
86
87 const pathId = conversationId || contactId;
88 const isSelected = conversation.getDisplayUri() === pathId;
89 const navigate = useNavigate();
90
simon1170c322022-10-31 14:51:31 -040091 const [menuAnchorEl, setMenuAnchorEl] = useState<HTMLElement | null>(null);
simon575c9402022-10-25 16:21:40 -040092 const [modalDetailsIsOpen, setModalDetailsIsOpen] = useState(false);
93 const [modalDeleteIsOpen, setModalDeleteIsOpen] = useState(false);
94 const [blockOrRemove, setBlockOrRemove] = useState(true);
simon416d0792022-11-03 02:46:18 -040095 const [userId] = useState(conversation?.getFirstMember()?.contact.getUri());
96 const [isSwarm] = useState(true);
simon575c9402022-10-25 16:21:40 -040097
Michelle Sepkap Simeb3dd3122022-11-03 02:12:39 -040098 const navigateUrlPrefix = `/deprecated-account/${conversation.getAccountId()}`;
99
simon1170c322022-10-31 14:51:31 -0400100 const openMenu = (e: MouseEvent<HTMLDivElement>) => {
simon575c9402022-10-25 16:21:40 -0400101 e.preventDefault();
102 console.log(e);
simon1170c322022-10-31 14:51:31 -0400103 setMenuAnchorEl(e.currentTarget);
simon575c9402022-10-25 16:21:40 -0400104 };
105 const openModalDetails = () => setModalDetailsIsOpen(true);
106 const openModalDelete = () => setModalDeleteIsOpen(true);
simon1170c322022-10-31 14:51:31 -0400107 const closeModal = () => setMenuAnchorEl(null);
simon575c9402022-10-25 16:21:40 -0400108 const closeModalDetails = () => setModalDetailsIsOpen(false);
109 const closeModalDelete = () => setModalDeleteIsOpen(false);
110
111 const getContactDetails = () => {
112 const controller = new AbortController();
113 authManager
114 .fetch(`/api/accounts/${conversation.getAccountId()}/contacts/details/${userId}`, {
115 signal: controller.signal,
116 })
117 .then((res) => res.json())
118 .then((result) => {
119 console.log('CONTACT LIST - DETAILS: ', result);
120 })
121 .catch((e) => console.log('ERROR GET CONTACT DETAILS: ', e));
122 };
123
124 const removeOrBlock = (typeOfRemove: 'block' | 'remove') => {
125 console.log(typeOfRemove);
126 setBlockOrRemove(false);
127
128 console.log('EEEH', typeOfRemove, conversation.getAccountId(), userId);
129
130 const controller = new AbortController();
131 authManager
132 .fetch(`/api/accounts/${conversation.getAccountId()}/contacts/${typeOfRemove}/${userId}`, {
133 signal: controller.signal,
134 method: 'DELETE',
135 })
136 .then((res) => res.json())
simon416d0792022-11-03 02:46:18 -0400137 .then(() => {
simon575c9402022-10-25 16:21:40 -0400138 console.log('propre');
139 dispatch(setRefreshFromSlice());
140 })
141 .catch((e) => {
142 console.log(`ERROR ${typeOfRemove}ing CONTACT : `, e);
143 dispatch(setRefreshFromSlice());
144 });
145 closeModalDelete();
146 };
147
148 const uri = conversation.getId() ? `conversation/${conversation.getId()}` : `addContact/${userId}`;
149 return (
simon1170c322022-10-31 14:51:31 -0400150 <div onContextMenu={openMenu}>
simon575c9402022-10-25 16:21:40 -0400151 <div>
simon1170c322022-10-31 14:51:31 -0400152 <Menu open={!!menuAnchorEl} onClose={closeModal} anchorEl={menuAnchorEl}>
153 <MenuItem
simon575c9402022-10-25 16:21:40 -0400154 onClick={() => {
Michelle Sepkap Simeb3dd3122022-11-03 02:12:39 -0400155 navigate(`${navigateUrlPrefix}/${uri}`);
simon575c9402022-10-25 16:21:40 -0400156 closeModal();
157 }}
simon575c9402022-10-25 16:21:40 -0400158 >
simon1170c322022-10-31 14:51:31 -0400159 <ListItemIcon>
simon575c9402022-10-25 16:21:40 -0400160 <MessageIcon style={{ color: iconColor }} />
simon1170c322022-10-31 14:51:31 -0400161 </ListItemIcon>
162 <ListItemText>
163 <Trans i18nKey="conversation_message" />
164 </ListItemText>
165 </MenuItem>
166 <MenuItem
simon575c9402022-10-25 16:21:40 -0400167 onClick={() => {
Michelle Sepkap Simeb3dd3122022-11-03 02:12:39 -0400168 navigate(`${navigateUrlPrefix}/call/${conversation.getId()}`);
simon575c9402022-10-25 16:21:40 -0400169 }}
170 >
simon1170c322022-10-31 14:51:31 -0400171 <ListItemIcon>
172 <AudioCallIcon style={{ color: iconColor }} />
173 </ListItemIcon>
174 <ListItemText>
175 <Trans i18nKey="conversation_start_audiocall" />
176 </ListItemText>
177 </MenuItem>
simon575c9402022-10-25 16:21:40 -0400178
simon1170c322022-10-31 14:51:31 -0400179 <MenuItem
180 onClick={() => {
Michelle Sepkap Simeb3dd3122022-11-03 02:12:39 -0400181 navigate(`${navigateUrlPrefix}/call/${conversation.getId()}?video=true`);
simon1170c322022-10-31 14:51:31 -0400182 }}
183 >
184 <ListItemIcon>
185 <VideoCallIcon style={{ color: iconColor }} />
186 </ListItemIcon>
187 <ListItemText>
188 <Trans i18nKey="conversation_start_videocall" />
189 </ListItemText>
190 </MenuItem>
191
192 {isSelected && (
193 <MenuItem
194 onClick={() => {
Michelle Sepkap Simeb3dd3122022-11-03 02:12:39 -0400195 navigate(`${navigateUrlPrefix}/`);
simon1170c322022-10-31 14:51:31 -0400196 closeModal();
197 }}
198 >
199 <ListItemIcon>
200 <CancelIcon style={{ color: iconColor }} />
201 </ListItemIcon>
202 <ListItemText>
203 <Trans i18nKey="conversation_close" />
204 </ListItemText>
205 </MenuItem>
206 )}
207
208 <MenuItem
simon575c9402022-10-25 16:21:40 -0400209 onClick={() => {
210 console.log('open details contact for: ');
211 closeModal();
212 openModalDetails();
213 getContactDetails();
214 }}
simon575c9402022-10-25 16:21:40 -0400215 >
simon1170c322022-10-31 14:51:31 -0400216 <ListItemIcon>
simon575c9402022-10-25 16:21:40 -0400217 <ContactDetailsIcon style={{ color: iconColor }} />
simon1170c322022-10-31 14:51:31 -0400218 </ListItemIcon>
219 <ListItemText>
220 <Trans i18nKey="conversation_details" />
221 </ListItemText>
222 </MenuItem>
simon575c9402022-10-25 16:21:40 -0400223
simon1170c322022-10-31 14:51:31 -0400224 <MenuItem
simon575c9402022-10-25 16:21:40 -0400225 onClick={() => {
226 setBlockOrRemove(true);
227 closeModal();
228 openModalDelete();
229 }}
simon575c9402022-10-25 16:21:40 -0400230 >
simon1170c322022-10-31 14:51:31 -0400231 <ListItemIcon>
simon575c9402022-10-25 16:21:40 -0400232 <BlockContactIcon style={{ color: iconColor }} />
simon1170c322022-10-31 14:51:31 -0400233 </ListItemIcon>
234 <ListItemText>
235 <Trans i18nKey="conversation_block_contact" />
236 </ListItemText>
237 </MenuItem>
simon575c9402022-10-25 16:21:40 -0400238
simon1170c322022-10-31 14:51:31 -0400239 <MenuItem
simon575c9402022-10-25 16:21:40 -0400240 onClick={() => {
241 setBlockOrRemove(false);
242 closeModal();
243 openModalDelete();
244 }}
simon575c9402022-10-25 16:21:40 -0400245 >
simon1170c322022-10-31 14:51:31 -0400246 <ListItemIcon>
simon575c9402022-10-25 16:21:40 -0400247 <RemoveContactIcon style={{ color: iconColor }} />
simon1170c322022-10-31 14:51:31 -0400248 </ListItemIcon>
249 <ListItemText>
250 <Trans i18nKey="conversation_delete_contact" />
251 </ListItemText>
252 </MenuItem>
253 </Menu>
simon575c9402022-10-25 16:21:40 -0400254 </div>
255
256 <div>
257 <Modal
258 isOpen={modalDetailsIsOpen}
259 onRequestClose={closeModalDetails}
260 style={contactDetailsStyles}
261 contentLabel="Détails contact"
262 >
263 <Stack direction={'row'} alignContent="flex-end">
264 <Stack direction={'column'}>
265 <div style={{ height: '100px' }}>
266 <ConversationAvatar displayName={conversation.getDisplayNameNoFallback()} />
267 </div>
268
269 <div
270 style={{
271 fontSize: '20px',
272 marginBottom: '20px',
273 height: '20px',
274 }}
275 >
276 Informations
277 </div>
278
279 <Typography variant="caption">Nom d&apos;utilisateur</Typography>
280 <div style={{ height: '20px' }} />
281 <Typography variant="caption">Identifiant </Typography>
282 <div style={{ height: '20px' }} />
283
284 <div
285 style={{
286 flex: 1,
287 height: '150px',
288 flexDirection: 'column',
289 // alignSelf: "flex-end",
290 }}
291 >
292 <Typography variant="caption">Code QR</Typography>
293 </div>
294
295 <Typography variant="caption">est un swarm </Typography>
296 </Stack>
297
298 <Stack direction={'column'}>
299 <div
300 style={{
301 fontWeight: 'bold',
302 fontSize: '20px',
303 height: '100px',
304 }}
305 >
306 {conversation.getDisplayNameNoFallback() + '(resolved name)'}
307 </div>
308
309 <div
310 style={{
311 height: '40px',
312 }}
313 />
314 <Typography variant="caption">
315 <div style={{ fontWeight: 'bold' }}>{conversation.getDisplayNameNoFallback()}</div>
316 </Typography>
317
318 <div style={{ height: '20px' }} />
319
320 <Typography variant="caption">
321 <div style={{ fontWeight: 'bold' }}> {userId}</div>
322 </Typography>
323
324 <div style={{ height: '20px' }} />
325
326 <div>
327 <QRCodeCanvas size={40} value={`${userId}`} />
328 </div>
329
330 <Typography variant="caption">
simon1170c322022-10-31 14:51:31 -0400331 <div style={{ fontWeight: 'bold' }}> {String(isSwarm)}</div>
simon575c9402022-10-25 16:21:40 -0400332 </Typography>
333 </Stack>
334 </Stack>
335 <div
336 onClick={closeModalDetails}
337 style={{
338 width: '100px',
339 borderStyle: 'solid',
340 textAlign: 'center',
341 borderRadius: '5px',
342 marginLeft: '150px',
343 marginTop: '10px',
344 }}
345 >
346 <Typography variant="caption">Fermer</Typography>
347 </div>
348 </Modal>
349 </div>
350
351 <div>
352 <Modal
353 isOpen={modalDeleteIsOpen}
354 onRequestClose={closeModalDelete}
355 style={cancelStyles}
356 contentLabel="Merci de confirmer"
357 >
358 <Typography variant="h4">Merci de confirmer</Typography>
359 <Stack direction={'column'} justifyContent="space-around" spacing={'75px'}>
360 <div style={{ textAlign: 'center', marginTop: '10%' }}>
361 <Typography variant="body2">
362 Voulez vous vraiment {blockOrRemove ? 'bloquer' : 'supprimer'} ce contact?
363 </Typography>
364 </div>
365
366 <Stack direction={'row'} top={'25px'} alignSelf="center" spacing={1}>
367 <Box
368 onClick={() => {
369 if (blockOrRemove) removeOrBlock('block');
370 else removeOrBlock('remove');
371 }}
372 style={{
373 width: '100px',
374 textAlign: 'center',
375 borderStyle: 'solid',
376 borderColor: 'red',
377 borderRadius: '10px',
378 color: 'red',
379 }}
380 >
381 {blockOrRemove ? 'Bloquer' : 'Supprimer'}
382 </Box>
383 <Box
384 onClick={closeModalDelete}
385 style={{
386 width: '100px',
387 textAlign: 'center',
388 paddingLeft: '12px',
389 paddingRight: '12px',
390 borderStyle: 'solid',
391 borderRadius: '10px',
392 }}
393 >
394 Annuler
395 </Box>
396 </Stack>
397 </Stack>
398 </Modal>
399 </div>
400
401 <ListItem
402 button
403 alignItems="flex-start"
404 selected={isSelected}
Michelle Sepkap Simeb3dd3122022-11-03 02:12:39 -0400405 onClick={() => navigate(`${navigateUrlPrefix}/${uri}`)}
simon575c9402022-10-25 16:21:40 -0400406 >
407 <ListItemAvatar>
408 <ConversationAvatar displayName={conversation.getDisplayNameNoFallback()} />
409 </ListItemAvatar>
410 <ListItemText primary={conversation.getDisplayName()} secondary={conversation.getDisplayUri()} />
411 </ListItem>
412 </div>
413 );
414}