Update all non-major dependencies
[ProtonMail-WebClient.git] / applications / calendar / src / app / containers / setup / UnlockCalendarsModal.tsx
bloba651bb3daac2cf0a8cc771a4585892c17b8cfa17
1 import { useEffect } from 'react';
3 import { c } from 'ttag';
5 import { useGetAddressKeys } from '@proton/account/addressKeys/hooks';
6 import { useGetAddresses } from '@proton/account/addresses/hooks';
7 import { Button, ButtonLike } from '@proton/atoms';
8 import { useGetCalendars } from '@proton/calendar/calendars/hooks';
9 import {
10     GenericError,
11     ModalTwo as Modal,
12     ModalTwoContent as ModalContent,
13     ModalTwoFooter as ModalFooter,
14     ModalTwoHeader as ModalHeader,
15     PrimaryButton,
16     Prompt,
17     SettingsLink,
18     useApi,
19     useConfig,
20     useDrawer,
21     useModalState,
22 } from '@proton/components';
23 import { useLoading } from '@proton/hooks';
24 import { getPersonalCalendars } from '@proton/shared/lib/calendar/calendar';
25 import { CALENDAR_FLAGS } from '@proton/shared/lib/calendar/constants';
26 import { process } from '@proton/shared/lib/calendar/crypto/keys/resetHelper';
27 import { getCalendarsSettingsPath } from '@proton/shared/lib/calendar/settingsRoutes';
28 import { APPS, APPS_CONFIGURATION } from '@proton/shared/lib/constants';
29 import { closeDrawerFromChildApp } from '@proton/shared/lib/drawer/helpers';
30 import { hasBit } from '@proton/shared/lib/helpers/bitset';
31 import type { VisualCalendar } from '@proton/shared/lib/interfaces/calendar';
33 import CalendarReactivateSection from './CalendarReactivateSection';
34 import CalendarResetSection from './CalendarResetSection';
36 interface FilteredCalendars {
37     calendarsToReset: VisualCalendar[];
38     calendarsToReactivate: VisualCalendar[];
39     calendarsToClean: VisualCalendar[];
42 interface Props {
43     calendars: VisualCalendar[];
44     unlockAll: boolean;
45     onDone: () => void;
46     hasReactivatedCalendarsRef: React.MutableRefObject<boolean>;
49 const UnlockCalendarsModal = ({ calendars, unlockAll, hasReactivatedCalendarsRef, onDone }: Props) => {
50     const api = useApi();
51     const getCalendars = useGetCalendars();
52     const getAddresses = useGetAddresses();
53     const getAddressKeys = useGetAddressKeys();
54     const { parentApp } = useDrawer();
55     const { APP_NAME: currentApp } = useConfig();
57     const { calendarsToReset, calendarsToReactivate, calendarsToClean } = calendars.reduce<FilteredCalendars>(
58         (acc, calendar) => {
59             const { Flags } = calendar;
60             if (hasBit(Flags, CALENDAR_FLAGS.RESET_NEEDED)) {
61                 acc.calendarsToReset.push(calendar);
62             } else if (hasBit(Flags, CALENDAR_FLAGS.UPDATE_PASSPHRASE)) {
63                 acc.calendarsToReactivate.push(calendar);
64             } else if (hasBit(Flags, CALENDAR_FLAGS.LOST_ACCESS)) {
65                 acc.calendarsToClean.push(calendar);
66             }
68             return acc;
69         },
70         {
71             calendarsToReset: [],
72             calendarsToReactivate: [],
73             calendarsToClean: [],
74         }
75     );
77     const hasCalendarsToReset = calendarsToReset.length > 0;
78     const hasCalendarsToReactivate = calendarsToReactivate.length > 0;
79     const hasCalendarsToClean = calendarsToClean.length > 0;
81     const [errorModal, setErrorModalOpen, renderErrorModal] = useModalState();
82     const [resetModal, setResetModalOpen, renderResetModal] = useModalState();
83     const [reshareModal, setReshareModalOpen, renderReshareModal] = useModalState();
84     const [reactivateModal, setReactivateModalOpen, renderReactivateModal] = useModalState();
86     const [isLoading, withLoading] = useLoading(false);
88     const handleProcess = () => {
89         return withLoading(
90             process({
91                 api,
92                 getCalendars,
93                 getAddressKeys,
94                 getAddresses,
95                 calendarsToReset,
96                 calendarsToReactivate,
97                 calendarsToClean,
98             })
99         );
100     };
102     useEffect(() => {
103         if (hasCalendarsToReactivate) {
104             setReactivateModalOpen(true);
105         } else if (hasCalendarsToReset) {
106             setResetModalOpen(true);
107         } else if (hasCalendarsToClean) {
108             // When user has only calendars to clean (e.g: holidays/shared), we want to do the process in the background
109             void handleProcess().then(() => {
110                 onDone();
111             });
112         }
113     }, []);
115     const handleError = () => window.location.reload();
116     const handleReset = () => {
117         handleProcess()
118             .then((hasSharedCalendars = false) => {
119                 if (hasSharedCalendars) {
120                     setResetModalOpen(false);
121                     setReshareModalOpen(true);
122                 } else {
123                     onDone();
124                 }
125             })
126             .catch((error) => {
127                 console.error(error);
128                 setResetModalOpen(false);
129                 setErrorModalOpen(true);
130             });
131     };
133     const handleReactivate = () => {
134         handleProcess()
135             .then(() => {
136                 hasReactivatedCalendarsRef.current = true;
137                 if (hasCalendarsToReset) {
138                     setReactivateModalOpen(false);
139                     setResetModalOpen(true);
140                     return;
141                 }
142                 onDone();
143             })
144             .catch((error) => {
145                 console.error(error);
146                 setReactivateModalOpen(false);
147                 setErrorModalOpen(true);
148             });
149     };
151     const closeDrawer = () => {
152         if (parentApp) {
153             closeDrawerFromChildApp(parentApp, currentApp, true);
154         }
155     };
157     const calendarAppBareName = APPS_CONFIGURATION[APPS.PROTONCALENDAR].bareName.toLowerCase();
159     return (
160         <>
161             {renderErrorModal && (
162                 <Modal {...errorModal}>
163                     <ModalHeader title={c('Title').t`Error`} hasClose={false} />
164                     <ModalContent>
165                         <GenericError />
166                     </ModalContent>
167                     <ModalFooter>
168                         <PrimaryButton type="submit" onClick={handleError}>{c('Action').t`Close`}</PrimaryButton>
169                     </ModalFooter>
170                 </Modal>
171             )}
172             {renderResetModal && (
173                 <Modal {...resetModal} size="large">
174                     <ModalHeader
175                         title={
176                             unlockAll
177                                 ? c('Title').t`We've locked your calendars to protect your data`
178                                 : c('Title').t`We've locked some calendars to protect your data`
179                         }
180                         hasClose={false}
181                     />
182                     <ModalContent>
183                         <CalendarResetSection
184                             calendarsToReset={getPersonalCalendars(calendarsToReset)}
185                             resetAll={unlockAll}
186                         />
187                     </ModalContent>
188                     <ModalFooter>
189                         <ButtonLike as={SettingsLink} path={'/recovery'} onClick={closeDrawer}>
190                             {c('Action').t`Recover data`}
191                         </ButtonLike>
192                         <PrimaryButton type="submit" loading={isLoading} onClick={handleReset}>
193                             {c('Action').t`Continue to ${calendarAppBareName}`}
194                         </PrimaryButton>
195                     </ModalFooter>
196                 </Modal>
197             )}
198             {renderReshareModal && (
199                 <Prompt
200                     {...reshareModal}
201                     title={c('Title').t`Reshare your calendars`}
202                     buttons={[
203                         <ButtonLike
204                             as={SettingsLink}
205                             type="submit"
206                             color="norm"
207                             path={getCalendarsSettingsPath()}
208                             onClick={closeDrawer}
209                         >
210                             {c('Action').t`Open settings`}
211                         </ButtonLike>,
212                         <Button onClick={onDone}>{c('Action').t`Close`}</Button>,
213                     ]}
214                 >
215                     <p>
216                         {c('Info; reshare calendar modal; part 1')
217                             .t`Calendar sharing was disabled following your recent password reset.`}
218                     </p>
219                     <p>{c('Info; reshare calendar modal; part 2').t`You can reshare your calendars in settings.`}</p>
220                 </Prompt>
221             )}
222             {renderReactivateModal && (
223                 <Modal {...reactivateModal}>
224                     <ModalHeader title={c('Title').t`Reactivate calendar keys`} hasClose={false} />
225                     <ModalContent>
226                         <CalendarReactivateSection calendarsToReactivate={calendarsToReactivate} />
227                     </ModalContent>
228                     <ModalFooter>
229                         <Button onClick={onDone}>{c('Action').t`Cancel`}</Button>
230                         <PrimaryButton type="submit" loading={isLoading} onClick={handleReactivate}>
231                             {c('Action').t`Got it`}
232                         </PrimaryButton>
233                     </ModalFooter>
234                 </Modal>
235             )}
236         </>
237     );
240 export default UnlockCalendarsModal;