'use client'; import * as React from 'react'; import { Download, CheckCircle, XCircle, Loader2, Clock, TrendingUp, RefreshCw } from 'lucide-react'; import { cn, actionBtn } from '@/lib/utils'; import { downloadBlob, formatFileSize, generateOutputFilename } from '@/lib/media/utils/fileUtils'; import type { ConversionJob } from '@/types/media'; export interface ConversionPreviewProps { job: ConversionJob; onRetry?: () => void; } export function ConversionPreview({ job, onRetry }: ConversionPreviewProps) { const [previewUrl, setPreviewUrl] = React.useState(null); const [elapsedTime, setElapsedTime] = React.useState(0); const [estimatedRemaining, setEstimatedRemaining] = React.useState(null); React.useEffect(() => { if (job.status === 'processing' || job.status === 'loading') { const interval = setInterval(() => { if (job.startTime) { const elapsed = Date.now() - job.startTime; setElapsedTime(elapsed); if (job.progress > 5 && job.progress < 100) { const rate = job.progress / elapsed; setEstimatedRemaining((100 - job.progress) / rate); } } }, 100); return () => clearInterval(interval); } else { setEstimatedRemaining(null); } }, [job.status, job.startTime, job.progress]); React.useEffect(() => { if (job.result && job.status === 'completed') { const url = URL.createObjectURL(job.result); setPreviewUrl(url); return () => URL.revokeObjectURL(url); } else { setPreviewUrl(null); } }, [job.result, job.status]); const handleDownload = () => { if (job.result) { downloadBlob(job.result, generateOutputFilename(job.inputFile.name, job.outputFormat.extension)); } }; const fmt = (ms: number) => { const s = Math.floor(ms / 1000); if (s < 60) return `${s}s`; return `${Math.floor(s / 60)}m ${s % 60}s`; }; if (job.status === 'pending') return null; const inputSize = job.inputFile.size; const outputSize = job.result?.size ?? 0; const sizeReduction = inputSize > 0 ? ((inputSize - outputSize) / inputSize) * 100 : 0; const filename = generateOutputFilename(job.inputFile.name, job.outputFormat.extension); return (
{/* Header row */}
{(job.status === 'loading' || job.status === 'processing') && ( )} {job.status === 'completed' && ( )} {job.status === 'error' && ( )} {job.inputFile.name}
{job.inputFormat.extension} → {job.outputFormat.extension}
{/* Loading state */} {job.status === 'loading' && (
Loading converter… {fmt(elapsedTime)}
)} {/* Processing state */} {job.status === 'processing' && (
{fmt(elapsedTime)} {estimatedRemaining && ( <> ~{fmt(estimatedRemaining)} left )}
{job.progress}%
)} {/* Completed state */} {job.status === 'completed' && (
{/* Size stats */}
{formatFileSize(inputSize)} {formatFileSize(outputSize)} {Math.abs(sizeReduction) > 1 && ( 0 ? 'bg-emerald-500/15 text-emerald-400' : 'bg-white/5 text-muted-foreground/50' )}> {sizeReduction > 0 ? '↓' : '↑'}{Math.abs(sizeReduction).toFixed(0)}% )} {job.startTime && job.endTime && ( {((job.endTime - job.startTime) / 1000).toFixed(1)}s )}
{/* Media preview */} {previewUrl && (() => { switch (job.outputFormat.category) { case 'image': return (
Preview
); case 'video': return (
); case 'audio': return (
); default: return null; } })()} {/* Download */}
)} {/* Error state */} {job.status === 'error' && (
{job.error && (

{job.error}

)} {onRetry && ( )}
)}
); }