1 import type { Dispatch, SetStateAction } from 'react';
3 import { c } from 'ttag';
5 import { Button } from '@proton/atoms';
6 import Alert from '@proton/components/components/alert/Alert';
7 import ModalTwoContent from '@proton/components/components/modalTwo/ModalContent';
8 import ModalTwoFooter from '@proton/components/components/modalTwo/ModalFooter';
9 import ModalTwoHeader from '@proton/components/components/modalTwo/ModalHeader';
10 import type { ContactFormatted, ContactMergeModel } from '@proton/shared/lib/interfaces/contacts';
11 import move from '@proton/utils/move';
13 import type { ContactMergePreviewModalProps } from './ContactMergePreviewModal';
14 import MergeTable from './table/MergeTable';
17 model: ContactMergeModel;
18 updateModel: Dispatch<SetStateAction<ContactMergeModel>>;
21 beMergedModel: { [ID: string]: string[] };
22 beDeletedModel: { [ID: string]: string };
23 totalBeMerged: number;
24 totalBeDeleted: number;
25 onMergeDetails: (contactID: string) => void;
26 onMergePreview: (props: ContactMergePreviewModalProps) => void;
30 * Re-order elements in an array inside a group of arrays
33 collection: ContactFormatted[][],
35 { oldIndex, newIndex }: { oldIndex: number; newIndex: number }
37 return collection.map((group, i) => {
38 if (i === groupIndex) {
39 return move(group, oldIndex, newIndex);
45 const ContactMergeTableContent = ({
57 const { orderedContacts, isChecked, beDeleted } = model;
59 const isDeleteOnly = totalBeMerged <= 0 && totalBeDeleted > 0;
61 const handleToggleCheck = (ID: string) => {
62 updateModel((model) => ({
64 isChecked: { ...isChecked, [ID]: !isChecked[ID] },
67 const handleToggleDelete = (ID: string) => {
68 updateModel((model) => ({
70 beDeleted: { ...beDeleted, [ID]: !beDeleted[ID] },
74 (groupIndex: number) =>
75 ({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }) => {
76 updateModel((model) => ({
78 orderedContacts: moveInGroup(orderedContacts, groupIndex, { oldIndex, newIndex }),
82 const handlePreview = (beMergedID: string, beDeletedIDs: string[]) => {
83 const beMergedModelSingle = { [beMergedID]: beMergedModel[beMergedID] };
84 const beDeletedModelSingle = beDeletedIDs.reduce<{ [ID: string]: string }>((acc, ID) => {
85 acc[ID] = beDeletedModel[ID];
90 beMergedModel: beMergedModelSingle,
91 beDeletedModel: beDeletedModelSingle,
98 <ModalTwoHeader title={c('Title').t`Merge contacts`} />
100 <Alert className="mb-4">
102 .t`Use Drag and Drop to rank merging priority between contacts. Uncheck the contacts you do not want to merge.`}
104 <Alert className="mb-4" type="warning">
106 .t`You can mark for deletion the contacts that you do not want neither to merge nor to keep. Deletion will only take place after the merge button is clicked`}
109 onSortEnd={handleSortEnd}
110 contacts={orderedContacts}
111 isChecked={isChecked}
112 beDeleted={beDeleted}
113 onClickCheckbox={handleToggleCheck}
114 onClickDetails={onMergeDetails}
115 onToggleDelete={handleToggleDelete}
116 onClickPreview={handlePreview}
120 <Button onClick={onClose} data-testid="merge-model-cancel-button">{c('Action').t`Cancel`}</Button>
122 <Button color="norm" onClick={onSubmit}>{c('Action').t`Continue`}</Button>
126 disabled={!totalBeMerged}
128 data-testid="merge-model-merge-button"
130 {c('Action').t`Merge`}
138 export default ContactMergeTableContent;