Feature/v2/file handling improvements (#4222)

# Description of Changes

A new universal file context rather than the splintered ones for the
main views, tools and manager we had before (manager still has its own
but its better integreated with the core context)
File context has been split it into a handful of different files
managing various file related issues separately to reduce the monolith -
FileReducer.ts - State management
  fileActions.ts - File operations
  fileSelectors.ts - Data access patterns
  lifecycle.ts - Resource cleanup and memory management
  fileHooks.ts - React hooks interface
  contexts.ts - Context providers
Improved thumbnail generation
Improved indexxedb handling
Stopped handling files as blobs were not necessary to improve
performance
A new library handling drag and drop
https://github.com/atlassian/pragmatic-drag-and-drop (Out of scope yes
but I broke the old one with the new filecontext and it needed doing so
it was a might as well)
A new library handling virtualisation on page editor
@tanstack/react-virtual, as above.
Quickly ripped out the last remnants of the old URL params stuff and
replaced with the beginnings of what will later become the new URL
navigation system (for now it just restores the tool name in url
behavior)
Fixed selected file not regestered when opening a tool
Fixed png thumbnails
Closes #(issue_number)

---

## 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: Reece Browne <you@example.com>
This commit is contained in:
Reece Browne
2025-08-21 17:30:26 +01:00
committed by GitHub
parent a33e51351b
commit 949ffa01ad
90 changed files with 5416 additions and 4164 deletions

View File

@@ -1,8 +1,8 @@
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useFileSelection } from "../contexts/FileContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -17,8 +17,8 @@ import { BaseToolProps } from "../types/tool";
const AddPassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const [collapsedPermissions, setCollapsedPermissions] = useState(true);
@@ -30,6 +30,8 @@ const AddPassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
// Endpoint validation
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(addPasswordParams.getEndpointName());
useEffect(() => {
addPasswordOperation.resetResults();
onPreviewFile?.(null);
@@ -51,13 +53,11 @@ const AddPassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "addPassword");
setCurrentMode("viewer");
};
const handleSettingsReset = () => {
addPasswordOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("addPassword");
};
const hasFiles = selectedFiles.length > 0;

View File

@@ -1,8 +1,8 @@
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useFileSelection } from "../contexts/FileContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -25,8 +25,8 @@ import { BaseToolProps } from "../types/tool";
const AddWatermark = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const [collapsedType, setCollapsedType] = useState(false);
const [collapsedStyle, setCollapsedStyle] = useState(true);
@@ -43,6 +43,7 @@ const AddWatermark = ({ onPreviewFile, onComplete, onError }: BaseToolProps) =>
// Endpoint validation
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled("add-watermark");
useEffect(() => {
watermarkOperation.resetResults();
onPreviewFile?.(null);
@@ -71,13 +72,11 @@ const AddWatermark = ({ onPreviewFile, onComplete, onError }: BaseToolProps) =>
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "watermark");
setCurrentMode("viewer");
};
const handleSettingsReset = () => {
watermarkOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("watermark");
};
const hasFiles = selectedFiles.length > 0;

View File

@@ -1,8 +1,8 @@
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useFileSelection } from "../contexts/FileContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -15,8 +15,8 @@ import { BaseToolProps } from "../types/tool";
const ChangePermissions = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const changePermissionsParams = useChangePermissionsParameters();
const changePermissionsOperation = useChangePermissionsOperation();
@@ -48,13 +48,11 @@ const ChangePermissions = ({ onPreviewFile, onComplete, onError }: BaseToolProps
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "changePermissions");
setCurrentMode("viewer");
};
const handleSettingsReset = () => {
changePermissionsOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("changePermissions");
};
const hasFiles = selectedFiles.length > 0;

View File

@@ -1,8 +1,8 @@
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useFileSelection } from "../contexts/FileContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -15,8 +15,8 @@ import { useCompressTips } from "../components/tooltips/useCompressTips";
const Compress = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const compressParams = useCompressParameters();
const compressOperation = useCompressOperation();
@@ -46,13 +46,12 @@ const Compress = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "compress");
setCurrentMode("viewer");
};
const handleSettingsReset = () => {
compressOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("compress");
actions.setMode("compress");
};
const hasFiles = selectedFiles.length > 0;

