1 import { useCallback } from 'react';
3 import { useDevicesListing } from '../_devices';
4 import type { DecryptedLink } from '../_links';
5 import { useLink } from '../_links';
6 import useLinksState from '../_links/useLinksState';
7 import { ShareType, useShare } from '../_shares';
8 import { isLinkReadOnly } from './utils/useIsActiveLinkReadOnly';
18 const generateLinkPath = async (
19 abortSignal: AbortSignal,
22 getLink: (abortSignal: AbortSignal, shareId: string, linkId: string) => Promise<DecryptedLink>
24 const currentLinkMeta = await getLink(abortSignal, shareId, linkId);
25 const path = [currentLinkMeta];
27 let nextLinkId = currentLinkMeta.parentLinkId;
29 const linkMeta = await getLink(abortSignal, shareId, nextLinkId);
30 path.unshift(linkMeta);
31 nextLinkId = linkMeta.parentLinkId;
38 * useLinkPath provides paths to links.
39 * Ideally, this should not be used directly, but be part of useFolderView
40 * (for breadcrumb), for example.
42 export default function useLinkPath() {
43 const { getLink } = useLink();
44 const { getShare } = useShare();
45 const { getDeviceByShareId } = useDevicesListing();
47 // This is hack. Do not keep it around when moved properly to the state.
48 // When name of some parent changes, we need to update the location as
49 // well, but thats not part of the child link. Therefore, this function
50 // needs to be called any time the state changes. To not do too much
51 // work when its not needed, we cache the callbacks, for which we need
52 // the state. Once the location is part of the state, this whole hook
53 // will not be needed. The problem might be, that updating location for
54 // every link in the store might not be good as well, so that needs more
56 const { getLink: getCachedLink } = useLinksState();
58 const traverseLinksToRoot = useCallback(
59 async (abortSignal: AbortSignal, shareId: string, linkId: string): Promise<PathItem[]> => {
60 const path = await generateLinkPath(abortSignal, shareId, linkId, getLink);
61 const rootShare = await getShare(abortSignal, shareId);
63 const rootLinkName = rootShare.type === ShareType.device && getDeviceByShareId(shareId)?.name;
65 return path.map((link) => ({
67 name: !link.parentLinkId && rootLinkName ? rootLinkName : link.name,
68 isRoot: !link.parentLinkId,
69 isReadOnly: isLinkReadOnly(link, rootShare.type),
76 const getPath = useCallback(
77 async (abortSignal: AbortSignal, shareId: string, linkId: string): Promise<string> => {
78 return traverseLinksToRoot(abortSignal, shareId, linkId)
80 return `/${path.map(({ name }) => name).join('/')}`;
83 return err.message || '';
95 export function useLinkPathPublic() {
96 const { getLink } = useLink();
97 // This is hack. Do not keep it around when moved properly to the state.
98 // When name of some parent changes, we need to update the location as
99 // well, but thats not part of the child link. Therefore, this function
100 // needs to be called any time the state changes. To not do too much
101 // work when its not needed, we cache the callbacks, for which we need
102 // the state. Once the location is part of the state, this whole hook
103 // will not be needed. The problem might be, that updating location for
104 // every link in the store might not be good as well, so that needs more
106 const { getLink: getCachedLink } = useLinksState();
108 const traverseLinksToRoot = useCallback(
109 async (abortSignal: AbortSignal, shareId: string, linkId: string): Promise<PathItem[]> => {
110 const path = await generateLinkPath(abortSignal, shareId, linkId, getLink);
112 return path.map((link) => ({
115 isRoot: !!link.parentLinkId,