blob: 02bc99a15dc09537986050a5affe8e109714b528 [file] [log] [blame]
Ziwei Wangfea1d602023-01-09 17:16:01 -05001/*
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 */
18
Ziwei Wangfd1aba22023-01-18 17:31:07 -050019import { ListItem, ListItemAvatar, ListItemText } from '@mui/material';
Ziwei Wangfea1d602023-01-09 17:16:01 -050020import List from '@mui/material/List';
Ziwei Wangfd1aba22023-01-18 17:31:07 -050021import { memo, SetStateAction, useMemo, useState } from 'react';
22import { useTranslation } from 'react-i18next';
Ziwei Wangfea1d602023-01-09 17:16:01 -050023
Ziwei Wang046fb202023-01-17 18:27:17 -050024import {
25 useBlockContactMutation,
26 useContactListQuery,
27 useContactQuery,
28 useRemoveContactMutation,
29} from '../services/contactQueries';
Ziwei Wange8d77032023-01-11 15:57:38 -050030import ContactDetailDialog from './ContactDetailDialog';
Ziwei Wangfd1aba22023-01-18 17:31:07 -050031import ContextMenu, { ContextMenuHandler, useContextMenuHandler } from './ContextMenu';
Ziwei Wangfea1d602023-01-09 17:16:01 -050032import ConversationAvatar from './ConversationAvatar';
Ziwei Wangfd1aba22023-01-18 17:31:07 -050033import { ConfirmationDialog, useDialogHandler } from './Dialog';
Ziwei Wang046fb202023-01-17 18:27:17 -050034import LoadingPage from './Loading';
Ziwei Wangfd1aba22023-01-18 17:31:07 -050035import { PopoverListItemData } from './PopoverList';
36import { BlockContactIcon, CancelIcon, PersonIcon } from './SvgIcon';
Ziwei Wangfea1d602023-01-09 17:16:01 -050037
38export default function ContactList() {
Ziwei Wangfea1d602023-01-09 17:16:01 -050039 const [currentContactId, setCurrentContactId] = useState<string>('');
Ziwei Wangfea1d602023-01-09 17:16:01 -050040 const [isBlocking, setIsBlocking] = useState(true);
Ziwei Wang046fb202023-01-17 18:27:17 -050041
Ziwei Wange8d77032023-01-11 15:57:38 -050042 const [contactDetailDialogOpen, setContactDetailDialogOpen] = useState<boolean>(false);
43
Ziwei Wang046fb202023-01-17 18:27:17 -050044 const contactListQuery = useContactListQuery();
45 const { isLoading, data: contacts } = contactListQuery;
46
Ziwei Wang046fb202023-01-17 18:27:17 -050047 const singleContactQuery = useContactQuery(currentContactId);
48 const { data: contactDetail } = singleContactQuery;
49
Ziwei Wangfd1aba22023-01-18 17:31:07 -050050 const contextMenuHandler = useContextMenuHandler();
Ziwei Wangfea1d602023-01-09 17:16:01 -050051
Ziwei Wangfd1aba22023-01-18 17:31:07 -050052 const {
53 props: { open: dialogOpen, onClose: closeContactDialog },
54 openDialog: openContactDialog,
55 } = useDialogHandler();
Ziwei Wangfea1d602023-01-09 17:16:01 -050056
Ziwei Wange8d77032023-01-11 15:57:38 -050057 const ContactDetailDialogElement = useMemo(() => {
58 const onClosingContactDetailDialog = () => setContactDetailDialogOpen(false);
Ziwei Wange8d77032023-01-11 15:57:38 -050059 return (
60 <ContactDetailDialog
61 contactDetail={contactDetail}
62 open={contactDetailDialogOpen}
63 onClose={onClosingContactDetailDialog}
64 />
65 );
66 }, [contactDetail, contactDetailDialogOpen]);
67
Ziwei Wang046fb202023-01-17 18:27:17 -050068 if (isLoading) {
69 return <LoadingPage />;
70 }
Ziwei Wangfd1aba22023-01-18 17:31:07 -050071
Ziwei Wangfea1d602023-01-09 17:16:01 -050072 return (
73 <>
Ziwei Wangfd1aba22023-01-18 17:31:07 -050074 <ContactDialog
75 isBlocking={isBlocking}
76 open={dialogOpen}
77 closeContactDialog={closeContactDialog}
78 currentContactId={currentContactId}
79 />
Ziwei Wange8d77032023-01-11 15:57:38 -050080 {ContactDetailDialogElement}
81
Ziwei Wangfd1aba22023-01-18 17:31:07 -050082 <ContactMenu
83 contextMenuProps={contextMenuHandler.props}
84 openContactDialog={openContactDialog}
85 setIsBlocking={setIsBlocking}
86 setContactDetailDialogOpen={setContactDetailDialogOpen}
87 />
88
Ziwei Wangfea1d602023-01-09 17:16:01 -050089 <List>
90 {contacts?.map((contact) => (
Ziwei Wangfd1aba22023-01-18 17:31:07 -050091 <ListItem
92 alignItems="flex-start"
93 key={contact.id}
94 onContextMenu={(e) => {
95 setCurrentContactId(contact.id);
96 contextMenuHandler.handleAnchorPosition(e);
97 }}
98 >
Ziwei Wangfea1d602023-01-09 17:16:01 -050099 <ListItemAvatar>
Ziwei Wang727dbbb2023-01-10 13:59:50 -0500100 <ConversationAvatar />
Ziwei Wangfea1d602023-01-09 17:16:01 -0500101 </ListItemAvatar>
102 <ListItemText primary={contact.id} secondary={contact.id} />
103 </ListItem>
104 ))}
105 </List>
106 </>
107 );
108}
Ziwei Wangfd1aba22023-01-18 17:31:07 -0500109
110interface ContactMenuProps {
111 contextMenuProps: ContextMenuHandler['props'];
112 openContactDialog: () => void;
113 setIsBlocking: React.Dispatch<SetStateAction<boolean>>;
114 setContactDetailDialogOpen: React.Dispatch<SetStateAction<boolean>>;
115}
116
117const ContactMenu = ({
118 contextMenuProps,
119 openContactDialog,
120 setIsBlocking,
121 setContactDetailDialogOpen,
122}: ContactMenuProps) => {
123 const { t } = useTranslation();
124 const menuOptions: PopoverListItemData[] = useMemo(
125 () => [
126 {
127 label: t('contact_details_text'),
128 Icon: PersonIcon,
129 onClick: () => {
130 setContactDetailDialogOpen(true);
131 },
132 },
133 {
134 label: t('contact_block'),
135 Icon: BlockContactIcon,
136 onClick: () => {
137 openContactDialog();
138 setIsBlocking(true);
139 },
140 },
141 {
142 label: t('contact_remove'),
143 Icon: CancelIcon,
144 onClick: () => {
145 openContactDialog();
146 setIsBlocking(false);
147 },
148 },
149 ],
150 [t, setIsBlocking, setContactDetailDialogOpen, openContactDialog]
151 );
152 return <ContextMenu {...contextMenuProps} items={menuOptions} />;
153};
154
155interface ContactDialogProps {
156 isBlocking: boolean;
157 open: boolean;
158 closeContactDialog: () => void;
159 currentContactId: string;
160}
161
162const ContactDialog = memo(({ isBlocking, open, closeContactDialog, currentContactId }: ContactDialogProps) => {
163 const removeContactMutation = useRemoveContactMutation();
164 const blockContactMutation = useBlockContactMutation();
165
166 const removeContact = (): void => {
167 removeContactMutation.mutate(currentContactId);
168 closeContactDialog();
169 };
170
171 const blockContact = (): void => {
172 blockContactMutation.mutate(currentContactId);
173 closeContactDialog();
174 };
175
176 const { t } = useTranslation();
177 return (
178 <ConfirmationDialog
179 open={open}
180 onClose={closeContactDialog}
181 title={t('dialog_confirm_title_default')}
182 content={isBlocking ? t('contact_ask_confirm_block') : t('contact_ask_confirm_remove')}
183 onConfirm={isBlocking ? blockContact : removeContact}
184 confirmButtonText={isBlocking ? t('contact_confirm_block') : t('contact_confirm_remove')}
185 />
186 );
187});