Remove payments API routing initialization
[ProtonMail-WebClient.git] / packages / components / containers / contacts / view / ContactDetailsModal.tsx
blob39d18239e7511e1fcfc13787daaa62dc0e52e5c4
1 import { useEffect, useMemo, useRef } from 'react';
3 import { c } from 'ttag';
5 import { useAddresses } from '@proton/account/addresses/hooks';
6 import { useUserKeys } from '@proton/account/userKeys/hooks';
7 import { Button } from '@proton/atoms';
8 import Icon from '@proton/components/components/icon/Icon';
9 import Loader from '@proton/components/components/loader/Loader';
10 import type { ModalProps } from '@proton/components/components/modalTwo/Modal';
11 import ModalTwo from '@proton/components/components/modalTwo/Modal';
12 import ModalTwoContent from '@proton/components/components/modalTwo/ModalContent';
13 import ModalTwoFooter from '@proton/components/components/modalTwo/ModalFooter';
14 import ModalTwoHeader from '@proton/components/components/modalTwo/ModalHeader';
15 import Tooltip from '@proton/components/components/tooltip/Tooltip';
16 import useConfig from '@proton/components/hooks/useConfig';
17 import useNotifications from '@proton/components/hooks/useNotifications';
18 import { useContactGroups } from '@proton/mail';
19 import { useContact } from '@proton/mail/contacts/contactHooks';
20 import { useMailSettings } from '@proton/mail/mailSettings/hooks';
21 import { APPS } from '@proton/shared/lib/constants';
22 import { CRYPTO_PROCESSING_TYPES } from '@proton/shared/lib/contacts/constants';
23 import { singleExport } from '@proton/shared/lib/contacts/helpers/export';
24 import { textToClipboard } from '@proton/shared/lib/helpers/browser';
25 import { toMap } from '@proton/shared/lib/helpers/object';
26 import type { ContactEmail } from '@proton/shared/lib/interfaces/contacts';
27 import type { VCardContact } from '@proton/shared/lib/interfaces/contacts/VCard';
29 import { useLinkHandler } from '../../../hooks/useLinkHandler';
30 import ErrorBoundary from '../../app/ErrorBoundary';
31 import GenericError from '../../error/GenericError';
32 import type { ContactEditProps } from '../edit/ContactEditModal';
33 import type { ContactEmailSettingsProps } from '../email/ContactEmailSettingsModal';
34 import type { ContactGroupEditProps } from '../group/ContactGroupEditModal';
35 import useContactList from '../hooks/useContactList';
36 import useVCardContact from '../hooks/useVCardContact';
37 import type { ContactDeleteProps } from '../modals/ContactDeleteModal';
38 import ContactView from './ContactView';
40 export interface ContactDetailsProps {
41     contactID: string;
42     onMailTo?: (src: string) => void;
43     onEdit: (props: ContactEditProps) => void;
44     onDelete: (props: ContactDeleteProps) => void;
45     onEmailSettings: (props: ContactEmailSettingsProps) => void;
46     onGroupDetails: (contactGroupID: string) => void;
47     onGroupEdit: (props: ContactGroupEditProps) => void;
48     onUpgrade: () => void;
49     onSignatureError: (contactID: string) => void;
50     onDecryptionError: (contactID: string) => void;
53 type Props = ContactDetailsProps & ModalProps;
55 const ContactDetailsModal = ({
56     contactID,
57     onMailTo,
58     onEdit,
59     onDelete,
60     onEmailSettings,
61     onGroupDetails,
62     onGroupEdit,
63     onUpgrade,
64     onSignatureError,
65     onDecryptionError,
66     ...rest
67 }: Props) => {
68     const { onClose } = rest;
70     const [mailSettings] = useMailSettings();
71     const [contactGroups = [], loadingContactGroups] = useContactGroups();
72     const [userKeysList, loadingUserKeys] = useUserKeys();
73     const [addresses = [], loadingAddresses] = useAddresses();
74     const { loading: loadingContacts, contactEmailsMap } = useContactList({});
75     const [contact, loadingContact] = useContact(contactID);
76     const modalRef = useRef<HTMLDivElement>(null);
77     const { createNotification } = useNotifications();
79     const { APP_NAME } = useConfig();
81     const { modal: linkModal } = useLinkHandler(modalRef, mailSettings, { onMailTo });
83     const {
84         vCardContact,
85         isLoading: loadingVCard,
86         errors,
87         isVerified,
88         onReload,
89     } = useVCardContact({ contact, userKeysList });
91     // Close the modal on a click on a mailto, useLinkHandler will open the composer
92     useEffect(() => {
93         const handleClick = (event: MouseEvent) => {
94             const link = (event.target as Element).closest('a');
95             const src = link?.getAttribute('href');
96             if (src?.startsWith('mailto:')) {
97                 if (APP_NAME === APPS.PROTONMAIL) {
98                     onClose?.();
99                 } else {
100                     textToClipboard(src?.replace('mailto:', ''));
101                     createNotification({
102                         text: c('Success').t`Email address copied to clipboard`,
103                     });
104                 }
105             }
106         };
108         modalRef.current?.addEventListener('click', handleClick);
109         return () => modalRef.current?.removeEventListener('click', handleClick);
110     }, []);
112     const handleEdit = (newField?: string) => {
113         onEdit({ contactID, vCardContact, newField });
114     };
116     const handleDelete = () => {
117         onDelete({ contactIDs: [contactID] });
118         onClose?.();
119     };
121     const handleExport = () => {
122         const hasError = errors?.some(
123             (error) => error instanceof Error || error.type !== CRYPTO_PROCESSING_TYPES.SIGNATURE_NOT_VERIFIED
124         );
126         if (hasError) {
127             createNotification({ text: c('Error').t`Cannot export this contact`, type: 'error' });
128             return;
129         }
131         return singleExport(vCardContact as VCardContact);
132     };
134     const ownAddresses = useMemo(() => addresses.map(({ Email }) => Email), [addresses]);
135     const contactGroupsMap = useMemo(() => toMap(contactGroups), [contactGroups]);
137     const isLoading =
138         loadingContacts ||
139         loadingContactGroups ||
140         loadingUserKeys ||
141         loadingAddresses ||
142         loadingContact ||
143         loadingVCard;
145     return (
146         <ModalTwo size="large" className="contacts-modal" data-testid="contact-details-modal" {...rest}>
147             <ModalTwoHeader
148                 actions={[
149                     <Tooltip title={c('Action').t`Edit`}>
150                         <Button
151                             color="weak"
152                             shape="ghost"
153                             icon
154                             onClick={() => handleEdit()}
155                             className="inline-flex ml-2"
156                             data-testid="contact-details:edit"
157                         >
158                             <Icon name="pen" alt={c('Action').t`Edit`} />
159                         </Button>
160                     </Tooltip>,
161                     <Tooltip title={c('Action').t`Export`}>
162                         <Button
163                             color="weak"
164                             shape="ghost"
165                             icon
166                             onClick={handleExport}
167                             className="inline-flex ml-2"
168                             data-testid="contact-details:export"
169                         >
170                             <Icon name="arrow-up-from-square" alt={c('Action').t`Export`} />
171                         </Button>
172                     </Tooltip>,
173                     <Tooltip title={c('Action').t`Delete`}>
174                         <Button
175                             color="weak"
176                             shape="ghost"
177                             icon
178                             onClick={handleDelete}
179                             className="inline-flex ml-2"
180                             data-testid="contact-details:delete"
181                         >
182                             <Icon name="trash" alt={c('Action').t`Delete`} />
183                         </Button>
184                     </Tooltip>,
185                 ]}
186             />
187             <ModalTwoContent>
188                 <ErrorBoundary key={contactID} component={<GenericError className="pt-7 view-column-detail flex-1" />}>
189                     <div ref={modalRef}>
190                         {isLoading ? (
191                             <Loader />
192                         ) : (
193                             <ContactView
194                                 vCardContact={vCardContact as VCardContact}
195                                 contactID={contactID}
196                                 contactEmails={contactEmailsMap[contactID] as ContactEmail[]}
197                                 contactGroupsMap={contactGroupsMap}
198                                 ownAddresses={ownAddresses}
199                                 errors={errors}
200                                 isSignatureVerified={isVerified}
201                                 onReload={onReload}
202                                 onEdit={handleEdit}
203                                 onEmailSettings={onEmailSettings}
204                                 onGroupDetails={onGroupDetails}
205                                 onGroupEdit={onGroupEdit}
206                                 onUpgrade={onUpgrade}
207                                 onSignatureError={onSignatureError}
208                                 onDecryptionError={onDecryptionError}
209                             />
210                         )}
211                     </div>
212                     {linkModal}
213                 </ErrorBoundary>
214             </ModalTwoContent>
215             <ModalTwoFooter>
216                 <Button onClick={onClose}>{c('Action').t`Close`}</Button>
217             </ModalTwoFooter>
218         </ModalTwo>
219     );
222 export default ContactDetailsModal;