documentsmanager
This commit is contained in:
@@ -36,8 +36,13 @@ type NavigateHandler = (path: string, options?: { replace?: boolean }) => void;
|
||||
|
||||
interface UseDocumentPreviewArgs {
|
||||
routeDocumentId?: DocumentId | null;
|
||||
documents: DocumentLike[];
|
||||
searchResults: DocumentLike[] | null;
|
||||
documentsManager: {
|
||||
getById: (id: DocumentId) => DocumentLike | null;
|
||||
ensure: (id: DocumentId) => Promise<DocumentLike | null>;
|
||||
getMany: (ids: DocumentId[]) => DocumentLike[];
|
||||
subscribe: (listener: () => void) => () => void;
|
||||
ingest: (docs: unknown[]) => { canonical: DocumentLike[]; changed: boolean };
|
||||
};
|
||||
selectedFolder?: FolderId | null;
|
||||
assetManager: AssetManagerLike;
|
||||
api: ApiClient;
|
||||
@@ -55,7 +60,6 @@ interface UseDocumentPreviewArgs {
|
||||
|
||||
interface UseDocumentPreviewResult {
|
||||
documentLinks: Map<DocumentId, DocumentLink>;
|
||||
previewDocuments: Map<DocumentId, DocumentLike>;
|
||||
ensureDownloadUrl: (documentId: DocumentId, options?: { force?: boolean }) => Promise<DocumentLink | null>;
|
||||
ensurePreviewData: (documentId: DocumentId) => Promise<DocumentLike | null>;
|
||||
openDocumentPreview: (documentId: DocumentId, options?: { replace?: boolean }) => void;
|
||||
@@ -66,10 +70,9 @@ interface UseDocumentPreviewResult {
|
||||
|
||||
const useDocumentPreview = ({
|
||||
routeDocumentId,
|
||||
documents,
|
||||
searchResults,
|
||||
documentsManager,
|
||||
selectedFolder,
|
||||
assetManager,
|
||||
assetManager: _assetManager,
|
||||
api,
|
||||
resolveApiPath,
|
||||
notifyApiError,
|
||||
@@ -80,7 +83,6 @@ const useDocumentPreview = ({
|
||||
setActivePreviewId,
|
||||
}: UseDocumentPreviewArgs): UseDocumentPreviewResult => {
|
||||
const [documentLinks, setDocumentLinks] = useState<Map<DocumentId, DocumentLink>>(() => new Map());
|
||||
const [previewDocuments, setPreviewDocuments] = useState<Map<DocumentId, DocumentLike>>(() => new Map());
|
||||
const previewInflightRef = useRef<Map<DocumentId, Promise<DocumentLink | null>>>(new Map());
|
||||
const previewReturnPathRef = useRef<string | null>(null);
|
||||
|
||||
@@ -110,35 +112,6 @@ const useDocumentPreview = ({
|
||||
});
|
||||
}, []);
|
||||
|
||||
const cachePreviewDocument = useCallback((doc: DocumentLike) => {
|
||||
if (!doc?.id) {
|
||||
return;
|
||||
}
|
||||
setPreviewDocuments((prev) => {
|
||||
const existing = prev.get(doc.id);
|
||||
if (existing === doc) {
|
||||
return prev;
|
||||
}
|
||||
const next = new Map(prev);
|
||||
next.set(doc.id, doc);
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const removeCachedPreviewDocument = useCallback((documentId: DocumentId) => {
|
||||
if (!documentId) {
|
||||
return;
|
||||
}
|
||||
setPreviewDocuments((prev) => {
|
||||
if (!prev.has(documentId)) {
|
||||
return prev;
|
||||
}
|
||||
const next = new Map(prev);
|
||||
next.delete(documentId);
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const ensureDownloadUrl = useCallback(
|
||||
async (documentId: DocumentId, { force = false }: { force?: boolean } = {}): Promise<DocumentLink | null> => {
|
||||
if (!documentId) return null;
|
||||
@@ -193,32 +166,22 @@ const useDocumentPreview = ({
|
||||
async (documentId: DocumentId): Promise<DocumentLike | null> => {
|
||||
if (!documentId) return null;
|
||||
|
||||
const findInCache = () => {
|
||||
const pool = searchResults ?? documents;
|
||||
return pool.find((item) => item.id === documentId) || null;
|
||||
};
|
||||
const findInCache = () => documentsManager.getById(documentId);
|
||||
|
||||
let doc = findInCache();
|
||||
|
||||
if (!doc) {
|
||||
doc = await documentsManager.ensure(documentId);
|
||||
}
|
||||
|
||||
if (!doc) {
|
||||
const { data } = await api.get(`/documents/${documentId}`);
|
||||
const hydratedDetail = assetManager.hydrateDetail(data);
|
||||
const fetched = hydratedDetail?.document || (data as { document?: DocumentLike })?.document || data;
|
||||
doc = fetched ? assetManager.hydrateDocument(fetched) || null : null;
|
||||
const fetched = (data as { document?: DocumentLike })?.document || data;
|
||||
const { canonical } = documentsManager.ingest([fetched as unknown]);
|
||||
doc = (canonical[0] as DocumentLike | undefined) || null;
|
||||
if (!doc) {
|
||||
throw new Error('Document metadata unavailable.');
|
||||
}
|
||||
|
||||
const existsInDocuments = documents.some((item) => item.id === doc?.id);
|
||||
const existsInSearch = Array.isArray(searchResults)
|
||||
? searchResults.some((item) => item.id === doc?.id)
|
||||
: false;
|
||||
|
||||
if (doc?.id && (existsInDocuments || existsInSearch)) {
|
||||
removeCachedPreviewDocument(doc.id);
|
||||
} else {
|
||||
cachePreviewDocument(doc);
|
||||
}
|
||||
}
|
||||
|
||||
if (!previewReturnPathRef.current) {
|
||||
@@ -232,14 +195,10 @@ const useDocumentPreview = ({
|
||||
return doc;
|
||||
},
|
||||
[
|
||||
searchResults,
|
||||
documents,
|
||||
assetManager,
|
||||
documentsManager,
|
||||
ensureDownloadUrl,
|
||||
setActivePreviewId,
|
||||
api,
|
||||
cachePreviewDocument,
|
||||
removeCachedPreviewDocument,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -270,21 +229,6 @@ const useDocumentPreview = ({
|
||||
[navigate, selectedFolder],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!routeDocumentId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === 'Escape') {
|
||||
closeDocumentPreview();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
return () => window.removeEventListener('keydown', handleKeyDown);
|
||||
}, [routeDocumentId, closeDocumentPreview]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!routeDocumentId) {
|
||||
return undefined;
|
||||
@@ -305,33 +249,8 @@ const useDocumentPreview = ({
|
||||
};
|
||||
}, [routeDocumentId, ensurePreviewData, notifyApiError, closeDocumentPreview]);
|
||||
|
||||
useEffect(() => {
|
||||
setPreviewDocuments((prev) => {
|
||||
if (!prev.size) {
|
||||
return prev;
|
||||
}
|
||||
const next = new Map(prev);
|
||||
let changed = false;
|
||||
const prune = (list?: DocumentLike[] | null) => {
|
||||
if (!Array.isArray(list)) {
|
||||
return;
|
||||
}
|
||||
list.forEach((doc) => {
|
||||
if (doc?.id && next.has(doc.id)) {
|
||||
next.delete(doc.id);
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
prune(documents);
|
||||
prune(searchResults);
|
||||
return changed ? next : prev;
|
||||
});
|
||||
}, [documents, searchResults]);
|
||||
|
||||
return {
|
||||
documentLinks,
|
||||
previewDocuments,
|
||||
ensureDownloadUrl,
|
||||
ensurePreviewData,
|
||||
openDocumentPreview,
|
||||
|
||||
Reference in New Issue
Block a user