Stirling-PDF/frontend/src/hooks/useProcessedFiles.ts
Reece Browne 922bbc9076
Stirling 2.0 (#3928)
# Description of Changes

<!--

File context for managing files between tools and views
Optimisation for large files
Updated Split to work with new file system and match Matts stepped
design closer

-->

---

## Checklist

### General

- [ ] I have read the [Contribution
Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md)
- [ ] I have read the [Stirling-PDF Developer
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md)
(if applicable)
- [ ] I have read the [How to add new languages to
Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)
(if applicable)
- [ ] I have performed a self-review of my own code
- [ ] My changes generate no new warnings

### Documentation

- [ ] I have updated relevant docs on [Stirling-PDF's doc
repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/)
(if functionality has heavily changed)
- [ ] I have read the section [Add New Translation
Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags)
(for new translation tags only)

### UI Changes (if applicable)

- [ ] Screenshots or videos demonstrating the UI changes are attached
(e.g., as comments or direct attachments in the PR)

### Testing (if applicable)

- [ ] I have tested my changes locally. Refer to the [Testing
Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing)
for more details.

---------

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
2025-07-16 17:53:50 +01:00

125 lines
3.8 KiB
TypeScript

import { useState, useEffect } from 'react';
import { ProcessedFile, ProcessingState } from '../types/processing';
import { pdfProcessingService } from '../services/pdfProcessingService';
interface UseProcessedFilesResult {
processedFiles: Map<File, ProcessedFile>;
processingStates: Map<string, ProcessingState>;
isProcessing: boolean;
hasProcessingErrors: boolean;
cacheStats: {
entries: number;
totalSizeBytes: number;
maxSizeBytes: number;
};
}
export function useProcessedFiles(activeFiles: File[]): UseProcessedFilesResult {
const [processedFiles, setProcessedFiles] = useState<Map<File, ProcessedFile>>(new Map());
const [processingStates, setProcessingStates] = useState<Map<string, ProcessingState>>(new Map());
useEffect(() => {
// Subscribe to processing state changes
const unsubscribe = pdfProcessingService.onProcessingChange(setProcessingStates);
// Check/start processing for each active file
const checkProcessing = async () => {
const newProcessedFiles = new Map<File, ProcessedFile>();
for (const file of activeFiles) {
const processed = await pdfProcessingService.getProcessedFile(file);
if (processed) {
newProcessedFiles.set(file, processed);
}
}
setProcessedFiles(newProcessedFiles);
};
checkProcessing();
return unsubscribe;
}, [activeFiles]);
// Listen for processing completion and update processed files
useEffect(() => {
const updateProcessedFiles = async () => {
const updated = new Map<File, ProcessedFile>();
for (const file of activeFiles) {
const existing = processedFiles.get(file);
if (existing) {
updated.set(file, existing);
} else {
// Check if processing just completed
const processed = await pdfProcessingService.getProcessedFile(file);
if (processed) {
updated.set(file, processed);
}
}
}
setProcessedFiles(updated);
};
// Small delay to allow processing state to settle
const timeoutId = setTimeout(updateProcessedFiles, 100);
return () => clearTimeout(timeoutId);
}, [processingStates, activeFiles]);
// Cleanup when activeFiles changes
useEffect(() => {
const currentFiles = new Set(activeFiles);
const previousFiles = Array.from(processedFiles.keys());
const removedFiles = previousFiles.filter(file => !currentFiles.has(file));
if (removedFiles.length > 0) {
// Clean up processing service cache
pdfProcessingService.cleanup(removedFiles);
// Update local state
setProcessedFiles(prev => {
const updated = new Map();
for (const [file, processed] of prev) {
if (currentFiles.has(file)) {
updated.set(file, processed);
}
}
return updated;
});
}
}, [activeFiles]);
// Derived state
const isProcessing = processingStates.size > 0;
const hasProcessingErrors = Array.from(processingStates.values()).some(state => state.status === 'error');
const cacheStats = pdfProcessingService.getCacheStats();
return {
processedFiles,
processingStates,
isProcessing,
hasProcessingErrors,
cacheStats
};
}
// Hook for getting a single processed file
export function useProcessedFile(file: File | null): {
processedFile: ProcessedFile | null;
isProcessing: boolean;
processingState: ProcessingState | null;
} {
const result = useProcessedFiles(file ? [file] : []);
const processedFile = file ? result.processedFiles.get(file) || null : null;
const fileKey = file ? pdfProcessingService.generateFileKey(file) : '';
const processingState = fileKey ? result.processingStates.get(fileKey) || null : null;
const isProcessing = !!processingState;
return {
processedFile,
isProcessing,
processingState
};
}