mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-26 14:19:24 +00:00
253 lines
7.8 KiB
TypeScript
253 lines
7.8 KiB
TypeScript
/**
|
|
* Performant file hooks - Clean API using FileContext
|
|
*/
|
|
|
|
import { useContext, useMemo } from 'react';
|
|
import {
|
|
FileStateContext,
|
|
FileActionsContext,
|
|
FileContextStateValue,
|
|
FileContextActionsValue
|
|
} from './contexts';
|
|
import { FileId, FileRecord } from '../../types/fileContext';
|
|
|
|
/**
|
|
* Hook for accessing file state (will re-render on any state change)
|
|
* Use individual selector hooks below for better performance
|
|
*/
|
|
export function useFileState(): FileContextStateValue {
|
|
const context = useContext(FileStateContext);
|
|
if (!context) {
|
|
throw new Error('useFileState must be used within a FileContextProvider');
|
|
}
|
|
return context;
|
|
}
|
|
|
|
/**
|
|
* Hook for accessing file actions (stable - won't cause re-renders)
|
|
*/
|
|
export function useFileActions(): FileContextActionsValue {
|
|
const context = useContext(FileActionsContext);
|
|
if (!context) {
|
|
throw new Error('useFileActions must be used within a FileContextProvider');
|
|
}
|
|
return context;
|
|
}
|
|
|
|
/**
|
|
* Hook for current/primary file (first in list)
|
|
*/
|
|
export function useCurrentFile(): { file?: File; record?: FileRecord } {
|
|
const { state, selectors } = useFileState();
|
|
|
|
const primaryFileId = state.files.ids[0];
|
|
return useMemo(() => ({
|
|
file: primaryFileId ? selectors.getFile(primaryFileId) : undefined,
|
|
record: primaryFileId ? selectors.getFileRecord(primaryFileId) : undefined
|
|
}), [primaryFileId, selectors]);
|
|
}
|
|
|
|
/**
|
|
* Hook for file selection state and actions
|
|
*/
|
|
export function useFileSelection() {
|
|
const { state } = useFileState();
|
|
const { actions } = useFileActions();
|
|
|
|
return useMemo(() => ({
|
|
selectedFileIds: state.ui.selectedFileIds,
|
|
selectedPageNumbers: state.ui.selectedPageNumbers,
|
|
setSelectedFiles: actions.setSelectedFiles,
|
|
setSelectedPages: actions.setSelectedPages,
|
|
clearSelections: actions.clearSelections
|
|
}), [
|
|
state.ui.selectedFileIds,
|
|
state.ui.selectedPageNumbers,
|
|
actions.setSelectedFiles,
|
|
actions.setSelectedPages,
|
|
actions.clearSelections
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Hook for file management operations
|
|
*/
|
|
export function useFileManagement() {
|
|
const { actions } = useFileActions();
|
|
|
|
return useMemo(() => ({
|
|
addFiles: actions.addFiles,
|
|
removeFiles: actions.removeFiles,
|
|
clearAllFiles: actions.clearAllFiles,
|
|
updateFileRecord: actions.updateFileRecord,
|
|
reorderFiles: actions.reorderFiles
|
|
}), [actions]);
|
|
}
|
|
|
|
/**
|
|
* Hook for UI state
|
|
*/
|
|
export function useFileUI() {
|
|
const { state } = useFileState();
|
|
const { actions } = useFileActions();
|
|
|
|
return useMemo(() => ({
|
|
isProcessing: state.ui.isProcessing,
|
|
processingProgress: state.ui.processingProgress,
|
|
hasUnsavedChanges: state.ui.hasUnsavedChanges,
|
|
setProcessing: actions.setProcessing,
|
|
setUnsavedChanges: actions.setHasUnsavedChanges
|
|
}), [state.ui, actions]);
|
|
}
|
|
|
|
/**
|
|
* Hook for specific file by ID (optimized for individual file access)
|
|
*/
|
|
export function useFileRecord(fileId: FileId): { file?: File; record?: FileRecord } {
|
|
const { selectors } = useFileState();
|
|
|
|
return useMemo(() => ({
|
|
file: selectors.getFile(fileId),
|
|
record: selectors.getFileRecord(fileId)
|
|
}), [fileId, selectors]);
|
|
}
|
|
|
|
/**
|
|
* Hook for all files (use sparingly - causes re-renders on file list changes)
|
|
*/
|
|
export function useAllFiles(): { files: File[]; records: FileRecord[]; fileIds: FileId[] } {
|
|
const { state, selectors } = useFileState();
|
|
|
|
return useMemo(() => ({
|
|
files: selectors.getFiles(),
|
|
records: selectors.getFileRecords(),
|
|
fileIds: state.files.ids
|
|
}), [state.files.ids, selectors]);
|
|
}
|
|
|
|
/**
|
|
* Hook for selected files (optimized for selection-based UI)
|
|
*/
|
|
export function useSelectedFiles(): { files: File[]; records: FileRecord[]; fileIds: FileId[] } {
|
|
const { state, selectors } = useFileState();
|
|
|
|
return useMemo(() => ({
|
|
files: selectors.getSelectedFiles(),
|
|
records: selectors.getSelectedFileRecords(),
|
|
fileIds: state.ui.selectedFileIds
|
|
}), [state.ui.selectedFileIds, selectors]);
|
|
}
|
|
|
|
// Navigation management removed - moved to NavigationContext
|
|
|
|
/**
|
|
* Primary API hook for file context operations
|
|
* Used by tools for core file context functionality
|
|
*/
|
|
export function useFileContext() {
|
|
const { state, selectors } = useFileState();
|
|
const { actions } = useFileActions();
|
|
|
|
return useMemo(() => ({
|
|
// Lifecycle management
|
|
trackBlobUrl: actions.trackBlobUrl,
|
|
scheduleCleanup: actions.scheduleCleanup,
|
|
setUnsavedChanges: actions.setHasUnsavedChanges,
|
|
|
|
// File management
|
|
addFiles: actions.addFiles,
|
|
consumeFiles: actions.consumeFiles,
|
|
recordOperation: (fileId: string, operation: any) => {}, // Operation tracking not implemented
|
|
markOperationApplied: (fileId: string, operationId: string) => {}, // Operation tracking not implemented
|
|
markOperationFailed: (fileId: string, operationId: string, error: string) => {}, // Operation tracking not implemented
|
|
|
|
// File ID lookup
|
|
findFileId: (file: File) => {
|
|
return state.files.ids.find(id => {
|
|
const record = state.files.byId[id];
|
|
return record &&
|
|
record.name === file.name &&
|
|
record.size === file.size &&
|
|
record.lastModified === file.lastModified;
|
|
});
|
|
},
|
|
|
|
// Pinned files
|
|
pinnedFiles: state.pinnedFiles,
|
|
pinFile: actions.pinFile,
|
|
unpinFile: actions.unpinFile,
|
|
isFilePinned: selectors.isFilePinned,
|
|
|
|
// Active files
|
|
activeFiles: selectors.getFiles()
|
|
}), [state, selectors, actions]);
|
|
}
|
|
|
|
/**
|
|
* Primary API hook for tool file selection workflow
|
|
* Used by tools for managing file selection and tool-specific operations
|
|
*/
|
|
export function useToolFileSelection() {
|
|
const { state, selectors } = useFileState();
|
|
const { actions } = useFileActions();
|
|
|
|
// Memoize selected files to avoid recreating arrays
|
|
const selectedFiles = useMemo(() => {
|
|
return selectors.getSelectedFiles();
|
|
}, [state.ui.selectedFileIds, selectors]);
|
|
|
|
return useMemo(() => ({
|
|
selectedFiles,
|
|
selectedFileIds: state.ui.selectedFileIds,
|
|
selectedPageNumbers: state.ui.selectedPageNumbers,
|
|
setSelectedFiles: actions.setSelectedFiles,
|
|
setSelectedPages: actions.setSelectedPages,
|
|
clearSelections: actions.clearSelections,
|
|
// Tool workflow properties
|
|
maxFiles: 10, // Default value for tools
|
|
isToolMode: true,
|
|
setMaxFiles: (maxFiles: number) => { /* Tool-specific - can be implemented if needed */ },
|
|
setIsToolMode: (isToolMode: boolean) => { /* Tool-specific - can be implemented if needed */ }
|
|
}), [
|
|
selectedFiles,
|
|
state.ui.selectedFileIds,
|
|
state.ui.selectedPageNumbers,
|
|
actions.setSelectedFiles,
|
|
actions.setSelectedPages,
|
|
actions.clearSelections
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Hook for processed files (compatibility with old FileContext)
|
|
* Provides access to files with their processed metadata
|
|
*/
|
|
export function useProcessedFiles() {
|
|
const { state, selectors } = useFileState();
|
|
|
|
// Create a Map-like interface for backward compatibility
|
|
const compatibilityMap = useMemo(() => ({
|
|
size: state.files.ids.length,
|
|
get: (file: File) => {
|
|
// Find file record by matching File object properties
|
|
const record = Object.values(state.files.byId).find(r =>
|
|
r.name === file.name && r.size === file.size && r.lastModified === file.lastModified
|
|
);
|
|
return record?.processedFile || null;
|
|
},
|
|
has: (file: File) => {
|
|
// Find file record by matching File object properties
|
|
const record = Object.values(state.files.byId).find(r =>
|
|
r.name === file.name && r.size === file.size && r.lastModified === file.lastModified
|
|
);
|
|
return !!record?.processedFile;
|
|
},
|
|
// Removed deprecated set method
|
|
}), [state.files.byId, state.files.ids.length]);
|
|
|
|
return useMemo(() => ({
|
|
processedFiles: compatibilityMap,
|
|
getProcessedFile: (file: File) => compatibilityMap.get(file),
|
|
// Removed deprecated updateProcessedFile method
|
|
}), [compatibilityMap]);
|
|
} |