Remove client-side isLoggedIn value
[ProtonMail-WebClient.git] / packages / drive-store / components / revisions / RevisionsProvider.tsx
blobea6646669a4bc3552a5900f559a40de75762b0b1
1 import type { PropsWithChildren } from 'react';
2 import { createContext, useContext, useMemo, useRef, useState } from 'react';
4 import { fromUnixTime } from 'date-fns';
5 import { c } from 'ttag';
7 import { useConfirmActionModal, useNotifications } from '@proton/components';
8 import type { SHARE_MEMBER_PERMISSIONS } from '@proton/shared/lib/drive/permissions';
9 import { isPreviewAvailable } from '@proton/shared/lib/helpers/preview';
10 import { dateLocale } from '@proton/shared/lib/i18n';
11 import { FileRevisionState } from '@proton/shared/lib/interfaces/drive/file';
12 import clsx from '@proton/utils/clsx';
14 import type { DecryptedLink, DriveFileRevision } from '../../store';
15 import { useDownload, useRevisionsView } from '../../store';
16 import PortalPreview from '../PortalPreview';
17 import { useRevisionDetailsModal } from '../modals/DetailsModal';
18 import type { CategorizedRevisions } from './getCategorizedRevisions';
19 import { getCategorizedRevisions } from './getCategorizedRevisions';
21 import './RevisionPreview.scss';
23 export interface RevisionsProviderState {
24     hasPreviewAvailable: boolean;
25     isLoading: boolean;
26     permissions: SHARE_MEMBER_PERMISSIONS;
27     currentRevision: DriveFileRevision;
28     categorizedRevisions: CategorizedRevisions;
29     openRevisionPreview: (revision: DriveFileRevision) => void;
30     openRevisionDetails: (revision: DriveFileRevision) => void;
31     deleteRevision: (abortSignal: AbortSignal, revision: DriveFileRevision) => void;
32     restoreRevision: (abortSignal: AbortSignal, revision: DriveFileRevision) => void;
33     downloadRevision: (revisionId: string) => void;
36 const RevisionsContext = createContext<RevisionsProviderState | null>(null);
38 export const RevisionsProvider = ({
39     link,
40     children,
41 }: PropsWithChildren<{
42     link: DecryptedLink;
43 }>) => {
44     const { createNotification } = useNotifications();
45     const ref = useRef(null);
47     const {
48         isLoading,
49         revisions: [currentRevision, ...olderRevisions],
50         permissions,
51         deleteRevision,
52         restoreRevision,
53     } = useRevisionsView(link.rootShareId, link.linkId);
54     const categorizedRevisions = useMemo(() => getCategorizedRevisions(olderRevisions), [olderRevisions]);
55     const [confirmModal, showConfirmModal] = useConfirmActionModal();
56     const [revisionDetailsModal, showRevisionDetailsModal] = useRevisionDetailsModal();
57     const hasPreviewAvailable = !!link.mimeType && isPreviewAvailable(link.mimeType, link.size);
58     const [selectedRevision, setSelectedRevision] = useState<DriveFileRevision | null>(null);
59     const { download } = useDownload();
61     const downloadRevision = (revisionId: string) => {
62         void download([{ ...link, shareId: link.rootShareId, revisionId: revisionId }]);
63     };
65     const openRevisionDetails = (revision: DriveFileRevision) => {
66         void showRevisionDetailsModal({
67             revision,
68             shareId: link.rootShareId,
69             linkId: link.linkId,
70             name: link.name,
71         });
72     };
74     const handleRevisionDelete = (abortSignal: AbortSignal, revision: DriveFileRevision) => {
75         const formattedRevisionDate = new Intl.DateTimeFormat(dateLocale.code, {
76             dateStyle: 'long',
77             timeStyle: 'short',
78         }).format(fromUnixTime(revision.createTime));
79         void showConfirmModal({
80             size: 'small',
81             title: c('Action').t`Delete this version`,
82             submitText: c('Action').t`Delete permanently`,
83             message: (
84                 <>
85                     {
86                         // translator: complete sentence example: Are you sure you want to permanently delete Yearly reports.docx, February 6, 2023 at 12:00 from the version history?
87                         c('Info').t`Are you sure you want to permanently delete`
88                     }
89                     &nbsp;
90                     <span className="text-bold">
91                         {link.name}, {formattedRevisionDate}
92                     </span>
93                     &nbsp;
94                     {
95                         // translator: complete sentence example: Are you sure you want to permanently delete Yearly reports.docx, February 6, 2023 at 12:00 from the version history?
96                         c('Info').t`from the version history?`
97                     }
98                 </>
99             ),
100             onSubmit: () =>
101                 deleteRevision(abortSignal, revision.id).then(() => {
102                     createNotification({
103                         text: c('Info').t`Version is deleted`,
104                     });
105                 }),
106         });
107     };
109     const handleRevisionRestore = (abortSignal: AbortSignal, revision: DriveFileRevision) => {
110         const formattedRevisionDate = new Intl.DateTimeFormat(dateLocale.code, {
111             dateStyle: 'long',
112             timeStyle: 'short',
113         }).format(fromUnixTime(revision.createTime));
114         void showConfirmModal({
115             size: 'small',
116             title: c('Action').t`Restore this version`,
117             submitText: c('Action').t`Restore`,
118             actionType: 'norm',
119             canUndo: true,
120             message: (
121                 <>
122                     <span className="text-bold">{link.name}</span>
123                     &nbsp;
124                     {
125                         // translator: complete sentence example: Yearly reports.docx. will be restored to the version from February 6, 2023 at 12:00. All other versions will still be saved.
126                         c('Info')
127                             .t`will be restored to the version from ${formattedRevisionDate}. All other versions will still be saved.`
128                     }
129                 </>
130             ),
131             onSubmit: () =>
132                 restoreRevision(abortSignal, revision.id).then((Code) => {
133                     if (Code === 1000) {
134                         createNotification({
135                             text: c('Info').t`Version is restored`,
136                         });
137                     } else {
138                         createNotification({
139                             text: c('Info').t`Restore is in progress. This can take a few seconds.`,
140                         });
141                     }
142                 }),
143         });
144     };
146     const openRevisionPreview = (revision: DriveFileRevision) => {
147         setSelectedRevision(revision);
148     };
150     return (
151         <RevisionsContext.Provider
152             value={{
153                 hasPreviewAvailable,
154                 isLoading,
155                 permissions,
156                 deleteRevision: handleRevisionDelete,
157                 restoreRevision: handleRevisionRestore,
158                 currentRevision,
159                 categorizedRevisions,
160                 openRevisionPreview,
161                 openRevisionDetails,
162                 downloadRevision,
163             }}
164         >
165             {children}
166             {selectedRevision && (
167                 <PortalPreview
168                     key="portal-preview-revisions"
169                     open={!!selectedRevision}
170                     ref={ref}
171                     revisionId={selectedRevision.id}
172                     shareId={link.rootShareId}
173                     linkId={link.linkId}
174                     date={selectedRevision.createTime}
175                     className={clsx(
176                         'revision-preview',
177                         (confirmModal?.props.open || revisionDetailsModal?.props.open) && 'revision-preview--behind'
178                     )}
179                     onDetails={() => openRevisionDetails(selectedRevision)}
180                     onRestore={
181                         selectedRevision.state !== FileRevisionState.Active
182                             ? () => {
183                                   handleRevisionRestore(new AbortController().signal, selectedRevision);
184                               }
185                             : undefined
186                     }
187                     onClose={() => setSelectedRevision(null)}
188                     onExit={() => setSelectedRevision(null)}
189                 />
190             )}
192             {revisionDetailsModal}
193             {confirmModal}
194         </RevisionsContext.Provider>
195     );
198 export const useRevisionsProvider = () => {
199     const state = useContext(RevisionsContext);
200     if (!state) {
201         throw new Error('Trying to use uninitialized RevisionsProvider');
202     }
203     return state;