feat: Refactor DocumentsPanel to use a shared application shell context for state management
This commit is contained in:
@@ -1,34 +1,28 @@
|
||||
import { useMemo, useCallback, useRef, useEffect } from 'react';
|
||||
import type { DocumentsPanelInnerProps } from './DocumentsPanel';
|
||||
import { isPointerModifierEvent, isPrimaryPointerEvent } from '../features/selection/useEntryPointer';
|
||||
import { useDocumentsFilter } from '../context/DocumentsFilterContext';
|
||||
import { useWorkspaceSelectionContext } from '../../app/WorkspaceSelectionContext';
|
||||
import type { Identifier } from '../../types/identifiers';
|
||||
import { useStatusToast } from '../../lib/context/StatusToastContext';
|
||||
import { useTagInteractions } from '../interactions/useTagInteractions';
|
||||
import { subscribeToToast } from '../features/tagging/tagTransfer';
|
||||
import { useAppShell } from '../../lib/context/AppShellContext';
|
||||
|
||||
const EntryType = {
|
||||
folder: 'folder',
|
||||
document: 'document',
|
||||
};
|
||||
|
||||
export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
|
||||
export const useDocumentsContextValues = () => {
|
||||
const shell = useAppShell();
|
||||
const {
|
||||
ensureAssetUrl,
|
||||
getDocumentAsset,
|
||||
isSearchLoading,
|
||||
searchQuery = '',
|
||||
activeTagFilters = [],
|
||||
activeCorrespondentFilters = [],
|
||||
selectedFolder = null,
|
||||
onDocumentDragStart,
|
||||
onDocumentDragEnd,
|
||||
onEntryPointer,
|
||||
activeCorrespondentIds = [],
|
||||
draggingDocumentIds = [],
|
||||
tagLookupById,
|
||||
} = props;
|
||||
preview: { ensureAssetUrl, getDocumentAsset },
|
||||
search: { isSearchLoading, searchQuery, activeTagFilters, activeCorrespondentFilters, searchResultIds, documents },
|
||||
folderTree: { selectedFolder },
|
||||
mutations: { handleDocumentDragStart, handleDocumentDragEnd, draggedDocumentIds: draggingDocumentIds, handleDocumentTagAttach, handleDocumentTagDetach },
|
||||
selection: { handleEntryPointerCore: onEntryPointer },
|
||||
correspondents: { activeCorrespondentIds, correspondentLookupById },
|
||||
tags: { tagLookupById },
|
||||
} = shell as any;
|
||||
|
||||
const {
|
||||
setFocusedEntryKey,
|
||||
@@ -53,8 +47,8 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
|
||||
|
||||
// Handlers
|
||||
const tagHandlers = useTagInteractions({
|
||||
onAssignTagToDocument: props.onDocumentTagAttach,
|
||||
onRemoveTagFromDocument: props.onDocumentTagDetach,
|
||||
onAssignTagToDocument: handleDocumentTagAttach,
|
||||
onRemoveTagFromDocument: handleDocumentTagDetach,
|
||||
onTagClick: toggleTagFilter,
|
||||
});
|
||||
|
||||
@@ -67,14 +61,14 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
|
||||
() => new Set(activeCorrespondentIds || []),
|
||||
[activeCorrespondentIds],
|
||||
);
|
||||
const showingSearchResults = Array.isArray(props.searchResultIds);
|
||||
const hasDocumentEntries = (props.documents || []).length > 0 || (showingSearchResults && (props.searchResultIds || []).length > 0);
|
||||
const showingSearchResults = Array.isArray(searchResultIds);
|
||||
const hasDocumentEntries = (documents || []).length > 0 || (showingSearchResults && (searchResultIds || []).length > 0);
|
||||
|
||||
const viewId = useMemo(() => {
|
||||
if (showingSearchResults) {
|
||||
const trimmedQuery = searchQuery.trim();
|
||||
const tagsKey = [...activeTagFilters].sort().join(',');
|
||||
const correspondentsKey = [...activeCorrespondentFilters].sort().join(',');
|
||||
const trimmedQuery = (searchQuery || '').trim();
|
||||
const tagsKey = [...(activeTagFilters || [])].sort().join(',');
|
||||
const correspondentsKey = [...(activeCorrespondentFilters || [])].sort().join(',');
|
||||
return `search:${trimmedQuery}|tags:${tagsKey}|corr:${correspondentsKey}`;
|
||||
}
|
||||
const folderKey = selectedFolder && selectedFolder !== '' ? selectedFolder : 'root';
|
||||
@@ -115,19 +109,19 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
|
||||
const handleDocumentDragStartLocal = useCallback(
|
||||
(event: any, doc: any) => {
|
||||
suppressDocumentClickRef.current = true;
|
||||
onDocumentDragStart?.(event, doc);
|
||||
handleDocumentDragStart?.(event, doc);
|
||||
},
|
||||
[onDocumentDragStart],
|
||||
[handleDocumentDragStart],
|
||||
);
|
||||
|
||||
const handleDocumentDragEndLocal = useCallback(
|
||||
(event: any) => {
|
||||
onDocumentDragEnd?.(event);
|
||||
handleDocumentDragEnd?.(event);
|
||||
requestAnimationFrame(() => {
|
||||
suppressDocumentClickRef.current = false;
|
||||
});
|
||||
},
|
||||
[onDocumentDragEnd],
|
||||
[handleDocumentDragEnd],
|
||||
);
|
||||
|
||||
// Context Values Construction
|
||||
@@ -136,71 +130,61 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
|
||||
getDocumentAsset,
|
||||
}), [ensureAssetUrl, getDocumentAsset]);
|
||||
|
||||
const draggedFolderId = (shell as any).folderTree?.draggedFolderId;
|
||||
|
||||
const viewStateContextValue = useMemo(() => ({
|
||||
viewId,
|
||||
scrollRef,
|
||||
tagLookupById,
|
||||
correspondentLookupById: props.correspondentLookupById,
|
||||
correspondentLookupById,
|
||||
activeCorrespondentIdSet,
|
||||
draggingDocumentIdsSet,
|
||||
draggedFolderId: props.draggedFolderId,
|
||||
draggedFolderId,
|
||||
}), [
|
||||
viewId,
|
||||
scrollRef,
|
||||
tagLookupById,
|
||||
activeCorrespondentIdSet,
|
||||
draggingDocumentIdsSet,
|
||||
props.draggedFolderId,
|
||||
props.correspondentLookupById,
|
||||
draggedFolderId,
|
||||
correspondentLookupById,
|
||||
]);
|
||||
|
||||
// Use refs to stabilize handlers and avoid massive dependency arrays
|
||||
const latestPropsRef = useRef(props);
|
||||
const latestHandlersRef = useRef({
|
||||
const commandContextValue = useMemo(() => {
|
||||
const anyShell = shell as any;
|
||||
return {
|
||||
folder: {
|
||||
onClick: handleFolderClick,
|
||||
onSelect: anyShell.folderTree?.selectFolder,
|
||||
onRename: anyShell.folderTree?.handleFolderRename,
|
||||
onDrag: {
|
||||
start: anyShell.folderTree?.handleFolderDragStart,
|
||||
end: anyShell.folderTree?.handleFolderDragEnd,
|
||||
over: anyShell.folderTree?.folderClickHandlers?.onDragOver,
|
||||
leave: anyShell.folderTree?.folderClickHandlers?.onDragLeave,
|
||||
drop: anyShell.folderTree?.folderClickHandlers?.onDrop,
|
||||
},
|
||||
},
|
||||
document: {
|
||||
onRename: anyShell.mutations?.handleDocumentTitleUpdate,
|
||||
onDrag: {
|
||||
start: handleDocumentDragStartLocal,
|
||||
end: handleDocumentDragEndLocal,
|
||||
},
|
||||
},
|
||||
correspondents: {
|
||||
onClick: toggleCorrespondentFilter,
|
||||
},
|
||||
onEntryPointer,
|
||||
}
|
||||
}, [
|
||||
handleFolderClick,
|
||||
shell,
|
||||
handleDocumentDragStartLocal,
|
||||
handleDocumentDragEndLocal,
|
||||
tagHandlers,
|
||||
toggleTagFilter,
|
||||
toggleCorrespondentFilter,
|
||||
});
|
||||
|
||||
// Update refs on every render
|
||||
latestPropsRef.current = props;
|
||||
latestHandlersRef.current = {
|
||||
handleFolderClick,
|
||||
handleDocumentDragStartLocal,
|
||||
handleDocumentDragEndLocal,
|
||||
tagHandlers,
|
||||
toggleTagFilter,
|
||||
toggleCorrespondentFilter,
|
||||
};
|
||||
|
||||
const commandContextValue = useMemo(() => ({
|
||||
folder: {
|
||||
onClick: (f: any, e: any) => latestHandlersRef.current.handleFolderClick(f, e),
|
||||
onSelect: (id: Identifier) => latestPropsRef.current.onFolderSelect?.(id),
|
||||
onRename: (id: Identifier, name: string) => latestPropsRef.current.onFolderRename?.(id, name),
|
||||
onDrag: {
|
||||
start: (e: any, f: any) => latestPropsRef.current.onFolderDragStart?.(e, f),
|
||||
end: (e: any) => latestPropsRef.current.onFolderDragEnd?.(e),
|
||||
over: (e: any, f: any) => latestPropsRef.current.onFolderDragOver?.(e, f),
|
||||
leave: (e: any) => latestPropsRef.current.onFolderDragLeave?.(e),
|
||||
drop: (e: any, f: any) => latestPropsRef.current.onFolderDrop?.(e, f),
|
||||
},
|
||||
},
|
||||
document: {
|
||||
onRename: (id: Identifier, name: string) => latestPropsRef.current.onDocumentRename?.(id, name),
|
||||
onDrag: {
|
||||
start: (e: any, d: any) => latestHandlersRef.current.handleDocumentDragStartLocal(e, d),
|
||||
end: (e: any) => latestHandlersRef.current.handleDocumentDragEndLocal(e),
|
||||
},
|
||||
},
|
||||
correspondents: {
|
||||
onClick: (c: any) => latestHandlersRef.current.toggleCorrespondentFilter(c),
|
||||
},
|
||||
onEntryPointer: (entry: any, e: any) => latestPropsRef.current.onEntryPointer?.(entry, e),
|
||||
}), []);
|
||||
onEntryPointer,
|
||||
]);
|
||||
|
||||
return {
|
||||
assetContextValue,
|
||||
|
||||
Reference in New Issue
Block a user