diff --git a/apps/web/src/components/common/review-panel.tsx b/apps/web/src/components/common/review-panel.tsx index 3f9d5f13..38036e0c 100644 --- a/apps/web/src/components/common/review-panel.tsx +++ b/apps/web/src/components/common/review-panel.tsx @@ -1,8 +1,35 @@ -import { ArrowLeft, CheckCircle2, Download } from "lucide-react"; +import { AlertCircle, ArrowLeft, CheckCircle2, Download, FileText } from "lucide-react"; import { useMemo } from "react"; import { Link } from "react-router-dom"; import { useTranslation } from "@/contexts/i18n-context"; import { formatFileSize, triggerDownload } from "@/lib/download"; +import { format } from "@/lib/format"; + +/** Tools whose primary output is text/data, not a downloadable file. */ +const DATA_OUTPUT_TOOLS = new Set([ + "ocr", + "barcode-read", + "info", + "histogram", + "color-palette", + "transcribe-audio", + "extract-subtitles", + "image-to-base64", + "pdf-to-text", + "pdf-metadata", + "audio-metadata", + "video-metadata", +]); + +/** Tools that produce multiple output files bundled as a ZIP. */ +const MULTI_OUTPUT_TOOLS = new Set([ + "split", + "favicon", + "pdf-to-image", + "video-to-frames", + "split-audio", + "split-csv", +]); interface ReviewPanelProps { filename: string; @@ -13,6 +40,9 @@ interface ReviewPanelProps { onUndo: () => void; onStartOver: () => void; currentToolId: string; + totalCount?: number; + successCount?: number; + failedCount?: number; } export function ReviewPanel({ @@ -23,10 +53,16 @@ export function ReviewPanel({ downloadUrl, onUndo, onStartOver, - currentToolId: _currentToolId, + currentToolId, + totalCount, + successCount, + failedCount, }: ReviewPanelProps) { const { t } = useTranslation(); + const isDataOutput = DATA_OUTPUT_TOOLS.has(currentToolId); + const isMultiOutput = MULTI_OUTPUT_TOOLS.has(currentToolId); + const sizeDelta = useMemo(() => { if (!originalSize || originalSize === 0) return 0; return Math.round((1 - fileSize / originalSize) * 100); @@ -36,6 +72,9 @@ export function ReviewPanel({ triggerDownload(downloadUrl, filename); }; + const hasBatchStats = + totalCount != null && totalCount > 1 && successCount != null && failedCount != null; + return (
@@ -46,8 +85,22 @@ export function ReviewPanel({ {t.toolPage.conversionComplete}
- {/* Size delta */} - {originalSize > 0 && ( + {/* Batch partial failure summary */} + {hasBatchStats && failedCount > 0 && ( +
+ + + {format(t.toolPage.batchPartialSuccess, { + success: successCount, + total: totalCount, + failed: failedCount, + })} + +
+ )} + + {/* Size delta -- hidden for data-output tools */} + {!isDataOutput && originalSize > 0 && (
{t.toolPage.original} @@ -78,16 +131,39 @@ export function ReviewPanel({
)} - {/* Download button with format + size */} - + {/* Data-output tools: results hint + secondary download */} + {isDataOutput && ( + <> +
+ + {t.toolPage.dataResultsHint} +
+ + + )} + + {/* Download button -- primary for non-data tools */} + {!isDataOutput && ( + + )} {/* Adjust settings */}