feat: Centralize document preview logic into useDocumentPreview and add correspondentLookupByName to useCorrespondents

This commit is contained in:
2025-12-10 02:33:22 +01:00
parent ed8450c0e2
commit b9f0278329
8 changed files with 69 additions and 125 deletions
+14 -1
View File
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useRef } from 'react'; import { useCallback, useEffect, useRef, useMemo } from 'react';
import type { import type {
Dispatch, Dispatch,
MutableRefObject, MutableRefObject,
@@ -36,6 +36,8 @@ interface UseDocumentPreviewResult {
openDocumentPreview: (documentId: DocumentId, options?: { replace?: boolean }) => void; openDocumentPreview: (documentId: DocumentId, options?: { replace?: boolean }) => void;
closeDocumentPreview: (folderId?: FolderId) => void; closeDocumentPreview: (folderId?: FolderId) => void;
resetPreviewState: () => void; resetPreviewState: () => void;
previewWorkspaceDocument: Document | null;
previewActive: boolean;
} }
const useDocumentPreview = ({ const useDocumentPreview = ({
@@ -127,11 +129,22 @@ const useDocumentPreview = ({
}; };
}, [routeDocumentId, ensurePreviewData, notifyApiError, closeDocumentPreview]); }, [routeDocumentId, ensurePreviewData, notifyApiError, closeDocumentPreview]);
const previewWorkspaceDocument = useMemo(() => {
if (!routeDocumentId) {
return null;
}
return documentsManager.getById(routeDocumentId);
}, [routeDocumentId, documentsManager]);
const previewActive = Boolean(routeDocumentId && previewWorkspaceDocument);
return { return {
ensurePreviewData, ensurePreviewData,
openDocumentPreview, openDocumentPreview,
closeDocumentPreview, closeDocumentPreview,
resetPreviewState, resetPreviewState,
previewWorkspaceDocument,
previewActive,
}; };
}; };
+1
View File
@@ -19,6 +19,7 @@ interface UseManagementModalsArgs {
onTagDelete?: (...args: any[]) => void | Promise<void>; onTagDelete?: (...args: any[]) => void | Promise<void>;
correspondents?: Correspondent[]; correspondents?: Correspondent[];
correspondentLookupById?: Map<Identifier, Correspondent> | null; correspondentLookupById?: Map<Identifier, Correspondent> | null;
correspondentLookupByName?: Map<string, Correspondent> | null;
refreshCorrespondents?: () => void | Promise<void>; refreshCorrespondents?: () => void | Promise<void>;
onCorrespondentCreate?: (...args: any[]) => void | Promise<void>; onCorrespondentCreate?: (...args: any[]) => void | Promise<void>;
onCorrespondentUpdate?: (...args: any[]) => void | Promise<void>; onCorrespondentUpdate?: (...args: any[]) => void | Promise<void>;
@@ -1,4 +1,4 @@
import { useCallback, useSyncExternalStore } from 'react'; import { useCallback, useSyncExternalStore, useMemo } from 'react';
import { useStatusToast } from '../../lib/context/StatusToastContext'; import { useStatusToast } from '../../lib/context/StatusToastContext';
import type { Correspondent } from '../../types/documents'; import type { Correspondent } from '../../types/documents';
import type { Identifier } from '../../types/identifiers'; import type { Identifier } from '../../types/identifiers';
@@ -114,9 +114,20 @@ const useCorrespondents = ({
[documentsManager, notifyApiError, correspondentManager, showToast], [documentsManager, notifyApiError, correspondentManager, showToast],
); );
const correspondentLookupByName = useMemo(() => {
const map = new Map<string, Correspondent>();
for (const correspondent of correspondents) {
if (correspondent.name) {
map.set(correspondent.name.toLowerCase(), correspondent);
}
}
return map;
}, [correspondents]);
return { return {
correspondents, correspondents,
correspondentLookupById: correspondentsSnapshot, correspondentLookupById: correspondentsSnapshot,
correspondentLookupByName,
refreshCorrespondents, refreshCorrespondents,
handleCorrespondentCreate, handleCorrespondentCreate,
handleCorrespondentUpdate, handleCorrespondentUpdate,
@@ -1,4 +1,4 @@
import { useCallback, useMemo } from 'react'; import { useCallback } from 'react';
import { useStatusToast } from '../../lib/context/StatusToastContext'; import { useStatusToast } from '../../lib/context/StatusToastContext';
import type { Identifier } from '../../types/identifiers'; import type { Identifier } from '../../types/identifiers';
import type { Correspondent } from '../../types/documents'; import type { Correspondent } from '../../types/documents';
@@ -21,22 +21,12 @@ const useDocumentCorrespondentMutations = ({
const notifyApiError = useNotifyApiError(); const notifyApiError = useNotifyApiError();
const { const {
correspondents,
correspondentManager, correspondentManager,
correspondentLookupByName,
} = correspondentsState; } = correspondentsState;
const { documentsManager } = documentsState; const { documentsManager } = documentsState;
const correspondentLookupByName = useMemo(() => {
const map = new Map<string, Correspondent>();
correspondents.forEach((correspondent) => {
if (correspondent?.name) {
map.set(correspondent.name.toLowerCase(), correspondent);
}
});
return map;
}, [correspondents]);
const handleDocumentCorrespondentAttach = useCallback( const handleDocumentCorrespondentAttach = useCallback(
async ( async (
{ {
@@ -17,7 +17,6 @@ import type {
SelectionState, SelectionState,
TagsState, TagsState,
CorrespondentsState, CorrespondentsState,
ActionsState,
} from '../types/workspaceTypes'; } from '../types/workspaceTypes';
import type { Tag, Correspondent } from '../../types/documents'; import type { Tag, Correspondent } from '../../types/documents';
import useDocumentCorrespondentMutations from './useDocumentCorrespondentMutations'; import useDocumentCorrespondentMutations from './useDocumentCorrespondentMutations';
@@ -36,7 +35,7 @@ interface UseDocumentMutationsArgs {
selectionState: SelectionState; selectionState: SelectionState;
tagsState: TagsState; tagsState: TagsState;
correspondentsState: CorrespondentsState; correspondentsState: CorrespondentsState;
actions: ActionsState; closeDocumentPreview: () => void;
previewDocumentId?: DocumentId | null; previewDocumentId?: DocumentId | null;
} }
@@ -68,7 +67,6 @@ interface UseDocumentMutationsResult {
handleDocumentCorrespondentAttach: (args: { documentId: DocumentId; correspondentId: DocumentId; correspondent?: Correspondent | Partial<Correspondent> | null }) => Promise<boolean>; handleDocumentCorrespondentAttach: (args: { documentId: DocumentId; correspondentId: DocumentId; correspondent?: Correspondent | Partial<Correspondent> | null }) => Promise<boolean>;
handleDocumentCorrespondentDetach: (args: { documentId: DocumentId; correspondentId: DocumentId }) => Promise<boolean>; handleDocumentCorrespondentDetach: (args: { documentId: DocumentId; correspondentId: DocumentId }) => Promise<boolean>;
handleDocumentCorrespondentAdd: (args: { document: { id?: string }; name?: string; input?: HTMLInputElement | null; option?: Correspondent | Partial<Correspondent> | string | null }) => Promise<void>; handleDocumentCorrespondentAdd: (args: { document: { id?: string }; name?: string; input?: HTMLInputElement | null; option?: Correspondent | Partial<Correspondent> | string | null }) => Promise<void>;
correspondentLookupByName: Map<string, Correspondent>;
} }
const useDocumentMutations = ({ const useDocumentMutations = ({
@@ -77,7 +75,7 @@ const useDocumentMutations = ({
selectionState, selectionState,
tagsState, tagsState,
correspondentsState, correspondentsState,
actions, closeDocumentPreview,
previewDocumentId, previewDocumentId,
}: UseDocumentMutationsArgs): UseDocumentMutationsResult => { }: UseDocumentMutationsArgs): UseDocumentMutationsResult => {
const { showToast } = useStatusToast(); const { showToast } = useStatusToast();
@@ -102,7 +100,6 @@ const useDocumentMutations = ({
handleDocumentCorrespondentAttach, handleDocumentCorrespondentAttach,
handleDocumentCorrespondentDetach, handleDocumentCorrespondentDetach,
handleDocumentCorrespondentAdd, handleDocumentCorrespondentAdd,
correspondentLookupByName,
} = useDocumentCorrespondentMutations({ } = useDocumentCorrespondentMutations({
correspondentsState, correspondentsState,
documentsState: { documentsManager: documentsState.documentsManager }, documentsState: { documentsManager: documentsState.documentsManager },
@@ -115,13 +112,13 @@ const useDocumentMutations = ({
showToast('Analysis queued.', 'info'); showToast('Analysis queued.', 'info');
// Close preview if it's the current one to allow refresh? // Close preview if it's the current one to allow refresh?
if (previewDocumentId === documentId) { if (previewDocumentId === documentId) {
actions.closeDocumentPreview(); closeDocumentPreview();
} }
} catch (error) { } catch (error) {
notifyApiError(error, 'Failed to queue analysis.'); notifyApiError(error, 'Failed to queue analysis.');
} }
}, },
[actions, notifyApiError, previewDocumentId, showToast], [closeDocumentPreview, notifyApiError, previewDocumentId, showToast],
); );
const handleDocumentsDelete = useCallback( const handleDocumentsDelete = useCallback(
@@ -240,7 +237,6 @@ const useDocumentMutations = ({
handleDocumentCorrespondentAttach, handleDocumentCorrespondentAttach,
handleDocumentCorrespondentDetach, handleDocumentCorrespondentDetach,
handleDocumentCorrespondentAdd, handleDocumentCorrespondentAdd,
correspondentLookupByName,
}; };
}; };
@@ -273,6 +273,13 @@ const useDocumentsWorkspace = ({
foldersManager, foldersManager,
}; };
const resolveFolderPath = useCallback(
(folderId) => {
return resolveBreadcrumbs(folderId || 'root', folderNodes as any);
},
[folderNodes],
);
const [currentSubfolders, setCurrentSubfolders] = useState<Array<{ id?: FolderNodeId; name?: string | null;[key: string]: unknown }>>([]); const [currentSubfolders, setCurrentSubfolders] = useState<Array<{ id?: FolderNodeId; name?: string | null;[key: string]: unknown }>>([]);
const foldersSnapshot = useSyncExternalStore( const foldersSnapshot = useSyncExternalStore(
@@ -384,18 +391,7 @@ const useDocumentsWorkspace = ({
} }
}, [selectedFolder, documentsSortField, documentsSortDirection, fetchFolderData, updateViewState, notifyApiError]); }, [selectedFolder, documentsSortField, documentsSortDirection, fetchFolderData, updateViewState, notifyApiError]);
const { const documentsSearch = useDocumentsSearch({
searchQuery,
setSearchQuery,
searchResultIds,
setSearchResultIds,
searchLoading,
activeTagFilters,
setActiveTagFilters,
activeCorrespondentFilters,
setActiveCorrespondentFilters,
documentsFilterValue,
} = useDocumentsSearch({
api: apiClient, api: apiClient,
selectedFolder, selectedFolder,
locationPathname: location.pathname, locationPathname: location.pathname,
@@ -407,8 +403,8 @@ const useDocumentsWorkspace = ({
documentsManager, documentsManager,
}); });
const documentsFilter = documentsFilterValue; const documentsFilter = documentsSearch.documentsFilterValue;
const showingSearchResults = searchResultIds !== null; const showingSearchResults = documentsSearch.searchResultIds !== null;
// Live Filter: Ensure we only show documents that actually belong to the current folder. // Live Filter: Ensure we only show documents that actually belong to the current folder.
// Since 'documents' is reactive, if a document is moved, its folder_id updates immediately. // Since 'documents' is reactive, if a document is moved, its folder_id updates immediately.
@@ -431,7 +427,7 @@ const useDocumentsWorkspace = ({
} = useWorkspaceViewData({ } = useWorkspaceViewData({
documents: liveFilteredDocuments, documents: liveFilteredDocuments,
documentLookup, documentLookup,
searchResultIds, searchResultIds: documentsSearch.searchResultIds,
showingSearchResults, showingSearchResults,
currentSubfolders: visibleSubfolders, currentSubfolders: visibleSubfolders,
}); });
@@ -440,6 +436,8 @@ const useDocumentsWorkspace = ({
openDocumentPreview, openDocumentPreview,
closeDocumentPreview, closeDocumentPreview,
resetPreviewState, resetPreviewState,
previewWorkspaceDocument,
previewActive,
} = useDocumentPreview({ } = useDocumentPreview({
routeDocumentId: previewDocumentId, routeDocumentId: previewDocumentId,
documentsManager, documentsManager,
@@ -471,7 +469,7 @@ const useDocumentsWorkspace = ({
useWorkspaceSelectionSync({ useWorkspaceSelectionSync({
showingSearchResults, showingSearchResults,
searchQuery, searchQuery: documentsSearch.searchQuery,
setSelectedEntries, setSelectedEntries,
setSelectionOrder, setSelectionOrder,
selectionOrderRef, selectionOrderRef,
@@ -486,7 +484,7 @@ const useDocumentsWorkspace = ({
const tagsState = useTags({ const tagsState = useTags({
tenantIdRef, tenantIdRef,
tagManager, tagManager,
setActiveTagFilters, setActiveTagFilters: documentsSearch.setActiveTagFilters,
documentsManager, documentsManager,
}); });
@@ -584,10 +582,10 @@ const useDocumentsWorkspace = ({
selectionAnchorRef.current = null; selectionAnchorRef.current = null;
setDraggedDocumentIds([]); setDraggedDocumentIds([]);
setDraggedFolderId(null); setDraggedFolderId(null);
setSearchResultIds(null); documentsSearch.setSearchResultIds(null);
setSearchQuery(''); documentsSearch.setSearchQuery('');
setActiveTagFilters([]); documentsSearch.setActiveTagFilters([]);
setActiveCorrespondentFilters([]); documentsSearch.setActiveCorrespondentFilters([]);
setActivePreviewId(null); setActivePreviewId(null);
detailPanelControlRef.current.close(); detailPanelControlRef.current.close();
assetManager.reset(); assetManager.reset();
@@ -612,10 +610,7 @@ const useDocumentsWorkspace = ({
setDocuments, setDocuments,
setDraggedDocumentIds, setDraggedDocumentIds,
setDraggedFolderId, setDraggedFolderId,
setSearchResultIds, documentsSearch,
setSearchQuery,
setActiveTagFilters,
setActiveCorrespondentFilters,
setActivePreviewId, setActivePreviewId,
resetPreviewState, resetPreviewState,
upload, upload,
@@ -631,16 +626,12 @@ const useDocumentsWorkspace = ({
const documentsState = { const documentsState = {
documentLookup, documentLookup,
setDocuments, setDocuments,
setSearchResultIds, setSearchResultIds: documentsSearch.setSearchResultIds,
documentsManager, documentsManager,
extractDocumentFromResponse, extractDocumentFromResponse,
ingestDocuments: (docs: unknown[]) => documentsManager.ingest(docs), ingestDocuments: (docs: unknown[]) => documentsManager.ingest(docs),
}; };
const actionsState = {
closeDocumentPreview,
};
const documentMutationsResult = useDocumentMutations({ const documentMutationsResult = useDocumentMutations({
documentsState, documentsState,
folderState, folderState,
@@ -653,13 +644,12 @@ const useDocumentsWorkspace = ({
...correspondentsState, ...correspondentsState,
correspondentManager, correspondentManager,
}, },
actions: actionsState, closeDocumentPreview,
previewDocumentId, previewDocumentId,
}); });
const { const {
moveDocumentsToFolder, moveDocumentsToFolder,
handleThumbnailRegeneration,
handleDocumentsDelete, handleDocumentsDelete,
handleDocumentTagAdd, handleDocumentTagAdd,
handleDocumentTagAttach, handleDocumentTagAttach,
@@ -669,7 +659,6 @@ const useDocumentsWorkspace = ({
handleDocumentCorrespondentAttach, handleDocumentCorrespondentAttach,
handleDocumentCorrespondentDetach, handleDocumentCorrespondentDetach,
handleDocumentCorrespondentAdd, handleDocumentCorrespondentAdd,
correspondentLookupByName,
} = documentMutationsResult; } = documentMutationsResult;
const mutations = { const mutations = {
@@ -802,7 +791,7 @@ const useDocumentsWorkspace = ({
handleDeleteSelection, handleDeleteSelection,
} = useBulkDocumentActions({ } = useBulkDocumentActions({
resolveTargetDocumentIds, resolveTargetDocumentIds,
correspondentLookupByName, correspondentLookupByName: correspondentsState.correspondentLookupByName,
handleCorrespondentCreate: correspondentsState.handleCorrespondentCreate, handleCorrespondentCreate: correspondentsState.handleCorrespondentCreate,
selectedDocumentIds, selectedDocumentIds,
selectedFolderIds, selectedFolderIds,
@@ -874,7 +863,8 @@ const useDocumentsWorkspace = ({
onTagDelete: async (tagId: string) => { await tagsState.handleTagDelete(tagId); }, onTagDelete: async (tagId: string) => { await tagsState.handleTagDelete(tagId); },
correspondents: correspondentsState.correspondents, correspondents: correspondentsState.correspondents,
correspondentLookupById: correspondentsState.correspondentLookupById, correspondentLookupById: correspondentsState.correspondentLookupById,
refreshCorrespondents: correspondentsState.refreshCorrespondents, correspondentLookupByName: correspondentsState.correspondentLookupByName,
refreshCorrespondents,
onCorrespondentCreate: correspondentsState.handleCorrespondentCreate, onCorrespondentCreate: correspondentsState.handleCorrespondentCreate,
onCorrespondentUpdate: correspondentsState.handleCorrespondentUpdate, onCorrespondentUpdate: correspondentsState.handleCorrespondentUpdate,
onCorrespondentDelete: correspondentsState.handleCorrespondentDelete, onCorrespondentDelete: correspondentsState.handleCorrespondentDelete,
@@ -903,21 +893,11 @@ const useDocumentsWorkspace = ({
return () => window.removeEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown);
}, [settingsOpen]); }, [settingsOpen]);
const { const detailPanel = useDetailWorkspace({
detailPanelProps,
detailPanelOpen,
openDetailPanel,
previewActive,
previewWorkspaceDocument,
resolveFolderPath,
} = useDetailWorkspace({
documents: viewDocuments,
documentLookup, documentLookup,
folderNodes, folderNodes,
detailPanelControlRef, detailPanelControlRef,
detailFolderFetchRef, detailFolderFetchRef,
previewDocumentId,
activePreviewId,
openDocumentPreview: openDocumentPreviewForDetail, openDocumentPreview: openDocumentPreviewForDetail,
handleDocumentTitleUpdate, handleDocumentTitleUpdate,
handleDocumentIssuedUpdate, handleDocumentIssuedUpdate,
@@ -932,6 +912,7 @@ const useDocumentsWorkspace = ({
tags: tagsState.tags, tags: tagsState.tags,
tagLookupById: tagsState.tagLookupById, tagLookupById: tagsState.tagLookupById,
correspondentLookupById: correspondentsState.correspondentLookupById, correspondentLookupById: correspondentsState.correspondentLookupById,
resolveFolderPath,
}); });
const handleEntryPointerCore = useEntryPointerCore({ const handleEntryPointerCore = useEntryPointerCore({
@@ -985,7 +966,7 @@ const useDocumentsWorkspace = ({
const tags = { const tags = {
...tagsState, ...tagsState,
tagManager, tagManager,
activeTagFilters, activeTagFilters: documentsSearch.activeTagFilters,
// Add derived/action handlers that were previously in tagsContext // Add derived/action handlers that were previously in tagsContext
handleDocumentTagAttach, handleDocumentTagAttach,
handleDocumentTagDetach, handleDocumentTagDetach,
@@ -996,7 +977,7 @@ const useDocumentsWorkspace = ({
const correspondents = { const correspondents = {
...correspondentsState, ...correspondentsState,
activeCorrespondentFilters, activeCorrespondentFilters: documentsSearch.activeCorrespondentFilters,
// Add derived/action handlers // Add derived/action handlers
handleDocumentCorrespondentAttach, handleDocumentCorrespondentAttach,
handleDocumentCorrespondentDetach, handleDocumentCorrespondentDetach,
@@ -1013,26 +994,19 @@ const useDocumentsWorkspace = ({
closeDocumentPreview, closeDocumentPreview,
ensureAssetUrl, ensureAssetUrl,
getDocumentAsset, getDocumentAsset,
handleThumbnailRegeneration,
};
const detailPanel = {
detailPanelProps,
detailPanelOpen,
openDetailPanel,
}; };
const search = { const search = {
searchQuery, searchQuery: documentsSearch.searchQuery,
documentsFilter, documentsFilter,
searchLoading, searchLoading: documentsSearch.searchLoading,
documentsViewMode, documentsViewMode,
handleDocumentsViewModeChange, handleDocumentsViewModeChange,
documentsSortField, documentsSortField,
documentsSortDirection, documentsSortDirection,
handleDocumentsSortFieldChange, handleDocumentsSortFieldChange,
handleDocumentsSortDirectionToggle, handleDocumentsSortDirectionToggle,
searchResultIds, searchResultIds: documentsSearch.searchResultIds,
documents: viewDocuments, documents: viewDocuments,
}; };
@@ -22,8 +22,6 @@ export interface DocumentsManagerInterface {
remove(ids: Array<DocumentId>): boolean; remove(ids: Array<DocumentId>): boolean;
} }
type CloseDocumentPreview = () => void;
export interface DocumentsState { export interface DocumentsState {
documentLookup: Map<DocumentId, Document>; documentLookup: Map<DocumentId, Document>;
setDocuments: Dispatch<SetStateAction<Document[]>>; setDocuments: Dispatch<SetStateAction<Document[]>>;
@@ -62,16 +60,11 @@ export interface TagsState {
export interface CorrespondentsState { export interface CorrespondentsState {
correspondents: Correspondent[]; correspondents: Correspondent[];
correspondentLookupById: Map<Identifier, Correspondent>; correspondentLookupById: Map<Identifier, Correspondent>;
correspondentLookupByName?: Map<string, Correspondent>;
refreshCorrespondents: () => Promise<void>; refreshCorrespondents: () => Promise<void>;
correspondentManager: CorrespondentManager; correspondentManager: CorrespondentManager;
} }
export interface ActionsState {
closeDocumentPreview: CloseDocumentPreview;
handleFileDrop?: (dataTransfer: DataTransfer, folderId: FolderId) => Promise<void> | void;
moveDocumentsToFolder?: (docIds: FolderId[], folderId: FolderId) => Promise<void>;
}
export interface DragState { export interface DragState {
draggedDocumentIds: DocumentId[]; draggedDocumentIds: DocumentId[];
draggedFolderId: FolderId | null; draggedFolderId: FolderId | null;
@@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo } from 'react'; import { useCallback, useEffect } from 'react';
import type { MutableRefObject } from 'react'; import type { MutableRefObject } from 'react';
import { resolveDocumentAssetUrl } from '../../lib/assets/AssetManager'; import { resolveDocumentAssetUrl } from '../../lib/assets/AssetManager';
import { useDetailPanel } from '../../app/useDetailPanel'; import { useDetailPanel } from '../../app/useDetailPanel';
@@ -6,7 +6,6 @@ import type { DocumentInfoPanelProps } from '../components/DocumentInfoPanel';
import type { EnsureAssetUrl, GetAsset } from '../../lib/assets/AssetManager'; import type { EnsureAssetUrl, GetAsset } from '../../lib/assets/AssetManager';
import type { Identifier } from '../../types/identifiers'; import type { Identifier } from '../../types/identifiers';
import type { Document } from '../../types/documents'; import type { Document } from '../../types/documents';
import { resolveBreadcrumbs } from '../../documents/logic/breadcrumbs';
import type { Tag, Correspondent } from '../../types/documents'; import type { Tag, Correspondent } from '../../types/documents';
import { listFolderContents } from '../../lib/api/apiClient'; import { listFolderContents } from '../../lib/api/apiClient';
import { useStatusToast } from '../../lib/context/StatusToastContext'; import { useStatusToast } from '../../lib/context/StatusToastContext';
@@ -19,13 +18,10 @@ interface FolderNode {
} }
interface UseDetailWorkspaceArgs { interface UseDetailWorkspaceArgs {
documents: Document[];
documentLookup: Map<Identifier, Document>; documentLookup: Map<Identifier, Document>;
folderNodes: Map<Identifier | 'root', FolderNode>; folderNodes: Map<Identifier | 'root', FolderNode>;
detailPanelControlRef: MutableRefObject<{ open?: (documentId: Identifier) => void; close?: () => void } | null>; detailPanelControlRef: MutableRefObject<{ open?: (documentId: Identifier) => void; close?: () => void } | null>;
detailFolderFetchRef: MutableRefObject<Set<Identifier | 'root'>>; detailFolderFetchRef: MutableRefObject<Set<Identifier | 'root'>>;
previewDocumentId?: Identifier | null;
activePreviewId?: Identifier | null;
openDocumentPreview?: (args: { documentIds: Identifier[] }) => void; openDocumentPreview?: (args: { documentIds: Identifier[] }) => void;
handleDocumentTitleUpdate?: (docId: Identifier, title: string) => Promise<boolean> | boolean; handleDocumentTitleUpdate?: (docId: Identifier, title: string) => Promise<boolean> | boolean;
handleDocumentIssuedUpdate?: (docId: Identifier, issued: number | null) => Promise<boolean> | boolean; handleDocumentIssuedUpdate?: (docId: Identifier, issued: number | null) => Promise<boolean> | boolean;
@@ -40,6 +36,7 @@ interface UseDetailWorkspaceArgs {
tags?: unknown[]; tags?: unknown[];
tagLookupById?: Map<Identifier, Tag> | null; tagLookupById?: Map<Identifier, Tag> | null;
correspondentLookupById?: Map<Identifier, Correspondent> | null; correspondentLookupById?: Map<Identifier, Correspondent> | null;
resolveFolderPath?: (folderId?: Identifier | 'root') => Array<{ id: Identifier | 'root'; name: string }>;
} }
interface UseDetailWorkspaceResult { interface UseDetailWorkspaceResult {
@@ -49,20 +46,15 @@ interface UseDetailWorkspaceResult {
closeDetailPanel: ReturnType<typeof useDetailPanel>['closeDetailPanel']; closeDetailPanel: ReturnType<typeof useDetailPanel>['closeDetailPanel'];
handleDetailPanelClose: () => void; handleDetailPanelClose: () => void;
inspectDocument: (docId: Identifier | null) => void; inspectDocument: (docId: Identifier | null) => void;
previewActive: boolean;
previewWorkspaceDocument: Document | null;
resolveThumbnailUrlForDoc: (doc: Document | null) => string | null; resolveThumbnailUrlForDoc: (doc: Document | null) => string | null;
resolveFolderPath: (folderId?: Identifier | 'root') => Array<{ id: Identifier | 'root'; name: string }>; resolveFolderPath: (folderId?: Identifier | 'root') => Array<{ id: Identifier | 'root'; name: string }>;
} }
const useDetailWorkspace = ({ const useDetailWorkspace = ({
documents,
documentLookup, documentLookup,
folderNodes, folderNodes,
detailPanelControlRef, detailPanelControlRef,
detailFolderFetchRef, detailFolderFetchRef,
previewDocumentId,
activePreviewId,
openDocumentPreview, openDocumentPreview,
handleDocumentTitleUpdate, handleDocumentTitleUpdate,
handleDocumentIssuedUpdate, handleDocumentIssuedUpdate,
@@ -77,6 +69,7 @@ const useDetailWorkspace = ({
tags, tags,
tagLookupById, tagLookupById,
correspondentLookupById, correspondentLookupById,
resolveFolderPath,
}: UseDetailWorkspaceArgs): UseDetailWorkspaceResult => { }: UseDetailWorkspaceArgs): UseDetailWorkspaceResult => {
const { showToast } = useStatusToast(); const { showToast } = useStatusToast();
const notifyApiError = useNotifyApiError(); const notifyApiError = useNotifyApiError();
@@ -97,12 +90,6 @@ const useDetailWorkspace = ({
}; };
}, [detailPanelControlRef, openDetailPanel, closeDetailPanel]); }, [detailPanelControlRef, openDetailPanel, closeDetailPanel]);
useEffect(() => {
if (detailPanelOpen && activePreviewId) {
openDetailPanel(activePreviewId);
}
}, [detailPanelOpen, activePreviewId, openDetailPanel]);
// Prefetch folder ancestors for breadcrumb display // Prefetch folder ancestors for breadcrumb display
useEffect(() => { useEffect(() => {
const folderId = detailPanelDocument?.folder_id; const folderId = detailPanelDocument?.folder_id;
@@ -144,24 +131,6 @@ const useDetailWorkspace = ({
} }
}, [detailPanelDocument, folderNodes, detailFolderFetchRef]); }, [detailPanelDocument, folderNodes, detailFolderFetchRef]);
const resolveFolderPath = useCallback(
(folderId) => {
return resolveBreadcrumbs(folderId || 'root', folderNodes as any);
},
[folderNodes],
);
const previewWorkspaceDocument = useMemo(() => {
if (!previewDocumentId) {
return null;
}
return documentLookup.get(previewDocumentId)
|| documents.find((doc) => doc.id === previewDocumentId)
|| null;
}, [previewDocumentId, documentLookup, documents]);
const previewActive = Boolean(previewDocumentId && previewWorkspaceDocument);
const resolveThumbnailUrlForDoc = useCallback( const resolveThumbnailUrlForDoc = useCallback(
(doc) => (doc) =>
resolveDocumentAssetUrl(doc, 'thumbnail', { resolveDocumentAssetUrl(doc, 'thumbnail', {
@@ -219,7 +188,6 @@ const useDetailWorkspace = ({
onTagAdd: handleDetailTagAdd, onTagAdd: handleDetailTagAdd,
onTagRemove: handleDetailTagRemove, onTagRemove: handleDetailTagRemove,
onOpenPreview: openDocumentPreview, onOpenPreview: openDocumentPreview,
activePreviewId,
onUpdateTitle: handleDocumentTitleUpdate, onUpdateTitle: handleDocumentTitleUpdate,
onUpdateIssued: handleDocumentIssuedUpdate, onUpdateIssued: handleDocumentIssuedUpdate,
ensureAssetUrl, ensureAssetUrl,
@@ -240,8 +208,6 @@ const useDetailWorkspace = ({
closeDetailPanel, closeDetailPanel,
handleDetailPanelClose, handleDetailPanelClose,
inspectDocument, inspectDocument,
previewActive,
previewWorkspaceDocument,
resolveThumbnailUrlForDoc, resolveThumbnailUrlForDoc,
resolveFolderPath, resolveFolderPath,
}; };