Remove payments API routing initialization
[ProtonMail-WebClient.git] / packages / components / containers / contacts / merge / ContactMergeModal.tsx
blob3dbce98b34833ceded700511cdf1b5d8dc790880
1 import { useEffect, useMemo, useState } from 'react';
3 import type { ModalProps } from '@proton/components/components/modalTwo/Modal';
4 import ModalTwo from '@proton/components/components/modalTwo/Modal';
5 import useEventManager from '@proton/components/hooks/useEventManager';
6 import type { ContactFormatted, ContactMergeModel } from '@proton/shared/lib/interfaces/contacts';
8 import type { ContactMergePreviewModalProps } from './ContactMergePreviewModal';
9 import ContactMergeTableContent from './ContactMergeTableContent';
10 import ContactMergingContent from './ContactMergingContent';
12 export interface ContactMergeProps {
13     contacts: ContactFormatted[][];
14     onMerged: () => void;
17 export interface ContactMergeModalProps {
18     onMergeDetails: (contactID: string) => void;
19     onMergePreview: (props: ContactMergePreviewModalProps) => void;
22 type Props = ContactMergeProps & ContactMergeModalProps & ModalProps;
24 const ContactMergeModal = ({ contacts, onMerged, onMergeDetails, onMergePreview, ...rest }: Props) => {
25     const { call } = useEventManager();
27     const [isMerging, setIsMerging] = useState(false);
28     const [mergeFinished, setMergeFinished] = useState(false);
29     const [model, setModel] = useState<ContactMergeModel>(() => ({
30         orderedContacts: contacts,
31         isChecked: contacts.flat().reduce<{ [ID: string]: boolean }>((acc, { ID }) => {
32             acc[ID] = true;
33             return acc;
34         }, {}),
35         beDeleted: contacts.flat().reduce<{ [ID: string]: boolean }>((acc, { ID }) => {
36             acc[ID] = false;
37             return acc;
38         }, {}),
39     }));
41     const { orderedContacts, isChecked, beDeleted } = model;
43     useEffect(() => {
44         // close the modal if all contacts have been merged from preview
45         if (!orderedContacts.flat().length) {
46             onMerged?.();
47             rest.onClose?.();
48         }
49     }, [orderedContacts]);
51     // beMergedModel = { 'ID of be-merged contact': [IDs to be merged] }
52     // beDeletedModel = { 'ID of be-deleted contact': 'ID to navigate to in case it is the current ID' }
53     const { beMergedModel, beDeletedModel, totalBeMerged, totalBeDeleted } = useMemo(
54         () =>
55             orderedContacts.reduce<{
56                 beMergedModel: { [ID: string]: string[] };
57                 beDeletedModel: { [ID: string]: string };
58                 totalBeMerged: number;
59                 totalBeDeleted: number;
60             }>(
61                 (acc, group) => {
62                     const groupIDs = group.map(({ ID }) => ID);
63                     const beMergedIDs = groupIDs
64                         .map((ID) => isChecked[ID] && !beDeleted[ID] && ID)
65                         .filter(Boolean) as string[];
66                     const beDeletedIDs = groupIDs.map((ID) => beDeleted[ID] && ID).filter(Boolean) as string[];
67                     const willBeMerged = beMergedIDs.length > 1;
69                     if (willBeMerged) {
70                         acc.beMergedModel[beMergedIDs[0]] = beMergedIDs;
71                         acc.totalBeMerged += beMergedIDs.length;
72                     }
73                     for (const ID of beDeletedIDs) {
74                         // route to merged contact or to /contacts if no associated contact is merged
75                         acc.beDeletedModel[ID] = willBeMerged ? beMergedIDs[0] : '';
76                         acc.totalBeDeleted += 1;
77                     }
78                     return acc;
79                 },
80                 { beMergedModel: {}, beDeletedModel: {}, totalBeMerged: 0, totalBeDeleted: 0 }
81             ),
82         [orderedContacts, isChecked, beDeleted]
83     );
85     const handleStartMerge = () => {
86         setIsMerging(true);
87     };
89     const handleMergingFinish = async () => {
90         await call();
91         setMergeFinished(true);
92     };
94     const handleMerged = () => {
95         onMerged?.();
96         rest.onClose?.();
97     };
99     return (
100         <ModalTwo size="large" className="contacts-modal" {...rest}>
101             {isMerging ? (
102                 <ContactMergingContent
103                     mergeFinished={mergeFinished}
104                     onFinish={handleMergingFinish}
105                     onMerged={handleMerged}
106                     onClose={rest.onClose}
107                     beMergedModel={beMergedModel}
108                     beDeletedModel={beDeletedModel}
109                     totalBeMerged={totalBeMerged}
110                     totalBeDeleted={totalBeDeleted}
111                 />
112             ) : (
113                 <ContactMergeTableContent
114                     model={model}
115                     updateModel={setModel}
116                     onSubmit={handleStartMerge}
117                     onClose={rest.onClose}
118                     beMergedModel={beMergedModel}
119                     beDeletedModel={beDeletedModel}
120                     totalBeMerged={totalBeMerged}
121                     totalBeDeleted={totalBeDeleted}
122                     onMergeDetails={onMergeDetails}
123                     onMergePreview={onMergePreview}
124                 />
125             )}
126         </ModalTwo>
127     );
130 export default ContactMergeModal;