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 Alert from '@proton/components/components/alert/Alert';
8 import useModalState from '@proton/components/components/modalTwo/useModalState';
9 import OrderableTable from '@proton/components/components/orderableTable/OrderableTable';
10 import OrderableTableBody from '@proton/components/components/orderableTable/OrderableTableBody';
11 import OrderableTableHeader from '@proton/components/components/orderableTable/OrderableTableHeader';
12 import OrderableTableRow from '@proton/components/components/orderableTable/OrderableTableRow';
13 import MailUpsellButton from '@proton/components/components/upsell/MailUpsellButton';
14 import NewUpsellModal from '@proton/components/components/upsell/modal/NewUpsellModal';
15 import UpsellModal from '@proton/components/components/upsell/modal/UpsellModal';
16 import useOneDollarConfig from '@proton/components/components/upsell/useOneDollarPromo';
17 import useUpsellConfig from '@proton/components/components/upsell/useUpsellConfig';
18 import SettingsParagraph from '@proton/components/containers/account/SettingsParagraph';
19 import useApi from '@proton/components/hooks/useApi';
20 import useEventManager from '@proton/components/hooks/useEventManager';
21 import useNotifications from '@proton/components/hooks/useNotifications';
22 import { orderAddress } from '@proton/shared/lib/api/addresses';
23 import { APP_UPSELL_REF_PATH, BRAND_NAME, MAIL_UPSELL_PATHS, UPSELL_COMPONENT } from '@proton/shared/lib/constants';
24 import isDeepEqual from '@proton/shared/lib/helpers/isDeepEqual';
25 import { getUpsellRef, useNewUpsellModalVariant } from '@proton/shared/lib/helpers/upsell';
26 import { getKnowledgeBaseUrl } from '@proton/shared/lib/helpers/url';
27 import type { Address, CachedOrganizationKey, Member, UserModel } from '@proton/shared/lib/interfaces';
28 import { getIsNonDefault, sortAddresses } from '@proton/shared/lib/mail/addresses';
29 import addressesImg from '@proton/styles/assets/img/illustrations/new-upsells-img/addresses.svg';
30 import move from '@proton/utils/move';
32 import AddressActions from './AddressActions';
33 import AddressStatus from './AddressStatus';
34 import { getPermissions, getStatus } from './helper';
39 organizationKey?: CachedOrganizationKey;
40 hasDescription?: boolean;
41 allowAddressDeletion: boolean;
44 const AddressesUser = ({ user, organizationKey, member, hasDescription = true, allowAddressDeletion }: Props) => {
46 const { createNotification } = useNotifications();
47 const [savingIndex, setSavingIndex] = useState<number | undefined>();
48 const { call } = useEventManager();
49 const [addresses, loadingAddresses] = useAddresses();
50 const [list, setAddresses] = useState<Address[]>(() => sortAddresses(addresses || []));
52 const upsellRef = getUpsellRef({
53 app: APP_UPSELL_REF_PATH.MAIL_UPSELL_REF_PATH,
54 component: UPSELL_COMPONENT.MODAL,
55 feature: MAIL_UPSELL_PATHS.UNLIMITED_ADDRESSES,
59 const oneDollarConfig = useOneDollarConfig();
60 const upsellConfig = useUpsellConfig({ upsellRef, ...oneDollarConfig });
62 const displayNewUpsellModalsVariant = useNewUpsellModalVariant();
64 const [upsellModalProps, handleUpsellModalDisplay, renderUpsellModal] = useModalState();
68 setAddresses(sortAddresses(addresses));
72 const handleSortEnd = useCallback(
73 async ({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }) => {
75 const newList = move(list, oldIndex, newIndex);
76 const { isExternal, isDisabled } = getStatus(newList[0], 0);
78 if (isDeepEqual(list, newList)) {
82 if (newIndex === 0 && (isDisabled || isExternal)) {
83 const errorMessage = (() => {
85 return c('Notification').t`A disabled address cannot be default`;
88 return c('Notification').t`An external address cannot be default`;
97 setAddresses(sortAddresses(addresses));
101 setAddresses(newList);
102 setSavingIndex(newIndex);
104 await api(orderAddress(newList.map(({ ID }) => ID)));
107 setSavingIndex(undefined);
109 setSavingIndex(undefined);
110 setAddresses(sortAddresses(addresses));
116 const setDefaultAddress = useCallback(
117 (addressOldIndex: number) => {
119 await handleSortEnd({ oldIndex: addressOldIndex, newIndex: 0 });
125 if (!loadingAddresses && !addresses?.length) {
126 return <Alert className="mb-4">{c('Info').t`No addresses exist`}</Alert>;
129 const modal = displayNewUpsellModalsVariant ? (
131 titleModal={c('Title').t`An address for each role`}
132 description={c('Description')
133 .t`Keep different parts of your life separate and your inbox organized with additional addresses.`}
134 modalProps={upsellModalProps}
135 illustration={addressesImg}
136 sourceEvent="BUTTON_MORE_ADDRESSES"
141 title={c('Title').t`Increase your privacy with more addresses`}
142 description={c('Description')
143 .t`Separate different aspects of your life with multiple email addresses and unlock more premium features when you upgrade.`}
144 modalProps={upsellModalProps}
145 sourceEvent="BUTTON_MORE_ADDRESSES"
146 features={['more-storage', 'more-email-addresses', 'unlimited-folders-and-labels', 'custom-email-domains']}
154 <SettingsParagraph className="mt-2">
156 {c('Info').t`Use the different types of email addresses and aliases offered by ${BRAND_NAME}.`}
159 <Href href={getKnowledgeBaseUrl('/addresses-and-aliases')}>{c('Link').t`Learn more`}</Href>
163 {!user.hasPaidMail && (
165 onClick={() => handleUpsellModalDisplay(true)}
166 text={c('Action').t`Get more addresses`}
171 onSortEnd={handleSortEnd}
172 className="simple-table--has-actions mt-4"
173 helperClassname="simple-table--has-actions"
175 <OrderableTableHeader
177 c('Header for addresses table').t`Address`,
178 c('Header for addresses table').t`Status`,
179 c('Header for addresses table').t`Actions`,
182 <OrderableTableBody colSpan={3} loading={loadingAddresses}>
184 list.map((address, i) => {
185 const addressStatuses = getStatus(address, i);
188 disableSort={getIsNonDefault(address)}
192 <div key={0} className="text-ellipsis" title={address.Email}>
195 <AddressStatus key={1} {...addressStatuses} />,
201 onSetDefault={setDefaultAddress(i)}
202 savingIndex={savingIndex}
204 permissions={getPermissions({
212 allowAddressDeletion={allowAddressDeletion}
218 </OrderableTableBody>
221 {renderUpsellModal && modal}
226 export default AddressesUser;