202 lines
6.7 KiB
TypeScript
202 lines
6.7 KiB
TypeScript
import { useMemo, useCallback, useRef, useEffect } from 'react';
|
|
import { isPointerModifierEvent, isPrimaryPointerEvent } from '../features/selection/useEntryPointer';
|
|
import { useDocumentsFilter } from '../context/DocumentsFilterContext';
|
|
import { useWorkspaceSelectionContext } from '../../app/WorkspaceSelectionContext';
|
|
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 = () => {
|
|
const shell = useAppShell();
|
|
const {
|
|
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,
|
|
} = useWorkspaceSelectionContext();
|
|
|
|
const {
|
|
toggleTag: toggleTagFilter,
|
|
toggleCorrespondent: toggleCorrespondentFilter,
|
|
} = useDocumentsFilter();
|
|
|
|
const scrollRef = useRef<HTMLElement | null>(null);
|
|
const suppressDocumentClickRef = useRef(false);
|
|
|
|
const { showToast } = useStatusToast();
|
|
|
|
// Subscribe to tag operation results
|
|
useEffect(() => {
|
|
return subscribeToToast((message, type) => {
|
|
showToast(message, type);
|
|
});
|
|
}, [showToast]);
|
|
|
|
// Handlers
|
|
const tagHandlers = useTagInteractions({
|
|
onAssignTagToDocument: handleDocumentTagAttach,
|
|
onRemoveTagFromDocument: handleDocumentTagDetach,
|
|
onTagClick: toggleTagFilter,
|
|
});
|
|
|
|
// Derived State
|
|
const draggingDocumentIdsSet = useMemo(
|
|
() => new Set(draggingDocumentIds || []),
|
|
[draggingDocumentIds],
|
|
);
|
|
const activeCorrespondentIdSet = useMemo(
|
|
() => new Set(activeCorrespondentIds || []),
|
|
[activeCorrespondentIds],
|
|
);
|
|
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(',');
|
|
return `search:${trimmedQuery}|tags:${tagsKey}|corr:${correspondentsKey}`;
|
|
}
|
|
const folderKey = selectedFolder && selectedFolder !== '' ? selectedFolder : 'root';
|
|
return `folder:${folderKey}`;
|
|
}, [
|
|
showingSearchResults,
|
|
searchQuery,
|
|
activeTagFilters,
|
|
activeCorrespondentFilters,
|
|
selectedFolder,
|
|
]);
|
|
|
|
const handleFolderClick = useCallback(
|
|
(folder: any, event: any) => {
|
|
if (!folder) {
|
|
return;
|
|
}
|
|
|
|
if (onEntryPointer) {
|
|
onEntryPointer(
|
|
{ type: EntryType.folder, id: folder.id, key: `folder:${folder.id}`, folder },
|
|
event,
|
|
);
|
|
}
|
|
|
|
if (
|
|
!isPointerModifierEvent(event)
|
|
&& isPrimaryPointerEvent(event)
|
|
&& scrollRef.current
|
|
) {
|
|
scrollRef.current.focus({ preventScroll: true });
|
|
setFocusedEntryKey(`folder:${folder.id}`);
|
|
}
|
|
},
|
|
[onEntryPointer, setFocusedEntryKey],
|
|
);
|
|
|
|
const handleDocumentDragStartLocal = useCallback(
|
|
(event: any, doc: any) => {
|
|
suppressDocumentClickRef.current = true;
|
|
handleDocumentDragStart?.(event, doc);
|
|
},
|
|
[handleDocumentDragStart],
|
|
);
|
|
|
|
const handleDocumentDragEndLocal = useCallback(
|
|
(event: any) => {
|
|
handleDocumentDragEnd?.(event);
|
|
requestAnimationFrame(() => {
|
|
suppressDocumentClickRef.current = false;
|
|
});
|
|
},
|
|
[handleDocumentDragEnd],
|
|
);
|
|
|
|
// Context Values Construction
|
|
const assetContextValue = useMemo(() => ({
|
|
ensureAssetUrl,
|
|
getDocumentAsset,
|
|
}), [ensureAssetUrl, getDocumentAsset]);
|
|
|
|
const draggedFolderId = (shell as any).folderTree?.draggedFolderId;
|
|
|
|
const viewStateContextValue = useMemo(() => ({
|
|
viewId,
|
|
scrollRef,
|
|
tagLookupById,
|
|
correspondentLookupById,
|
|
activeCorrespondentIdSet,
|
|
draggingDocumentIdsSet,
|
|
draggedFolderId,
|
|
}), [
|
|
viewId,
|
|
scrollRef,
|
|
tagLookupById,
|
|
activeCorrespondentIdSet,
|
|
draggingDocumentIdsSet,
|
|
draggedFolderId,
|
|
correspondentLookupById,
|
|
]);
|
|
|
|
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,
|
|
toggleCorrespondentFilter,
|
|
onEntryPointer,
|
|
]);
|
|
|
|
return {
|
|
assetContextValue,
|
|
viewStateContextValue,
|
|
commandContextValue,
|
|
tagHandlers,
|
|
scrollRef,
|
|
hasDocumentEntries,
|
|
isSearchLoading,
|
|
showingSearchResults,
|
|
activeTagFilters,
|
|
activeCorrespondentFilters,
|
|
};
|
|
};
|