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';
17 * useDefaultShare provides access to main default user's share.
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]);
36 sharesState.setShares(shares);
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);
56 if (!defaultShareId) {
57 const { shareId } = await createVolume();
58 defaultShareId = shareId;
59 // Load shares to the cache.
60 await loadUserShares();
63 return getShareWithKey(abortSignal || new AbortController().signal, defaultShareId);
69 [sharesState.getDefaultShareId, getShareWithKey]
72 const getDefaultShareAddressEmail = useCallback(
73 async (abortSignal?: AbortSignal): Promise<string> => {
74 const share = await getDefaultShare(abortSignal);
75 const { address } = await getOwnAddressAndPrimaryKeys(share.addressId);
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);
96 // We currently don't support photos share creation on web
97 return defaultPhotosShareId
98 ? getShareWithKey(abortSignal || new AbortController().signal, defaultPhotosShareId)
101 ['getDefaultPhotosShare'],
105 [sharesState.getDefaultPhotosShareId, getShareWithKey]
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;
115 ['isShareAvailable', shareId],
124 getDefaultShareAddressEmail,
125 getDefaultPhotosShare,