setIsSliding(true)}
onTouchEnd={() => setIsSliding(false)}
disabled={disabled}
- style={{
+ style={{
width: '100%',
height: '6px',
borderRadius: '3px',
@@ -107,6 +110,8 @@ const CompressSettings = ({ parameters, onParameterChange, disabled = false }: C
)}
+
+
{/* File Size Input */}
{parameters.compressionMethod === 'filesize' && (
@@ -141,7 +146,7 @@ const CompressSettings = ({ parameters, onParameterChange, disabled = false }: C
{/* Compression Options */}
-
);
}
diff --git a/frontend/src/tools/Convert.tsx b/frontend/src/tools/Convert.tsx
index 3512ca8eb..788c5aac8 100644
--- a/frontend/src/tools/Convert.tsx
+++ b/frontend/src/tools/Convert.tsx
@@ -1,16 +1,12 @@
-import React, { useEffect, useMemo, useRef } from "react";
-import { Button, Stack, Text } from "@mantine/core";
+import React, { useEffect, useRef } from "react";
+import { Stack } from "@mantine/core";
import { useTranslation } from "react-i18next";
-import DownloadIcon from "@mui/icons-material/Download";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
-import ToolStep, { ToolStepContainer } from "../components/tools/shared/ToolStep";
+import { createToolSteps, ToolStepProvider } from "../components/tools/shared/ToolStep";
import OperationButton from "../components/tools/shared/OperationButton";
-import ErrorNotification from "../components/tools/shared/ErrorNotification";
-import FileStatusIndicator from "../components/tools/shared/FileStatusIndicator";
-import ResultsPreview from "../components/tools/shared/ResultsPreview";
import ConvertSettings from "../components/tools/convert/ConvertSettings";
@@ -105,101 +101,55 @@ const Convert = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
setCurrentMode('convert');
};
- const previewResults = useMemo(() =>
- convertOperation.files?.map((file, index) => ({
- file,
- thumbnail: convertOperation.thumbnails[index]
- })) || [],
- [convertOperation.files, convertOperation.thumbnails]
- );
+ const steps = createToolSteps();
return (
-
-
-
-
-
+
+
+ {/* Files Step */}
+ {steps.createFilesStep({
+ selectedFiles,
+ isCollapsed: filesCollapsed,
+ placeholder: t("convert.selectFilesPlaceholder", "Select files in the main view to get started")
+ })}
-
-
-
-
- {hasFiles && convertParams.parameters.fromExtension && convertParams.parameters.toExtension && (
-
+
- )}
-
-
+
+ ))}
+ {!hasResults && (
+
+ )}
-
-
- {convertOperation.status && (
- {convertOperation.status}
- )}
-
-
-
- {convertOperation.downloadUrl && (
- }
- color="green"
- fullWidth
- mb="md"
- data-testid="download-button"
- >
- {t("convert.downloadConverted", "Download Converted File")}
-
- )}
-
-
-
-
-
-
+ {/* Results Step */}
+ {steps.createResultsStep({
+ isVisible: hasResults,
+ operation: convertOperation,
+ title: t("convert.conversionResults", "Conversion Results"),
+ onFileClick: handleThumbnailClick
+ })}
+
+
);
};
diff --git a/frontend/src/tools/OCR.tsx b/frontend/src/tools/OCR.tsx
index 92a8da132..8e033bb79 100644
--- a/frontend/src/tools/OCR.tsx
+++ b/frontend/src/tools/OCR.tsx
@@ -1,16 +1,12 @@
import React, { useEffect, useMemo, useState } from "react";
-import { Button, Stack, Text, Box } from "@mantine/core";
+import { Stack, Box } from "@mantine/core";
import { useTranslation } from "react-i18next";
-import DownloadIcon from "@mui/icons-material/Download";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
-import ToolStep, { ToolStepContainer } from "../components/tools/shared/ToolStep";
+import { createToolSteps, ToolStepProvider } from "../components/tools/shared/ToolStep";
import OperationButton from "../components/tools/shared/OperationButton";
-import ErrorNotification from "../components/tools/shared/ErrorNotification";
-import FileStatusIndicator from "../components/tools/shared/FileStatusIndicator";
-import ResultsPreview from "../components/tools/shared/ResultsPreview";
import OCRSettings from "../components/tools/ocr/OCRSettings";
import AdvancedOCRSettings from "../components/tools/ocr/AdvancedOCRSettings";
@@ -79,140 +75,80 @@ const OCR = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
};
- // Step visibility and collapse logic
- const filesVisible = true;
- const settingsVisible = true;
const resultsVisible = hasResults;
const filesCollapsed = expandedStep !== 'files';
const settingsCollapsed = expandedStep !== 'settings';
- const previewResults = useMemo(() =>
- ocrOperation.files?.map((file: File, index: number) => ({
- file,
- thumbnail: ocrOperation.thumbnails[index]
- })) || [],
- [ocrOperation.files, ocrOperation.thumbnails]
- );
+
+ const steps = createToolSteps();
return (
-
+
{/* Files Step */}
-
-
-
+ {steps.createFilesStep({
+ selectedFiles,
+ isCollapsed: hasFiles && filesCollapsed,
+ })}
{/* Settings Step */}
- {
+ {steps.create("Settings", {
+ isCollapsed: !hasFiles || settingsCollapsed,
+ isCompleted: hasFiles && hasValidSettings,
+ onCollapsedClick: () => {
if (!hasFiles) return; // Only allow if files are selected
setExpandedStep(expandedStep === 'settings' ? null : 'settings');
- }}
- completedMessage={hasFiles && hasValidSettings && settingsCollapsed ? "Basic settings configured" : undefined}
- tooltip={ocrTips}
- >
+ },
+ tooltip: ocrTips
+ }, (
-
-
+ ))}
{/* Advanced Step */}
- {
+ {steps.create("Advanced", {
+ isCollapsed: expandedStep !== 'advanced',
+ isCompleted: hasFiles && hasResults,
+ onCollapsedClick: () => {
if (!hasFiles) return; // Only allow if files are selected
setExpandedStep(expandedStep === 'advanced' ? null : 'advanced');
- }}
- completedMessage={hasFiles && hasResults && expandedStep !== 'advanced' ? "OCR processing completed" : undefined}
- >
+ },
+ }, (
-
+ ))}
{/* Process Button - Available after all configuration */}
{hasValidSettings && !hasResults && (
-
-
)}
{/* Results Step */}
-
-
- {ocrOperation.status && (
- {ocrOperation.status}
- )}
-
-
-
- {ocrOperation.downloadUrl && (
- }
- color="green"
- fullWidth
- mb="md"
- >
- {t("download", "Download")}
-
- )}
-
-
-
-
-
+ {steps.createResultsStep({
+ isVisible: resultsVisible,
+ operation: ocrOperation,
+ title: t("ocr.results.title", "OCR Results"),
+ onFileClick: handleThumbnailClick
+ })}
+
);
}
-export default OCR;
\ No newline at end of file
+export default OCR;
diff --git a/frontend/src/tools/Split.tsx b/frontend/src/tools/Split.tsx
index bc516c754..abcc77dd9 100644
--- a/frontend/src/tools/Split.tsx
+++ b/frontend/src/tools/Split.tsx
@@ -1,16 +1,12 @@
import React, { useEffect, useMemo } from "react";
-import { Button, Stack, Text } from "@mantine/core";
+import { Stack } from "@mantine/core";
import { useTranslation } from "react-i18next";
-import DownloadIcon from "@mui/icons-material/Download";
import { useEndpointEnabled } from "../hooks/useEndpointConfig";
import { useFileContext } from "../contexts/FileContext";
import { useToolFileSelection } from "../contexts/FileSelectionContext";
-import ToolStep, { ToolStepContainer } from "../components/tools/shared/ToolStep";
+import { createToolSteps, ToolStepProvider } from "../components/tools/shared/ToolStep";
import OperationButton from "../components/tools/shared/OperationButton";
-import ErrorNotification from "../components/tools/shared/ErrorNotification";
-import FileStatusIndicator from "../components/tools/shared/FileStatusIndicator";
-import ResultsPreview from "../components/tools/shared/ResultsPreview";
import SplitSettings from "../components/tools/split/SplitSettings";
import { useSplitParameters } from "../hooks/tools/split/useSplitParameters";
@@ -66,42 +62,26 @@ const Split = ({ onPreviewFile, onComplete, onError }: BaseToolProps) => {
const hasFiles = selectedFiles.length > 0;
const hasResults = splitOperation.downloadUrl !== null;
const filesCollapsed = hasFiles;
- const settingsCollapsed = hasResults;
+ const settingsCollapsed = !hasFiles || hasResults;
- const previewResults = useMemo(() =>
- splitOperation.files?.map((file, index) => ({
- file,
- thumbnail: splitOperation.thumbnails[index]
- })) || [],
- [splitOperation.files, splitOperation.thumbnails]
- );
+ const steps = createToolSteps();
return (
-
-
+
+
{/* Files Step */}
-
-
-
+ {steps.createFilesStep({
+ selectedFiles,
+ isCollapsed: filesCollapsed,
+ placeholder: "Select a PDF file in the main view to get started"
+ })}
{/* Settings Step */}
-
+ {steps.create("Settings", {
+ isCollapsed: settingsCollapsed,
+ isCompleted: hasResults,
+ onCollapsedClick: hasResults ? handleSettingsReset : undefined,
+ }, (
{
disabled={endpointLoading}
/>
- {splitParams.parameters.mode && (
-
- )}
-
+ ))}
+
+ {!hasResults && (
+
+ )}
{/* Results Step */}
-
-
- {splitOperation.status && (
- {splitOperation.status}
- )}
-
-
-
- {splitOperation.downloadUrl && (
- }
- color="green"
- fullWidth
- mb="md"
- >
- {t("download", "Download")}
-
- )}
-
-
-
-
-
-
+ {steps.createResultsStep({
+ isVisible: hasResults,
+ operation: splitOperation,
+ title: "Split Results",
+ onFileClick: handleThumbnailClick
+ })}
+
+
);
}