110 lines
2.9 KiB
TypeScript
110 lines
2.9 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { createAssetView } from '../../asset_manager';
|
|
|
|
interface DocumentLike {
|
|
id?: string | number;
|
|
current_version?: unknown;
|
|
tags?: unknown;
|
|
}
|
|
|
|
interface AssetLike {
|
|
id?: string | number;
|
|
[key: string]: unknown;
|
|
}
|
|
|
|
interface PreviewMetadataEntry {
|
|
docId: string;
|
|
width: number;
|
|
height: number;
|
|
}
|
|
|
|
type GetDocumentAsset = (doc: DocumentLike, type: string) => AssetLike | null;
|
|
type EnsureAssetUrl = (docId: string | number, asset: AssetLike, options?: { start?: number; limit?: number }) => Promise<AssetLike | null>;
|
|
|
|
const usePreviewMetadata = (
|
|
documents: DocumentLike[] | null,
|
|
getDocumentAsset?: GetDocumentAsset,
|
|
ensureAssetUrl?: EnsureAssetUrl,
|
|
) => {
|
|
const [metadataMap, setMetadataMap] = useState<Map<string, PreviewMetadataEntry>>(() => new Map());
|
|
|
|
useEffect(() => {
|
|
let cancelled = false;
|
|
const docs = Array.isArray(documents) ? documents : [];
|
|
if (!docs.length) {
|
|
setMetadataMap(new Map());
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}
|
|
|
|
const fetchMetadataForDoc = async (doc: DocumentLike) => {
|
|
if (!doc?.id) {
|
|
return null;
|
|
}
|
|
|
|
const docId = String(doc.id);
|
|
const resolveAsset = (type: string) => getDocumentAsset?.(doc, type) ?? null;
|
|
|
|
let asset = resolveAsset('preview') || resolveAsset('thumbnail');
|
|
let view = createAssetView(asset);
|
|
let metadata = view.getPrimaryMetadata();
|
|
|
|
const hasDimensions = (meta: { width?: number | string; height?: number | string } | null) =>
|
|
Number.isFinite(Number(meta?.width)) &&
|
|
Number.isFinite(Number(meta?.height)) &&
|
|
Number(meta.width) > 0 &&
|
|
Number(meta.height) > 0;
|
|
|
|
if (!hasDimensions(metadata) && ensureAssetUrl && docId && asset?.id) {
|
|
try {
|
|
const ensured = await ensureAssetUrl(doc.id, asset, { start: 1, limit: 1 });
|
|
if (ensured) {
|
|
asset = ensured;
|
|
view = createAssetView(asset);
|
|
metadata = view.getPrimaryMetadata();
|
|
}
|
|
} catch (error) {
|
|
console.warn('[desk] ensureDocumentSize metadata fetch failed', error);
|
|
}
|
|
}
|
|
|
|
if (!hasDimensions(metadata)) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
docId,
|
|
width: Number(metadata.width),
|
|
height: Number(metadata.height),
|
|
};
|
|
};
|
|
|
|
let mounted = true;
|
|
(async () => {
|
|
const entries = await Promise.all(docs.map(fetchMetadataForDoc));
|
|
if (!mounted || cancelled) {
|
|
return;
|
|
}
|
|
const next = new Map();
|
|
entries.forEach((entry) => {
|
|
if (entry && entry.docId) {
|
|
next.set(entry.docId, entry);
|
|
}
|
|
});
|
|
if (!cancelled) {
|
|
setMetadataMap(next);
|
|
}
|
|
})();
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
mounted = false;
|
|
};
|
|
}, [documents, getDocumentAsset, ensureAssetUrl]);
|
|
|
|
return metadataMap;
|
|
};
|
|
|
|
export default usePreviewMetadata;
|