Merge branch 'MAILWEB-6067-improve-circular-dependencies-prevention' into 'main'
[ProtonMail-WebClient.git] / packages / drive-store / store / _shares / useDefaultShare.ts
blobb3eaf66407d3beb24f618608d83690a2e71f1b03
1 import { useCallback } from 'react';
3 import { queryUserShares } from '@proton/shared/lib/api/drive/share';
4 import type { UserShareResult } from '@proton/shared/lib/interfaces/drive/share';
6 import { shareMetaShortToShare, useDebouncedRequest } from '../_api';
7 import { useDriveCrypto } from '../_crypto';
8 import { useDebouncedFunction } from '../_utils';
9 import { useVolumesState } from '../_volumes';
10 import type { Share, ShareWithKey } from './interface';
11 import { ShareState } from './interface';
12 import useShare from './useShare';
13 import useSharesState, { findDefaultPhotosShareId, findDefaultShareId } from './useSharesState';
14 import useVolume from './useVolume';
16 /**
17  * useDefaultShare provides access to main default user's share.
18  */
19 export default function useDefaultShare() {
20     const debouncedFunction = useDebouncedFunction();
21     const debouncedRequest = useDebouncedRequest();
22     const sharesState = useSharesState();
23     const { getShare, getShareWithKey } = useShare();
24     const { createVolume } = useVolume();
25     const volumesState = useVolumesState();
26     const { getOwnAddressAndPrimaryKeys } = useDriveCrypto();
28     const loadUserShares = useCallback(async (): Promise<Share[]> => {
29         const { Shares } = await debouncedRequest<UserShareResult>(queryUserShares());
30         // We have to ignore the deleted shares until BE stop to return them
31         const shares = Shares.map(shareMetaShortToShare).filter((share) => share.state !== ShareState.deleted);
33         shares.forEach(({ volumeId, shareId }) => {
34             volumesState.setVolumeShareIds(volumeId, [shareId]);
35         });
36         sharesState.setShares(shares);
37         return shares;
38     }, []);
40     const getDefaultShare = useCallback(
41         async (abortSignal?: AbortSignal): Promise<ShareWithKey> => {
42             return debouncedFunction(
43                 async (abortSignal: AbortSignal) => {
44                     let defaultShareId = sharesState.getDefaultShareId();
46                     // First try to load fresh list of shares from API to make sure
47                     // we don't create second default share.
48                     if (!defaultShareId) {
49                         const shares = await loadUserShares();
50                         // Do not use sharesState.getDefaultShareId as useState
51                         // is not sync operation and thus the new state might
52                         // not be set just yet.
53                         defaultShareId = findDefaultShareId(shares);
54                     }
56                     if (!defaultShareId) {
57                         const { shareId } = await createVolume();
58                         defaultShareId = shareId;
59                         // Load shares to the cache.
60                         await loadUserShares();
61                     }
63                     return getShareWithKey(abortSignal || new AbortController().signal, defaultShareId);
64                 },
65                 ['getDefaultShare'],
66                 abortSignal
67             );
68         },
69         [sharesState.getDefaultShareId, getShareWithKey]
70     );
72     const getDefaultShareAddressEmail = useCallback(
73         async (abortSignal?: AbortSignal): Promise<string> => {
74             const share = await getDefaultShare(abortSignal);
75             const { address } = await getOwnAddressAndPrimaryKeys(share.addressId);
76             return address.Email;
77         },
78         [getDefaultShare]
79     );
81     const getDefaultPhotosShare = useCallback(
82         async (abortSignal?: AbortSignal): Promise<ShareWithKey | undefined> => {
83             return debouncedFunction(
84                 async (abortSignal: AbortSignal) => {
85                     let defaultPhotosShareId = sharesState.getDefaultPhotosShareId();
87                     // First try to load fresh list of shares from API
88                     if (!defaultPhotosShareId) {
89                         const shares = await loadUserShares();
90                         // Do not use sharesState.getDefaultPhotosShare as useState
91                         // is not sync operation and thus the new state might
92                         // not be set just yet.
93                         defaultPhotosShareId = findDefaultPhotosShareId(shares);
94                     }
96                     // We currently don't support photos share creation on web
97                     return defaultPhotosShareId
98                         ? getShareWithKey(abortSignal || new AbortController().signal, defaultPhotosShareId)
99                         : undefined;
100                 },
101                 ['getDefaultPhotosShare'],
102                 abortSignal
103             );
104         },
105         [sharesState.getDefaultPhotosShareId, getShareWithKey]
106     );
108     const isShareAvailable = useCallback(
109         (abortSignal: AbortSignal, shareId: string): Promise<boolean> => {
110             return debouncedFunction(
111                 async (abortSignal: AbortSignal) => {
112                     const share = await getShare(abortSignal, shareId);
113                     return !share.isLocked && !share.isVolumeSoftDeleted;
114                 },
115                 ['isShareAvailable', shareId],
116                 abortSignal
117             );
118         },
119         [getShare]
120     );
122     return {
123         getDefaultShare,
124         getDefaultShareAddressEmail,
125         getDefaultPhotosShare,
126         isShareAvailable,
127     };