Remove payments API routing initialization
[ProtonMail-WebClient.git] / packages / components / containers / addresses / AddressesWithUser.tsx
blobff6488f7eb60653cc2166be94b6bf6847980e7fe
1 import { useCallback, useEffect, useState } from 'react';
3 import { c } from 'ttag';
5 import { useAddresses } from '@proton/account/addresses/hooks';
6 import { Href } from '@proton/atoms';
7 import { NewUpsellModal, useUpsellConfig } from '@proton/components';
8 import Alert from '@proton/components/components/alert/Alert';
9 import useModalState from '@proton/components/components/modalTwo/useModalState';
10 import OrderableTable from '@proton/components/components/orderableTable/OrderableTable';
11 import OrderableTableBody from '@proton/components/components/orderableTable/OrderableTableBody';
12 import OrderableTableHeader from '@proton/components/components/orderableTable/OrderableTableHeader';
13 import OrderableTableRow from '@proton/components/components/orderableTable/OrderableTableRow';
14 import MailUpsellButton from '@proton/components/components/upsell/MailUpsellButton';
15 import UpsellModal from '@proton/components/components/upsell/modal/UpsellModal';
16 import useOneDollarConfig from '@proton/components/components/upsell/useOneDollarPromo';
17 import SettingsParagraph from '@proton/components/containers/account/SettingsParagraph';
18 import useApi from '@proton/components/hooks/useApi';
19 import useEventManager from '@proton/components/hooks/useEventManager';
20 import useNotifications from '@proton/components/hooks/useNotifications';
21 import { orderAddress } from '@proton/shared/lib/api/addresses';
22 import { APP_UPSELL_REF_PATH, BRAND_NAME, MAIL_UPSELL_PATHS, UPSELL_COMPONENT } from '@proton/shared/lib/constants';
23 import isDeepEqual from '@proton/shared/lib/helpers/isDeepEqual';
24 import { getUpsellRef, useNewUpsellModalVariant } from '@proton/shared/lib/helpers/upsell';
25 import { getKnowledgeBaseUrl } from '@proton/shared/lib/helpers/url';
26 import type { Address, CachedOrganizationKey, Member, UserModel } from '@proton/shared/lib/interfaces';
27 import { getIsNonDefault, sortAddresses } from '@proton/shared/lib/mail/addresses';
28 import addressesImg from '@proton/styles/assets/img/illustrations/new-upsells-img/addresses.svg';
29 import move from '@proton/utils/move';
31 import AddressActions from './AddressActions';
32 import AddressStatus from './AddressStatus';
33 import { getPermissions, getStatus } from './helper';
35 interface Props {
36     user: UserModel;
37     member?: Member;
38     organizationKey?: CachedOrganizationKey;
39     hasDescription?: boolean;
40     allowAddressDeletion: boolean;
43 const AddressesUser = ({ user, organizationKey, member, hasDescription = true, allowAddressDeletion }: Props) => {
44     const api = useApi();
45     const { createNotification } = useNotifications();
46     const [savingIndex, setSavingIndex] = useState<number | undefined>();
47     const { call } = useEventManager();
48     const [addresses, loadingAddresses] = useAddresses();
49     const [list, setAddresses] = useState<Address[]>(() => sortAddresses(addresses || []));
51     const upsellRef = getUpsellRef({
52         app: APP_UPSELL_REF_PATH.MAIL_UPSELL_REF_PATH,
53         component: UPSELL_COMPONENT.MODAL,
54         feature: MAIL_UPSELL_PATHS.UNLIMITED_ADDRESSES,
55         isSettings: true,
56     });
58     const oneDollarConfig = useOneDollarConfig();
59     const upsellConfig = useUpsellConfig({ upsellRef, ...oneDollarConfig });
61     const displayNewUpsellModalsVariant = useNewUpsellModalVariant();
63     const [upsellModalProps, handleUpsellModalDisplay, renderUpsellModal] = useModalState();
65     useEffect(() => {
66         if (addresses) {
67             setAddresses(sortAddresses(addresses));
68         }
69     }, [addresses]);
71     const handleSortEnd = useCallback(
72         async ({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }) => {
73             try {
74                 const newList = move(list, oldIndex, newIndex);
75                 const { isExternal, isDisabled } = getStatus(newList[0], 0);
77                 if (isDeepEqual(list, newList)) {
78                     return;
79                 }
81                 if (newIndex === 0 && (isDisabled || isExternal)) {
82                     const errorMessage = (() => {
83                         if (isDisabled) {
84                             return c('Notification').t`A disabled address cannot be default`;
85                         }
86                         if (isExternal) {
87                             return c('Notification').t`An external address cannot be default`;
88                         }
89                     })();
90                     if (errorMessage) {
91                         createNotification({
92                             type: 'error',
93                             text: errorMessage,
94                         });
95                     }
96                     setAddresses(sortAddresses(addresses));
97                     return;
98                 }
100                 setAddresses(newList);
101                 setSavingIndex(newIndex);
103                 await api(orderAddress(newList.map(({ ID }) => ID)));
104                 await call();
106                 setSavingIndex(undefined);
107             } catch (e: any) {
108                 setSavingIndex(undefined);
109                 setAddresses(sortAddresses(addresses));
110             }
111         },
112         [list, addresses]
113     );
115     const setDefaultAddress = useCallback(
116         (addressOldIndex: number) => {
117             return async () => {
118                 await handleSortEnd({ oldIndex: addressOldIndex, newIndex: 0 });
119             };
120         },
121         [list, addresses]
122     );
124     if (!loadingAddresses && !addresses?.length) {
125         return <Alert className="mb-4">{c('Info').t`No addresses exist`}</Alert>;
126     }
128     const modal = displayNewUpsellModalsVariant ? (
129         <NewUpsellModal
130             titleModal={c('Title').t`An address for each role`}
131             description={c('Description')
132                 .t`Keep different parts of your life separate and your inbox organized with additional addresses.`}
133             modalProps={upsellModalProps}
134             illustration={addressesImg}
135             sourceEvent="BUTTON_MORE_ADDRESSES"
136             {...upsellConfig}
137         />
138     ) : (
139         <UpsellModal
140             title={c('Title').t`Increase your privacy with more addresses`}
141             description={c('Description')
142                 .t`Separate different aspects of your life with multiple email addresses and unlock more premium features when you upgrade.`}
143             modalProps={upsellModalProps}
144             sourceEvent="BUTTON_MORE_ADDRESSES"
145             features={['more-storage', 'more-email-addresses', 'unlimited-folders-and-labels', 'custom-email-domains']}
146             {...upsellConfig}
147         />
148     );
150     return (
151         <>
152             {hasDescription && (
153                 <SettingsParagraph className="mt-2">
154                     <span>
155                         {c('Info').t`Use the different types of email addresses and aliases offered by ${BRAND_NAME}.`}
156                     </span>
157                     <br />
158                     <Href href={getKnowledgeBaseUrl('/addresses-and-aliases')}>{c('Link').t`Learn more`}</Href>
159                 </SettingsParagraph>
160             )}
162             {!user.hasPaidMail && (
163                 <MailUpsellButton
164                     onClick={() => handleUpsellModalDisplay(true)}
165                     text={c('Action').t`Get more addresses`}
166                 />
167             )}
169             <OrderableTable
170                 onSortEnd={handleSortEnd}
171                 className="simple-table--has-actions mt-4"
172                 helperClassname="simple-table--has-actions"
173             >
174                 <OrderableTableHeader
175                     cells={[
176                         c('Header for addresses table').t`Address`,
177                         c('Header for addresses table').t`Status`,
178                         c('Header for addresses table').t`Actions`,
179                     ]}
180                 />
181                 <OrderableTableBody colSpan={3} loading={loadingAddresses}>
182                     {list &&
183                         list.map((address, i) => {
184                             const addressStatuses = getStatus(address, i);
185                             return (
186                                 <OrderableTableRow
187                                     disableSort={getIsNonDefault(address)}
188                                     key={i}
189                                     index={i}
190                                     cells={[
191                                         <div key={0} className="text-ellipsis" title={address.Email}>
192                                             {address.Email}
193                                         </div>,
194                                         <AddressStatus key={1} {...addressStatuses} />,
195                                         <AddressActions
196                                             key={2}
197                                             address={address}
198                                             member={member}
199                                             user={user}
200                                             onSetDefault={setDefaultAddress(i)}
201                                             savingIndex={savingIndex}
202                                             addressIndex={i}
203                                             permissions={getPermissions({
204                                                 addressIndex: i,
205                                                 member,
206                                                 address,
207                                                 addresses: list,
208                                                 user,
209                                                 organizationKey,
210                                             })}
211                                             allowAddressDeletion={allowAddressDeletion}
212                                         />,
213                                     ]}
214                                 />
215                             );
216                         })}
217                 </OrderableTableBody>
218             </OrderableTable>
220             {renderUpsellModal && modal}
221         </>
222     );
225 export default AddressesUser;