blob: bab36b0b9ba2e199e531cc205519cac245564a7d [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 */
18import { Box, ListItem, ListItemAvatar, ListItemText, Stack, StackProps, Typography } from '@mui/material';
19import { Conversation } from 'jami-web-common';
20import { QRCodeCanvas } from 'qrcode.react';
21import { MouseEvent, useState } from 'react';
22import Modal from 'react-modal';
23import { useNavigate, useParams } from 'react-router-dom';
24
25import authManager from '../AuthManager';
26import { setRefreshFromSlice } from '../redux/appSlice';
27import { useAppDispatch } from '../redux/hooks';
28import ConversationAvatar from './ConversationAvatar';
29import { RemoveContactIcon, VideoCallIcon } from './SvgIcon';
30import { AudioCallIcon, BlockContactIcon, ContactDetailsIcon, CrossIcon, MessageIcon } from './SvgIcon';
31
32const customStyles: Modal.Styles = {
33 content: {
34 // right: "auto",
35 // bottom: "auto",
36 // // marginRight: "-50%",
37 // transform: "translate(-50%, -50%)",
38 // padding: "16px"
39
40 // top: "1364px",
41 left: '94px',
42 width: '180px',
43 height: '262px',
44 background: '#FFFFFF 0% 0% no-repeat padding-box',
45 boxShadow: '3px 3px 7px #00000029',
46 borderRadius: '5px 20px 20px 20px',
47 opacity: '1',
48
49 textAlign: 'left',
50 font: 'normal normal normal 12px/26px Ubuntu',
51 letterSpacing: '0px',
52 color: '#000000',
53 },
54};
55
56const cancelStyles: Modal.Styles = {
57 content: {
58 left: '94px',
59 width: '300px',
60 height: '220px',
61 background: '#FFFFFF 0% 0% no-repeat padding-box',
62 boxShadow: '3px 3px 7px #00000029',
63 borderRadius: '20px',
64 opacity: '1',
65
66 textAlign: 'left',
67 font: 'normal normal normal 12px/26px Ubuntu',
68 letterSpacing: '0px',
69 color: '#000000',
70 },
71};
72
73const contactDetailsStyles: Modal.Styles = {
74 content: {
75 left: '94px',
76 width: '450px',
77 height: '450px',
78 background: '#FFFFFF 0% 0% no-repeat padding-box',
79 boxShadow: '3px 3px 7px #00000029',
80 borderRadius: '20px',
81 opacity: '1',
82
83 textAlign: 'left',
84 font: 'normal normal normal 12px/26px Ubuntu',
85 letterSpacing: '0px',
86 color: '#000000',
87 },
88};
89
90const stackStyles: StackProps = {
91 flexDirection: 'row',
92 marginBottom: '4px',
93 spacing: '40px',
94 flex: 1,
95 alignItems: 'center',
96};
97
98const iconTextStyle = {
99 marginRight: '10px',
100};
101
102const iconColor = '#005699';
103
104type ConversationListItemProps = {
105 conversation: Conversation;
106};
107
108export default function ConversationListItem({ conversation }: ConversationListItemProps) {
109 const { conversationId, contactId } = useParams();
110 const dispatch = useAppDispatch();
111
112 const pathId = conversationId || contactId;
113 const isSelected = conversation.getDisplayUri() === pathId;
114 const navigate = useNavigate();
115
116 const [modalIsOpen, setIsOpen] = useState(false);
117 const [modalDetailsIsOpen, setModalDetailsIsOpen] = useState(false);
118 const [modalDeleteIsOpen, setModalDeleteIsOpen] = useState(false);
119 const [blockOrRemove, setBlockOrRemove] = useState(true);
120 const [userId, setUserId] = useState(conversation?.getFirstMember()?.contact.getUri());
121 const [isSwarm, setIsSwarm] = useState('true');
122
123 const openModal = (e: MouseEvent<HTMLDivElement>) => {
124 e.preventDefault();
125 console.log(e);
126 setIsOpen(true);
127 };
128 const openModalDetails = () => setModalDetailsIsOpen(true);
129 const openModalDelete = () => setModalDeleteIsOpen(true);
130 const closeModal = () => setIsOpen(false);
131 const closeModalDetails = () => setModalDetailsIsOpen(false);
132 const closeModalDelete = () => setModalDeleteIsOpen(false);
133
134 const getContactDetails = () => {
135 const controller = new AbortController();
136 authManager
137 .fetch(`/api/accounts/${conversation.getAccountId()}/contacts/details/${userId}`, {
138 signal: controller.signal,
139 })
140 .then((res) => res.json())
141 .then((result) => {
142 console.log('CONTACT LIST - DETAILS: ', result);
143 })
144 .catch((e) => console.log('ERROR GET CONTACT DETAILS: ', e));
145 };
146
147 const removeOrBlock = (typeOfRemove: 'block' | 'remove') => {
148 console.log(typeOfRemove);
149 setBlockOrRemove(false);
150
151 console.log('EEEH', typeOfRemove, conversation.getAccountId(), userId);
152
153 const controller = new AbortController();
154 authManager
155 .fetch(`/api/accounts/${conversation.getAccountId()}/contacts/${typeOfRemove}/${userId}`, {
156 signal: controller.signal,
157 method: 'DELETE',
158 })
159 .then((res) => res.json())
160 .then((result) => {
161 console.log('propre');
162 dispatch(setRefreshFromSlice());
163 })
164 .catch((e) => {
165 console.log(`ERROR ${typeOfRemove}ing CONTACT : `, e);
166 dispatch(setRefreshFromSlice());
167 });
168 closeModalDelete();
169 };
170
171 const uri = conversation.getId() ? `conversation/${conversation.getId()}` : `addContact/${userId}`;
172 return (
173 <div onContextMenu={openModal}>
174 <div>
175 <Modal
176 isOpen={modalIsOpen}
177 // onAfterOpen={afterOpenModal}
178 onRequestClose={closeModal}
179 style={customStyles}
180 contentLabel="Example Modal"
181 >
182 <Stack
183 onClick={() => {
184 navigate(`/account/${conversation.getAccountId()}/${uri}`);
185 closeModal();
186 }}
187 {...stackStyles}
188 >
189 <div style={{ ...iconTextStyle }}>
190 <MessageIcon style={{ color: iconColor }} />
191 </div>
192 Message
193 </Stack>
194 <Stack {...stackStyles}>
195 <div style={{ ...iconTextStyle }}>
196 <AudioCallIcon style={{ color: iconColor }} />
197 </div>
198 Démarrer appel audio
199 </Stack>
200
201 <Stack {...stackStyles}>
202 <div style={{ ...iconTextStyle }}>
203 <VideoCallIcon style={{ color: iconColor }} />
204 </div>
205 Démarrer appel vidéo
206 </Stack>
207
208 <Stack
209 {...stackStyles}
210 onClick={() => {
211 navigate(`/account/${conversation.getAccountId()}/`);
212 closeModal();
213 }}
214 >
215 <div style={{ ...iconTextStyle }}>
216 <CrossIcon style={{ color: iconColor }} />
217 </div>
218 Fermer la conversation
219 </Stack>
220
221 <Stack
222 onClick={() => {
223 console.log('open details contact for: ');
224 closeModal();
225 openModalDetails();
226 getContactDetails();
227 }}
228 {...stackStyles}
229 >
230 <div style={{ ...iconTextStyle }}>
231 <ContactDetailsIcon style={{ color: iconColor }} />
232 </div>
233 Détails de la conversation
234 </Stack>
235
236 <Stack
237 onClick={() => {
238 setBlockOrRemove(true);
239 closeModal();
240 openModalDelete();
241 }}
242 {...stackStyles}
243 >
244 <div style={{ ...iconTextStyle }}>
245 <BlockContactIcon style={{ color: iconColor }} />
246 </div>
247 Bloquer le contact
248 </Stack>
249
250 <Stack
251 onClick={() => {
252 setBlockOrRemove(false);
253 closeModal();
254 openModalDelete();
255 }}
256 {...stackStyles}
257 >
258 <div style={{ ...iconTextStyle }}>
259 <RemoveContactIcon style={{ color: iconColor }} />
260 </div>
261 Supprimer contact
262 </Stack>
263 </Modal>
264 </div>
265
266 <div>
267 <Modal
268 isOpen={modalDetailsIsOpen}
269 onRequestClose={closeModalDetails}
270 style={contactDetailsStyles}
271 contentLabel="Détails contact"
272 >
273 <Stack direction={'row'} alignContent="flex-end">
274 <Stack direction={'column'}>
275 <div style={{ height: '100px' }}>
276 <ConversationAvatar displayName={conversation.getDisplayNameNoFallback()} />
277 </div>
278
279 <div
280 style={{
281 fontSize: '20px',
282 marginBottom: '20px',
283 height: '20px',
284 }}
285 >
286 Informations
287 </div>
288
289 <Typography variant="caption">Nom d&apos;utilisateur</Typography>
290 <div style={{ height: '20px' }} />
291 <Typography variant="caption">Identifiant </Typography>
292 <div style={{ height: '20px' }} />
293
294 <div
295 style={{
296 flex: 1,
297 height: '150px',
298 flexDirection: 'column',
299 // alignSelf: "flex-end",
300 }}
301 >
302 <Typography variant="caption">Code QR</Typography>
303 </div>
304
305 <Typography variant="caption">est un swarm </Typography>
306 </Stack>
307
308 <Stack direction={'column'}>
309 <div
310 style={{
311 fontWeight: 'bold',
312 fontSize: '20px',
313 height: '100px',
314 }}
315 >
316 {conversation.getDisplayNameNoFallback() + '(resolved name)'}
317 </div>
318
319 <div
320 style={{
321 height: '40px',
322 }}
323 />
324 <Typography variant="caption">
325 <div style={{ fontWeight: 'bold' }}>{conversation.getDisplayNameNoFallback()}</div>
326 </Typography>
327
328 <div style={{ height: '20px' }} />
329
330 <Typography variant="caption">
331 <div style={{ fontWeight: 'bold' }}> {userId}</div>
332 </Typography>
333
334 <div style={{ height: '20px' }} />
335
336 <div>
337 <QRCodeCanvas size={40} value={`${userId}`} />
338 </div>
339
340 <Typography variant="caption">
341 <div style={{ fontWeight: 'bold' }}> {isSwarm}</div>
342 </Typography>
343 </Stack>
344 </Stack>
345 <div
346 onClick={closeModalDetails}
347 style={{
348 width: '100px',
349 borderStyle: 'solid',
350 textAlign: 'center',
351 borderRadius: '5px',
352 marginLeft: '150px',
353 marginTop: '10px',
354 }}
355 >
356 <Typography variant="caption">Fermer</Typography>
357 </div>
358 </Modal>
359 </div>
360
361 <div>
362 <Modal
363 isOpen={modalDeleteIsOpen}
364 onRequestClose={closeModalDelete}
365 style={cancelStyles}
366 contentLabel="Merci de confirmer"
367 >
368 <Typography variant="h4">Merci de confirmer</Typography>
369 <Stack direction={'column'} justifyContent="space-around" spacing={'75px'}>
370 <div style={{ textAlign: 'center', marginTop: '10%' }}>
371 <Typography variant="body2">
372 Voulez vous vraiment {blockOrRemove ? 'bloquer' : 'supprimer'} ce contact?
373 </Typography>
374 </div>
375
376 <Stack direction={'row'} top={'25px'} alignSelf="center" spacing={1}>
377 <Box
378 onClick={() => {
379 if (blockOrRemove) removeOrBlock('block');
380 else removeOrBlock('remove');
381 }}
382 style={{
383 width: '100px',
384 textAlign: 'center',
385 borderStyle: 'solid',
386 borderColor: 'red',
387 borderRadius: '10px',
388 color: 'red',
389 }}
390 >
391 {blockOrRemove ? 'Bloquer' : 'Supprimer'}
392 </Box>
393 <Box
394 onClick={closeModalDelete}
395 style={{
396 width: '100px',
397 textAlign: 'center',
398 paddingLeft: '12px',
399 paddingRight: '12px',
400 borderStyle: 'solid',
401 borderRadius: '10px',
402 }}
403 >
404 Annuler
405 </Box>
406 </Stack>
407 </Stack>
408 </Modal>
409 </div>
410
411 <ListItem
412 button
413 alignItems="flex-start"
414 selected={isSelected}
415 onClick={() => navigate(`/account/${conversation.getAccountId()}/${uri}`)}
416 >
417 <ListItemAvatar>
418 <ConversationAvatar displayName={conversation.getDisplayNameNoFallback()} />
419 </ListItemAvatar>
420 <ListItemText primary={conversation.getDisplayName()} secondary={conversation.getDisplayUri()} />
421 </ListItem>
422 </div>
423 );
424}