117 lines
2.6 KiB
TypeScript
117 lines
2.6 KiB
TypeScript
import { useEffect, useMemo, useState } from 'react';
|
|
import { resolveAssetUrl } from '../asset_manager';
|
|
import type { Identifier } from '../types/identifiers';
|
|
|
|
type DocumentLike = {
|
|
id?: Identifier;
|
|
[key: string]: unknown;
|
|
};
|
|
|
|
type AssetObject = {
|
|
url?: string | null;
|
|
metadata?: Record<string, unknown> | null;
|
|
expires_at?: number | null;
|
|
[key: string]: unknown;
|
|
};
|
|
|
|
type AssetLike = {
|
|
id?: Identifier;
|
|
url?: string | null;
|
|
expires_at?: number | null;
|
|
metadata?: Record<string, unknown> | null;
|
|
objects?: AssetObject[];
|
|
[key: string]: unknown;
|
|
};
|
|
|
|
type EnsureAssetUrl = (
|
|
documentId: Identifier,
|
|
asset: AssetLike,
|
|
options?: { force?: boolean;[key: string]: unknown },
|
|
) => Promise<unknown>;
|
|
|
|
type GetAsset = (document: DocumentLike, assetType: string) => AssetLike | null;
|
|
|
|
type AssetViewLike = {
|
|
url: string | null;
|
|
metadata: Record<string, unknown> | null;
|
|
};
|
|
|
|
interface UseAssetNavigatorOptions {
|
|
document?: DocumentLike | null;
|
|
assetType: string;
|
|
ensureAssetUrl?: EnsureAssetUrl | null;
|
|
getAsset?: GetAsset;
|
|
}
|
|
|
|
interface AssetNavigatorReturn {
|
|
document: DocumentLike | null;
|
|
documentId: Identifier | null;
|
|
asset: AssetLike | null;
|
|
assetType: string;
|
|
currentUrl: string | null;
|
|
currentMetadata: Record<string, unknown> | null;
|
|
isLoading: boolean;
|
|
}
|
|
|
|
export const useAssetNavigator = ({
|
|
document,
|
|
assetType,
|
|
ensureAssetUrl,
|
|
getAsset,
|
|
}: UseAssetNavigatorOptions): AssetNavigatorReturn => {
|
|
const documentId = (document?.id ?? null) as Identifier | null;
|
|
|
|
const asset = useMemo<AssetLike | null>(() => {
|
|
if (!document || !getAsset) {
|
|
return null;
|
|
}
|
|
return getAsset(document, assetType) || null;
|
|
}, [document, assetType, getAsset]);
|
|
|
|
const view = useMemo<AssetViewLike>(
|
|
() => ({
|
|
url: resolveAssetUrl(asset),
|
|
metadata: (asset?.metadata as Record<string, unknown> | null) || null,
|
|
}),
|
|
[asset],
|
|
);
|
|
|
|
const currentUrl = view.url || null;
|
|
const currentMetadata = view.metadata || null;
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (!ensureAssetUrl || !documentId || !asset) {
|
|
return undefined;
|
|
}
|
|
if (currentUrl) {
|
|
return undefined;
|
|
}
|
|
let cancelled = false;
|
|
setIsLoading(true);
|
|
ensureAssetUrl(documentId, asset, { force: true })
|
|
.catch(() => { })
|
|
.finally(() => {
|
|
if (!cancelled) {
|
|
setIsLoading(false);
|
|
}
|
|
});
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [asset, currentUrl, documentId, ensureAssetUrl]);
|
|
|
|
return {
|
|
document,
|
|
documentId,
|
|
asset,
|
|
assetType,
|
|
currentUrl,
|
|
currentMetadata,
|
|
isLoading,
|
|
};
|
|
};
|
|
|
|
export default useAssetNavigator;
|