View File

@@ -1,8 +1,8 @@
import React, { useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useFileState, useFileSelection } from "../contexts/FileContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -14,8 +14,10 @@ import { BaseToolProps } from "../types/tool";
const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode, activeFiles } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { selectors } = useFileState();
const { actions } = useNavigationActions();
const activeFiles = selectors.getFiles();
const { selectedFiles } = useFileSelection();
const scrollContainerRef = useRef<HTMLDivElement>(null);
const convertParams = useConvertParameters();
@@ -46,7 +48,7 @@ const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
convertParams.resetParameters();
}
}
}, [selectedFiles, activeFiles]);
}, [selectedFiles, activeFiles, convertParams.analyzeFileTypes, convertParams.resetParameters]);
useEffect(() => {
// Only clear results if we're not currently processing and parameters changed
@@ -84,13 +86,11 @@ const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "convert");
setCurrentMode("viewer");
};
const handleSettingsReset = () => {
convertOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("convert");
};
return createToolFlow({

View File

@@ -1,149 +0,0 @@
import React, { useState, useEffect } from "react";
import { Paper, Button, Checkbox, Stack, Text, Group, Loader, Alert } from "@mantine/core";
import { useTranslation } from "react-i18next";
import { FileWithUrl } from "../types/file";
import { fileStorage } from "../services/fileStorage";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
export interface MergePdfPanelProps {
files: FileWithUrl[];
setDownloadUrl: (url: string) => void;
params: {
order: string;
removeDuplicates: boolean;
};
updateParams: (newParams: Partial<MergePdfPanelProps["params"]>) => void;
}
const MergePdfPanel: React.FC<MergePdfPanelProps> = ({ files, setDownloadUrl, params, updateParams }) => {
const { t } = useTranslation();
const [selectedFiles, setSelectedFiles] = useState<boolean[]>([]);
const [downloadUrl, setLocalDownloadUrl] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled("merge-pdfs");
useEffect(() => {
setSelectedFiles(files.map(() => true));
}, [files]);
const handleMerge = async () => {
const filesToMerge = files.filter((_, index) => selectedFiles[index]);
if (filesToMerge.length < 2) {
setErrorMessage(t("multiPdfPrompt")); // "Select PDFs (2+)"
return;
}
const formData = new FormData();
// Handle IndexedDB files
for (const file of filesToMerge) {
if (!file.id) {
continue; // Skip files without an id
}
const storedFile = await fileStorage.getFile(file?.id);
if (storedFile) {
const blob = new Blob([storedFile.data], { type: storedFile.type });
const actualFile = new File([blob], storedFile.name, {
type: storedFile.type,
lastModified: storedFile.lastModified,
});
formData.append("fileInput", actualFile);
}
}
setIsLoading(true);
setErrorMessage(null);
try {
const response = await fetch("/api/v1/general/merge-pdfs", {
method: "POST",
body: formData,
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Failed to merge PDFs: ${errorText}`);
}
const blob = await response.blob();
const url = URL.createObjectURL(blob);
setDownloadUrl(url);
setLocalDownloadUrl(url);
} catch (error: any) {
setErrorMessage(error.message || "Unknown error occurred.");
} finally {
setIsLoading(false);
}
};
const handleCheckboxChange = (index: number) => {
setSelectedFiles((prev) => prev.map((selected, i) => (i === index ? !selected : selected)));
};
const selectedCount = selectedFiles.filter(Boolean).length;
const { order, removeDuplicates } = params;
if (endpointLoading) {
return (
<Stack align="center" justify="center" h={200}>
<Loader size="md" />
<Text size="sm" c="dimmed">
{t("loading", "Loading...")}
</Text>
</Stack>
);
}
if (endpointEnabled === false) {
return (
<Stack align="center" justify="center" h={200}>
<Alert color="red" title={t("error._value", "Error")} variant="light">
{t("endpointDisabled", "This feature is currently disabled.")}
</Alert>
</Stack>
);
}
return (
<Stack>
<Text fw={500} size="lg">
{t("merge.header")}
</Text>
<Stack gap={4}>
{files.map((file, index) => (
<Group key={index} gap="xs">
<Checkbox checked={selectedFiles[index] || false} onChange={() => handleCheckboxChange(index)} />
<Text size="sm">{file.name}</Text>
</Group>
))}
</Stack>
{selectedCount < 2 && (
<Text size="sm" c="red">
{t("multiPdfPrompt")}
</Text>
)}
<Button onClick={handleMerge} loading={isLoading} disabled={selectedCount < 2 || isLoading} mt="md">
{t("merge.submit")}
</Button>
{errorMessage && (
<Alert color="red" mt="sm">
{errorMessage}
</Alert>
)}
{downloadUrl && (
<Button component="a" href={downloadUrl} download="merged.pdf" color="green" variant="light" mt="md">
{t("downloadPdf")}
</Button>
)}
<Checkbox
label={t("merge.removeCertSign")}
checked={removeDuplicates}
onChange={() => updateParams({ removeDuplicates: !removeDuplicates })}
/>
</Stack>
);
};
export default MergePdfPanel;

View File

@@ -1,8 +1,8 @@
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useFileSelection } from "../contexts/FileContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -16,8 +16,8 @@ import { useOCRTips } from "../components/tooltips/useOCRTips";
const OCR = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const ocrParams = useOCRParameters();
const ocrOperation = useOCROperation();
@@ -66,13 +66,11 @@ const OCR = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "ocr");
setCurrentMode("viewer");
};
const handleSettingsReset = () => {
ocrOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("ocr");
};
const settingsCollapsed = expandedStep !== "settings";

View File

@@ -2,7 +2,8 @@ import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { useFileSelection } from "../contexts/file/fileHooks";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -12,8 +13,8 @@ import { BaseToolProps } from "../types/tool";
const RemoveCertificateSign = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const removeCertificateSignParams = useRemoveCertificateSignParameters();
const removeCertificateSignOperation = useRemoveCertificateSignOperation();
@@ -42,13 +43,12 @@ const RemoveCertificateSign = ({ onPreviewFile, onComplete, onError }: BaseToolP
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "removeCertificateSign");
setCurrentMode("viewer");
actions.setMode("viewer");
};
const handleSettingsReset = () => {
removeCertificateSignOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("removeCertificateSign");
};
const hasFiles = selectedFiles.length > 0;

View File

@@ -1,8 +1,8 @@
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useFileSelection } from "../contexts/FileContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -15,8 +15,8 @@ import { BaseToolProps } from "../types/tool";
const RemovePassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const removePasswordParams = useRemovePasswordParameters();
const removePasswordOperation = useRemovePasswordOperation();
@@ -25,6 +25,7 @@ const RemovePassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) =
// Endpoint validation
const { enabled: endpointEnabled, loading: endpointLoading } = useEndpointEnabled(removePasswordParams.getEndpointName());
useEffect(() => {
removePasswordOperation.resetResults();
onPreviewFile?.(null);
@@ -46,13 +47,11 @@ const RemovePassword = ({ onPreviewFile, onComplete, onError }: BaseToolProps) =
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "removePassword");
setCurrentMode("viewer");
};
const handleSettingsReset = () => {
removePasswordOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("removePassword");
};
const hasFiles = selectedFiles.length > 0;

View File

@@ -2,7 +2,8 @@ import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { useFileSelection } from "../contexts/file/fileHooks";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -12,8 +13,8 @@ import { BaseToolProps } from "../types/tool";
const Repair = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const repairParams = useRepairParameters();
const repairOperation = useRepairOperation();
@@ -42,13 +43,12 @@ const Repair = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "repair");
setCurrentMode("viewer");
actions.setMode("viewer");
};
const handleSettingsReset = () => {
repairOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("repair");
};
const hasFiles = selectedFiles.length > 0;

View File

@@ -1,7 +1,8 @@
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useFileSelection } from "../contexts/FileContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
import SanitizeSettings from "../components/tools/sanitize/SanitizeSettings";
@@ -9,13 +10,12 @@ import SanitizeSettings from "../components/tools/sanitize/SanitizeSettings";
import { useSanitizeParameters } from "../hooks/tools/sanitize/useSanitizeParameters";
import { useSanitizeOperation } from "../hooks/tools/sanitize/useSanitizeOperation";
import { BaseToolProps } from "../types/tool";
import { useFileContext } from "../contexts/FileContext";
const Sanitize = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { selectedFiles } = useToolFileSelection();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useFileSelection();
const { actions } = useNavigationActions();
const sanitizeParams = useSanitizeParameters();
const sanitizeOperation = useSanitizeOperation();
@@ -44,13 +44,11 @@ const Sanitize = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const handleSettingsReset = () => {
sanitizeOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("sanitize");
};
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "sanitize");
setCurrentMode("viewer");
};
const hasFiles = selectedFiles.length > 0;

View File

@@ -2,7 +2,8 @@ import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { useFileSelection } from "../contexts/file/fileHooks";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -12,8 +13,8 @@ import { BaseToolProps } from "../types/tool";
const SingleLargePage = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const singleLargePageParams = useSingleLargePageParameters();
const singleLargePageOperation = useSingleLargePageOperation();
@@ -42,13 +43,12 @@ const SingleLargePage = ({ onPreviewFile, onComplete, onError }: BaseToolProps)
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "single-large-page");
setCurrentMode("viewer");
actions.setMode("viewer");
};
const handleSettingsReset = () => {
singleLargePageOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("single-large-page");
};
const hasFiles = selectedFiles.length > 0;

View File

@@ -1,8 +1,8 @@
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useFileSelection } from "../contexts/FileContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
import SplitSettings from "../components/tools/split/SplitSettings";
@@ -13,8 +13,8 @@ import { BaseToolProps } from "../types/tool";
const Split = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const splitParams = useSplitParameters();
const splitOperation = useSplitOperation();
@@ -25,8 +25,7 @@ const Split = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
useEffect(() => {
splitOperation.resetResults();
onPreviewFile?.(null);
}, [splitParams.parameters]);
}, [splitParams.parameters, selectedFiles]);
const handleSplit = async () => {
try {
await splitOperation.executeOperation(splitParams.parameters, selectedFiles);
@@ -43,13 +42,12 @@ const Split = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "split");
setCurrentMode("viewer");
};
const handleSettingsReset = () => {
splitOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("split");
actions.setMode("split");
};
const hasFiles = selectedFiles.length > 0;

View File

@@ -2,7 +2,8 @@ import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
import { useNavigationActions } from "../contexts/NavigationContext";
import { useFileSelection } from "../contexts/file/fileHooks";
import { createToolFlow } from "../components/tools/shared/createToolFlow";
@@ -12,8 +13,8 @@ import { BaseToolProps } from "../types/tool";
const UnlockPdfForms = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const { t } = useTranslation();
const { setCurrentMode } = useFileContext();
const { selectedFiles } = useToolFileSelection();
const { actions } = useNavigationActions();
const { selectedFiles } = useFileSelection();
const unlockPdfFormsParams = useUnlockPdfFormsParameters();
const unlockPdfFormsOperation = useUnlockPdfFormsOperation();
@@ -42,13 +43,12 @@ const UnlockPdfForms = ({ onPreviewFile, onComplete, onError }: BaseToolProps) =
const handleThumbnailClick = (file: File) => {
onPreviewFile?.(file);
sessionStorage.setItem("previousMode", "unlockPdfForms");
setCurrentMode("viewer");
actions.setMode("viewer");
};
const handleSettingsReset = () => {
unlockPdfFormsOperation.resetResults();
onPreviewFile?.(null);
setCurrentMode("unlockPdfForms");
};
const hasFiles = selectedFiles.length > 0;