| /* |
| * 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 { ListItem, ListItemAvatar, ListItemText } from '@mui/material'; |
| import List from '@mui/material/List'; |
| import { memo, SetStateAction, useMemo, useState } from 'react'; |
| import { useTranslation } from 'react-i18next'; |
| |
| import { |
| useBlockContactMutation, |
| useContactListQuery, |
| useContactQuery, |
| useRemoveContactMutation, |
| } from '../services/contactQueries'; |
| import ContactDetailDialog from './ContactDetailDialog'; |
| import ContextMenu, { ContextMenuHandler, useContextMenuHandler } from './ContextMenu'; |
| import ConversationAvatar from './ConversationAvatar'; |
| import { ConfirmationDialog, useDialogHandler } from './Dialog'; |
| import LoadingPage from './Loading'; |
| import { PopoverListItemData } from './PopoverList'; |
| import { BlockContactIcon, CancelIcon, PersonIcon } from './SvgIcon'; |
| |
| export default function ContactList() { |
| const [currentContactId, setCurrentContactId] = useState<string>(''); |
| const [isBlocking, setIsBlocking] = useState(true); |
| |
| const [contactDetailDialogOpen, setContactDetailDialogOpen] = useState<boolean>(false); |
| |
| const contactListQuery = useContactListQuery(); |
| const { isLoading, data: contacts } = contactListQuery; |
| |
| const singleContactQuery = useContactQuery(currentContactId); |
| const { data: contactDetail } = singleContactQuery; |
| |
| const contextMenuHandler = useContextMenuHandler(); |
| |
| const { |
| props: { open: dialogOpen, onClose: closeContactDialog }, |
| openDialog: openContactDialog, |
| } = useDialogHandler(); |
| |
| const ContactDetailDialogElement = useMemo(() => { |
| const onClosingContactDetailDialog = () => setContactDetailDialogOpen(false); |
| return ( |
| <ContactDetailDialog |
| contactDetail={contactDetail} |
| open={contactDetailDialogOpen} |
| onClose={onClosingContactDetailDialog} |
| /> |
| ); |
| }, [contactDetail, contactDetailDialogOpen]); |
| |
| if (isLoading) { |
| return <LoadingPage />; |
| } |
| |
| return ( |
| <> |
| <ContactDialog |
| isBlocking={isBlocking} |
| open={dialogOpen} |
| closeContactDialog={closeContactDialog} |
| currentContactId={currentContactId} |
| /> |
| {ContactDetailDialogElement} |
| |
| <ContactMenu |
| contextMenuProps={contextMenuHandler.props} |
| openContactDialog={openContactDialog} |
| setIsBlocking={setIsBlocking} |
| setContactDetailDialogOpen={setContactDetailDialogOpen} |
| /> |
| |
| <List> |
| {contacts?.map((contact) => ( |
| <ListItem |
| alignItems="flex-start" |
| key={contact.id} |
| onContextMenu={(e) => { |
| setCurrentContactId(contact.id); |
| contextMenuHandler.handleAnchorPosition(e); |
| }} |
| > |
| <ListItemAvatar> |
| <ConversationAvatar /> |
| </ListItemAvatar> |
| <ListItemText primary={contact.id} secondary={contact.id} /> |
| </ListItem> |
| ))} |
| </List> |
| </> |
| ); |
| } |
| |
| interface ContactMenuProps { |
| contextMenuProps: ContextMenuHandler['props']; |
| openContactDialog: () => void; |
| setIsBlocking: React.Dispatch<SetStateAction<boolean>>; |
| setContactDetailDialogOpen: React.Dispatch<SetStateAction<boolean>>; |
| } |
| |
| const ContactMenu = ({ |
| contextMenuProps, |
| openContactDialog, |
| setIsBlocking, |
| setContactDetailDialogOpen, |
| }: ContactMenuProps) => { |
| const { t } = useTranslation(); |
| const menuOptions: PopoverListItemData[] = useMemo( |
| () => [ |
| { |
| label: t('contact_details_text'), |
| Icon: PersonIcon, |
| onClick: () => { |
| setContactDetailDialogOpen(true); |
| }, |
| }, |
| { |
| label: t('contact_block'), |
| Icon: BlockContactIcon, |
| onClick: () => { |
| openContactDialog(); |
| setIsBlocking(true); |
| }, |
| }, |
| { |
| label: t('contact_remove'), |
| Icon: CancelIcon, |
| onClick: () => { |
| openContactDialog(); |
| setIsBlocking(false); |
| }, |
| }, |
| ], |
| [t, setIsBlocking, setContactDetailDialogOpen, openContactDialog] |
| ); |
| return <ContextMenu {...contextMenuProps} items={menuOptions} />; |
| }; |
| |
| interface ContactDialogProps { |
| isBlocking: boolean; |
| open: boolean; |
| closeContactDialog: () => void; |
| currentContactId: string; |
| } |
| |
| const ContactDialog = memo(({ isBlocking, open, closeContactDialog, currentContactId }: ContactDialogProps) => { |
| const removeContactMutation = useRemoveContactMutation(); |
| const blockContactMutation = useBlockContactMutation(); |
| |
| const removeContact = (): void => { |
| removeContactMutation.mutate(currentContactId); |
| closeContactDialog(); |
| }; |
| |
| const blockContact = (): void => { |
| blockContactMutation.mutate(currentContactId); |
| closeContactDialog(); |
| }; |
| |
| const { t } = useTranslation(); |
| return ( |
| <ConfirmationDialog |
| open={open} |
| onClose={closeContactDialog} |
| title={t('dialog_confirm_title_default')} |
| content={isBlocking ? t('contact_ask_confirm_block') : t('contact_ask_confirm_remove')} |
| onConfirm={isBlocking ? blockContact : removeContact} |
| confirmButtonText={isBlocking ? t('contact_confirm_block') : t('contact_confirm_remove')} |
| /> |
| ); |
| }); |