2025-08-19 10:31:44 +01:00
|
|
|
import React, { useEffect, useRef } from 'react';
|
2025-08-15 14:43:30 +01:00
|
|
|
import { Button, Stack, Text } from '@mantine/core';
|
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import DownloadIcon from '@mui/icons-material/Download';
|
|
|
|
import ErrorNotification from './ErrorNotification';
|
|
|
|
import ResultsPreview from './ResultsPreview';
|
|
|
|
import { SuggestedToolsSection } from './SuggestedToolsSection';
|
|
|
|
import { ToolOperationHook } from '../../../hooks/tools/shared/useToolOperation';
|
|
|
|
|
|
|
|
export interface ReviewToolStepProps<TParams = unknown> {
|
|
|
|
isVisible: boolean;
|
|
|
|
operation: ToolOperationHook<TParams>;
|
|
|
|
title?: string;
|
|
|
|
onFileClick?: (file: File) => void;
|
|
|
|
}
|
|
|
|
|
2025-08-19 10:31:44 +01:00
|
|
|
function ReviewStepContent<TParams = unknown>({ operation, onFileClick }: { operation: ToolOperationHook<TParams>; onFileClick?: (file: File) => 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
|
|
|
|
|
|
|
const previewFiles = operation.files?.map((file, index) => ({
|
|
|
|
file,
|
|
|
|
thumbnail: operation.thumbnails[index]
|
|
|
|
})) || [];
|
|
|
|
|
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,
|
|
|
|
behavior: 'smooth'
|
|
|
|
});
|
|
|
|
}, 100); // Small delay to ensure content is rendered
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, [previewFiles.length, operation.downloadUrl, operation.errorMessage]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Stack gap="sm" ref={stepRef}>
|
2025-08-15 14:43:30 +01:00
|
|
|
<ErrorNotification
|
|
|
|
error={operation.errorMessage}
|
|
|
|
onClose={operation.clearError}
|
|
|
|
/>
|
|
|
|
|
|
|
|
{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}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
|
|
|
|
{operation.downloadUrl && (
|
|
|
|
<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();
|
|
|
|
|
|
|
|
return createStep(t("review", "Review"), {
|
|
|
|
isVisible: props.isVisible,
|
|
|
|
_excludeFromCount: true,
|
|
|
|
_noPadding: true
|
|
|
|
}, (
|
|
|
|
<ReviewStepContent
|
|
|
|
operation={props.operation}
|
|
|
|
onFileClick={props.onFileClick}
|
|
|
|
/>
|
2025-08-15 14:43:30 +01:00
|
|
|
));
|
|
|
|
}
|