import { useCallback, useEffect, useRef } from 'react'; import type { Dispatch, MutableRefObject, SetStateAction, } from 'react'; import type { DocumentId } from '../types/identifiers'; type FolderId = DocumentId | 'root'; import type { Document } from '../types/documents'; type NavigateHandler = (path: string, options?: { replace?: boolean }) => void; interface UseDocumentPreviewArgs { routeDocumentId?: DocumentId | null; documentsManager: { getById: (id: DocumentId) => Document | null; ensure: (id: DocumentId) => Promise; getMany: (ids: DocumentId[]) => Document[]; subscribe: (listener: () => void) => () => void; ingest: (docs: unknown[]) => { canonical: Document[]; changed: boolean }; }; selectedFolder?: FolderId | null; notifyApiError: (error: unknown, message: string) => void; navigate: NavigateHandler; locationPathname: string; locationSearch: string; detailPanelControlRef: MutableRefObject<{ open?: (args?: { documentIds?: DocumentId[] }) => void; close?: () => void; } | null>; setActivePreviewId: Dispatch>; } interface UseDocumentPreviewResult { ensurePreviewData: (documentId: DocumentId) => Promise; openDocumentPreview: (documentId: DocumentId, options?: { replace?: boolean }) => void; closeDocumentPreview: (folderId?: FolderId) => void; resetPreviewState: () => void; } const useDocumentPreview = ({ routeDocumentId, documentsManager, selectedFolder, notifyApiError, navigate, locationPathname, locationSearch, detailPanelControlRef, setActivePreviewId, }: UseDocumentPreviewArgs): UseDocumentPreviewResult => { const previewReturnPathRef = useRef(null); const resetPreviewState = useCallback(() => { previewReturnPathRef.current = null; }, []); const ensurePreviewData = useCallback( async (documentId: DocumentId): Promise => { if (!documentId) return null; const doc = await documentsManager.ensure(documentId); if (!doc) { throw new Error('Document metadata unavailable.'); } if (!previewReturnPathRef.current) { const fallbackFolderId = doc?.folder_id || 'root'; previewReturnPathRef.current = fallbackFolderId === 'root' ? '/documents' : `/documents/folder/${fallbackFolderId}`; } setActivePreviewId(documentId); return doc; }, [ documentsManager, setActivePreviewId, ], ); const openDocumentPreview = useCallback( (documentId: DocumentId, { replace = false }: { replace?: boolean } = {}) => { if (!documentId) return; detailPanelControlRef.current?.close?.(); previewReturnPathRef.current = `${locationPathname}${locationSearch}`; navigate(`/documents/${documentId}`, { replace }); }, [navigate, locationPathname, locationSearch, detailPanelControlRef], ); const closeDocumentPreview = useCallback( (folderId?: FolderId) => { const fallbackPath = previewReturnPathRef.current; previewReturnPathRef.current = null; if (fallbackPath) { navigate(fallbackPath, { replace: false }); return; } const targetId = folderId || selectedFolder || 'root'; const path = targetId === 'root' ? '/documents' : `/documents/folder/${targetId}`; navigate(path, { replace: false }); }, [navigate, selectedFolder], ); useEffect(() => { if (!routeDocumentId) { return undefined; } let cancelled = false; ensurePreviewData(routeDocumentId).catch((error) => { if (cancelled) { return; } notifyApiError(error, 'Failed to open document preview.'); closeDocumentPreview(); }); return () => { cancelled = true; }; }, [routeDocumentId, ensurePreviewData, notifyApiError, closeDocumentPreview]); return { ensurePreviewData, openDocumentPreview, closeDocumentPreview, resetPreviewState, }; }; export default useDocumentPreview;