Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / applications / drive / src / app / store / _views / useSharedWithMeView.ts
blob1699d9541defa7eca7af15cf45b86475cf4fcaa5
1 import { useCallback, useEffect, useMemo, useRef } from 'react';
3 import { useLoading } from '@proton/hooks';
4 import { SORT_DIRECTION } from '@proton/shared/lib/constants';
5 import useFlag from '@proton/unleash/useFlag';
7 import type { SortParams } from '../../components/FileBrowser';
8 import type { SharedWithMeItem } from '../../components/sections/SharedWithMe/SharedWithMe';
9 import { useRedirectToPublicPage } from '../../hooks/util/useRedirectToPublicPage';
10 import { sendErrorReport } from '../../utils/errorHandling';
11 import { getTokenFromSearchParams } from '../../utils/url/token';
12 import { useBookmarksActions } from '../_bookmarks';
13 import { useDriveEventManager } from '../_events';
14 import { useLinksListing } from '../_links';
15 import { useUserSettings } from '../_settings';
16 import { useInvitationsView } from './useInvitationsView';
17 import { useAbortSignal, useMemoArrayNoMatterTheOrder, useSortingWithDefault } from './utils';
18 import { sortItemsWithPositions } from './utils/sortItemsWithPositions';
19 import type { SortField } from './utils/useSorting';
21 const DEFAULT_SORT = {
22     sortField: 'sharedOn' as SortField,
23     sortOrder: SORT_DIRECTION.DESC,
26 /**
27  * useSharedWithMeView provides data for shared with me links view (file browser of shared links).
28  * @params {string} shareId
29  * @params {boolean} disabledByFF, This is used to prevent loading on InitContainer if the flag is enabled.
30  * Context is that we want to show the section if user have FF disabled for sharing by have item shared with him.
31  * TODO: This should be removed after full rollout
32  */
33 export default function useSharedWithMeView(shareId: string) {
34     const [isLoading, withLoading] = useLoading(true);
35     const bookmarksFeatureDisabled = useFlag('DriveShareURLBookmarksDisabled');
36     const [isBookmarksLoading, withBookmarksLoading] = useLoading(!bookmarksFeatureDisabled);
37     const linksListing = useLinksListing();
38     const invitationsPositions = useRef<Map<string, number>>(new Map());
39     const { invitationsBrowserItems, isLoading: isInvitationsLoading } = useInvitationsView();
40     const { addBookmarkFromPrivateApp } = useBookmarksActions();
41     const { cleanupUrl } = useRedirectToPublicPage();
42     const driveEventManager = useDriveEventManager();
44     const loadSharedWithMeLinks = useCallback(
45         async (signal: AbortSignal) => {
46             await linksListing.loadLinksSharedWithMeLink(signal);
47         },
48         [linksListing]
49     );
50     const abortSignalForCache = useAbortSignal([]);
51     const { links: sharedLinks, isDecrypting } = linksListing.getCachedSharedWithMeLink(abortSignalForCache);
52     const { links: bookmarksLinks, isDecrypting: isDecryptingBookmarks } =
53         linksListing.getCachedBookmarksLinks(abortSignalForCache);
55     const cachedSharedLinks = useMemoArrayNoMatterTheOrder(sharedLinks.concat(bookmarksLinks));
57     const { layout } = useUserSettings();
59     const { sortedList, sortParams, setSorting } = useSortingWithDefault(cachedSharedLinks, DEFAULT_SORT);
61     const browserItems: SharedWithMeItem[] = sortedList.reduce<SharedWithMeItem[]>((acc, item) => {
62         // rootShareId is equivalent of token in this context
63         const bookmarkDetails = linksListing.getCachedBookmarkDetails(item.rootShareId);
64         acc.push({
65             ...item,
66             id: item.rootShareId,
67             isBookmark: !!bookmarkDetails,
68             bookmarkDetails: bookmarkDetails ?? undefined,
69         });
70         return acc;
71     }, []);
73     useEffect(() => {
74         const abortController = new AbortController();
75         const unsubscribe = driveEventManager.eventHandlers.subscribeToCore((event) => {
76             if (event.DriveShareRefresh?.Action === 2) {
77                 loadSharedWithMeLinks(abortController.signal).catch(sendErrorReport);
78             }
79         });
81         return () => {
82             unsubscribe();
83             abortController.abort();
84         };
85     }, [loadSharedWithMeLinks, driveEventManager.eventHandlers]);
87     useEffect(() => {
88         const newInvitationsPositions = new Map(invitationsPositions.current);
89         invitationsBrowserItems.forEach((item, index) => {
90             newInvitationsPositions.set(item.rootShareId, index);
91         });
92         invitationsPositions.current = newInvitationsPositions;
93     }, [invitationsBrowserItems]);
95     const sortedItems = useMemo(
96         () => sortItemsWithPositions([...invitationsBrowserItems, ...browserItems], invitationsPositions.current),
97         [invitationsBrowserItems, browserItems, invitationsPositions.current]
98     );
100     useEffect(() => {
101         const abortController = new AbortController();
102         // Even if the user is going into a folder, we keep shared with me items decryption ongoing in the background
103         // This is due to issue with how we decrypt stuff, to prevent infinite loop
104         void withLoading(async () => loadSharedWithMeLinks(abortController.signal)).catch(sendErrorReport);
106         return () => {
107             abortController.abort();
108         };
109     }, []);
111     useEffect(() => {
112         const abortController = new AbortController();
113         if (!bookmarksFeatureDisabled) {
114             void withBookmarksLoading(async () => {
115                 // In case the user Sign-up from public page we will add the file to bookmarks and let him on shared-with-me section
116                 // For Sign-in with redirection to public page logic, check MainContainer
117                 const token = getTokenFromSearchParams();
118                 if (token) {
119                     await addBookmarkFromPrivateApp(abortController.signal, { token });
120                 }
121                 // Cleanup if there any token or redirectToPublic key in search params
122                 cleanupUrl();
123                 await linksListing.loadLinksBookmarks(abortController.signal, shareId);
124             }).catch(sendErrorReport);
125         }
126         return () => {
127             abortController.abort();
128         };
129     }, [bookmarksFeatureDisabled]);
131     return {
132         layout,
133         // Until we have separate section for pending invitations, we do this trick to keep the position of the item in the list,
134         // after invite as been transformed to normal link
135         // This will get all saved index of accepted invites, and place them at the same place in the final list.
136         items: sortedItems,
137         sortParams,
138         setSorting: (sortParams: SortParams<SortField>) => {
139             // If user wants to sort items we clear the pinnedItemsIds to have the normal sortedList
140             invitationsPositions.current = new Map(
141                 Array.from(invitationsPositions.current).filter(
142                     ([key]) => !browserItems.some((item) => item.rootShareId === key)
143                 )
144             );
145             return setSorting(sortParams);
146         },
147         isLoading: isLoading || isInvitationsLoading || isDecrypting || isBookmarksLoading || isDecryptingBookmarks,
148     };