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';
12 ModalTwoContent as ModalContent,
13 ModalTwoFooter as ModalFooter,
14 ModalTwoHeader as ModalHeader,
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[];
43 calendars: VisualCalendar[];
46 hasReactivatedCalendarsRef: React.MutableRefObject<boolean>;
49 const UnlockCalendarsModal = ({ calendars, unlockAll, hasReactivatedCalendarsRef, onDone }: Props) => {
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>(
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);
72 calendarsToReactivate: [],
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 = () => {
96 calendarsToReactivate,
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(() => {
115 const handleError = () => window.location.reload();
116 const handleReset = () => {
118 .then((hasSharedCalendars = false) => {
119 if (hasSharedCalendars) {
120 setResetModalOpen(false);
121 setReshareModalOpen(true);
127 console.error(error);
128 setResetModalOpen(false);
129 setErrorModalOpen(true);
133 const handleReactivate = () => {
136 hasReactivatedCalendarsRef.current = true;
137 if (hasCalendarsToReset) {
138 setReactivateModalOpen(false);
139 setResetModalOpen(true);
145 console.error(error);
146 setReactivateModalOpen(false);
147 setErrorModalOpen(true);
151 const closeDrawer = () => {
153 closeDrawerFromChildApp(parentApp, currentApp, true);
157 const calendarAppBareName = APPS_CONFIGURATION[APPS.PROTONCALENDAR].bareName.toLowerCase();
161 {renderErrorModal && (
162 <Modal {...errorModal}>
163 <ModalHeader title={c('Title').t`Error`} hasClose={false} />
168 <PrimaryButton type="submit" onClick={handleError}>{c('Action').t`Close`}</PrimaryButton>
172 {renderResetModal && (
173 <Modal {...resetModal} size="large">
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`
183 <CalendarResetSection
184 calendarsToReset={getPersonalCalendars(calendarsToReset)}
189 <ButtonLike as={SettingsLink} path={'/recovery'} onClick={closeDrawer}>
190 {c('Action').t`Recover data`}
192 <PrimaryButton type="submit" loading={isLoading} onClick={handleReset}>
193 {c('Action').t`Continue to ${calendarAppBareName}`}
198 {renderReshareModal && (
201 title={c('Title').t`Reshare your calendars`}
207 path={getCalendarsSettingsPath()}
208 onClick={closeDrawer}
210 {c('Action').t`Open settings`}
212 <Button onClick={onDone}>{c('Action').t`Close`}</Button>,
216 {c('Info; reshare calendar modal; part 1')
217 .t`Calendar sharing was disabled following your recent password reset.`}
219 <p>{c('Info; reshare calendar modal; part 2').t`You can reshare your calendars in settings.`}</p>
222 {renderReactivateModal && (
223 <Modal {...reactivateModal}>
224 <ModalHeader title={c('Title').t`Reactivate calendar keys`} hasClose={false} />
226 <CalendarReactivateSection calendarsToReactivate={calendarsToReactivate} />
229 <Button onClick={onDone}>{c('Action').t`Cancel`}</Button>
230 <PrimaryButton type="submit" loading={isLoading} onClick={handleReactivate}>
231 {c('Action').t`Got it`}
240 export default UnlockCalendarsModal;