2025-09-05 12:16:17 +01:00
|
|
|
import React, { useEffect, useRef } from "react";
|
|
|
|
import { Button, Stack } from "@mantine/core";
|
2025-09-02 15:09:05 +01:00
|
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import DownloadIcon from "@mui/icons-material/Download";
|
|
|
|
import UndoIcon from "@mui/icons-material/Undo";
|
|
|
|
import ErrorNotification from "./ErrorNotification";
|
|
|
|
import ResultsPreview from "./ResultsPreview";
|
|
|
|
import { SuggestedToolsSection } from "./SuggestedToolsSection";
|
|
|
|
import { ToolOperationHook } from "../../../hooks/tools/shared/useToolOperation";
|
|
|
|
import { Tooltip } from "../../shared/Tooltip";
|
2025-08-15 14:43:30 +01:00
|
|
|
|
|
|
|
export interface ReviewToolStepProps<TParams = unknown> {
|
|
|
|
isVisible: boolean;
|
|
|
|
operation: ToolOperationHook<TParams>;
|
|
|
|
title?: string;
|
|
|
|
onFileClick?: (file: File) => void;
|
2025-09-02 15:09:05 +01:00
|
|
|
onUndo: () => void;
|
2025-09-17 19:37:09 +01:00
|
|
|
isCollapsed?: boolean;
|
|
|
|
onCollapsedClick?: () => void;
|
2025-08-15 14:43:30 +01:00
|
|
|
}
|
|
|
|
|
2025-09-02 15:09:05 +01:00
|
|
|
function ReviewStepContent<TParams = unknown>({
|
|
|
|
operation,
|
|
|
|
onFileClick,
|
|
|
|
onUndo,
|
|
|
|
}: {
|
|
|
|
operation: ToolOperationHook<TParams>;
|
|
|
|
onFileClick?: (file: File) => void;
|
|
|
|
onUndo: () => void;
|
|
|
|
}) {
|
2025-08-15 14:43:30 +01:00
|
|
|
const { t } = useTranslation();
|
2025-08-19 10:31:44 +01:00
|
|
|
const stepRef = useRef<HTMLDivElement>(null);
|
2025-08-15 14:43:30 +01:00
|
|
|
|
2025-09-02 15:09:05 +01:00
|
|
|
const handleUndo = async () => {
|
|
|
|
try {
|
|
|
|
onUndo();
|
|
|
|
} catch (error) {
|
|
|
|
// Error is already handled by useToolOperation, just reset loading state
|
|
|
|
console.error("Undo operation failed:", error);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const previewFiles =
|
|
|
|
operation.files?.map((file, index) => ({
|
|
|
|
file,
|
|
|
|
thumbnail: operation.thumbnails[index],
|
|
|
|
})) || [];
|
2025-08-15 14:43:30 +01:00
|
|
|
|
2025-08-19 10:31:44 +01:00
|
|
|
// Auto-scroll to bottom when content appears
|
|
|
|
useEffect(() => {
|
|
|
|
if (stepRef.current && (previewFiles.length > 0 || operation.downloadUrl || operation.errorMessage)) {
|
|
|
|
const scrollableContainer = stepRef.current.closest('[style*="overflow: auto"]') as HTMLElement;
|
|
|
|
if (scrollableContainer) {
|
|
|
|
setTimeout(() => {
|
|
|
|
scrollableContainer.scrollTo({
|
|
|
|
top: scrollableContainer.scrollHeight,
|
2025-09-02 15:09:05 +01:00
|
|
|
behavior: "smooth",
|
2025-08-19 10:31:44 +01:00
|
|
|
});
|
|
|
|
}, 100); // Small delay to ensure content is rendered
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [previewFiles.length, operation.downloadUrl, operation.errorMessage]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Stack gap="sm" ref={stepRef}>
|
2025-09-02 15:09:05 +01:00
|
|
|
<ErrorNotification error={operation.errorMessage} onClose={operation.clearError} />
|
2025-08-15 14:43:30 +01:00
|
|
|
|
|
|
|
{previewFiles.length > 0 && (
|
|
|
|
<ResultsPreview
|
|
|
|
files={previewFiles}
|
2025-08-19 10:31:44 +01:00
|
|
|
onFileClick={onFileClick}
|
2025-08-15 14:43:30 +01:00
|
|
|
isGeneratingThumbnails={operation.isGeneratingThumbnails}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
|
2025-09-02 15:09:05 +01:00
|
|
|
<Tooltip content={t("undoOperationTooltip", "Click to undo the last operation and restore the original files")}>
|
|
|
|
<Button
|
|
|
|
leftSection={<UndoIcon />}
|
|
|
|
variant="outline"
|
|
|
|
color="var(--mantine-color-gray-6)"
|
|
|
|
onClick={handleUndo}
|
|
|
|
fullWidth
|
|
|
|
>
|
|
|
|
{t("undo", "Undo")}
|
|
|
|
</Button>
|
|
|
|
</Tooltip>
|
|
|
|
{operation.downloadUrl && (
|
2025-08-15 14:43:30 +01:00
|
|
|
<Button
|
|
|
|
component="a"
|
|
|
|
href={operation.downloadUrl}
|
|
|
|
download={operation.downloadFilename}
|
|
|
|
leftSection={<DownloadIcon />}
|
|
|
|
color="blue"
|
|
|
|
fullWidth
|
|
|
|
mb="md"
|
|
|
|
>
|
|
|
|
{t("download", "Download")}
|
|
|
|
</Button>
|
|
|
|
)}
|
|
|
|
|
|
|
|
<SuggestedToolsSection />
|
|
|
|
</Stack>
|
2025-08-19 10:31:44 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function createReviewToolStep<TParams = unknown>(
|
|
|
|
createStep: (title: string, props: any, children?: React.ReactNode) => React.ReactElement,
|
|
|
|
props: ReviewToolStepProps<TParams>
|
|
|
|
): React.ReactElement {
|
|
|
|
const { t } = useTranslation();
|
|
|
|
|
2025-09-02 15:09:05 +01:00
|
|
|
return createStep(
|
|
|
|
t("review", "Review"),
|
|
|
|
{
|
|
|
|
isVisible: props.isVisible,
|
2025-09-17 19:37:09 +01:00
|
|
|
isCollapsed: props.isCollapsed,
|
|
|
|
onCollapsedClick: props.onCollapsedClick,
|
2025-09-02 15:09:05 +01:00
|
|
|
_excludeFromCount: true,
|
|
|
|
_noPadding: true,
|
|
|
|
},
|
|
|
|
<ReviewStepContent operation={props.operation} onFileClick={props.onFileClick} onUndo={props.onUndo} />
|
|
|
|
);
|
2025-08-15 14:43:30 +01:00
|
|
|
}
|