'use client'; import * as React from 'react'; import { Download, CheckCircle, XCircle, Loader2, Clock, TrendingUp, FileCheck2, ArrowRight, RefreshCw } from 'lucide-react'; import { cn } from '@/lib/utils/cn'; import { Button } from '@/components/ui/Button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/Card'; import { Progress } from '@/components/ui/Progress'; import { downloadBlob, formatFileSize, generateOutputFilename } from '@/lib/utils/fileUtils'; import type { ConversionJob } from '@/types/conversion'; export interface ConversionPreviewProps { job: ConversionJob; onDownload?: () => void; onRetry?: () => void; } export function ConversionPreview({ job, onDownload, onRetry }: ConversionPreviewProps) { const [previewUrl, setPreviewUrl] = React.useState(null); const [elapsedTime, setElapsedTime] = React.useState(0); const [estimatedTimeRemaining, setEstimatedTimeRemaining] = React.useState(null); // Timer for elapsed time and estimation React.useEffect(() => { if (job.status === 'processing' || job.status === 'loading') { const interval = setInterval(() => { if (job.startTime) { const elapsed = Date.now() - job.startTime; setElapsedTime(elapsed); // Estimate time remaining based on progress if (job.progress > 5 && job.progress < 100) { const progressRate = job.progress / elapsed; const remainingProgress = 100 - job.progress; const estimated = remainingProgress / progressRate; setEstimatedTimeRemaining(estimated); } } }, 100); return () => clearInterval(interval); } else { setEstimatedTimeRemaining(null); } }, [job.status, job.startTime, job.progress]); // Create preview URL for result React.useEffect(() => { if (job.result && job.status === 'completed') { console.log('[Preview] Creating object URL for blob'); const url = URL.createObjectURL(job.result); setPreviewUrl(url); console.log('[Preview] Object URL created:', url); return () => { console.log('[Preview] Revoking object URL:', url); URL.revokeObjectURL(url); }; } else { setPreviewUrl(null); } }, [job.result, job.status]); const handleDownload = () => { if (job.result) { const filename = generateOutputFilename(job.inputFile.name, job.outputFormat.extension); downloadBlob(job.result, filename); onDownload?.(); } }; const renderPreview = () => { if (!previewUrl || !job.result) return null; const category = job.outputFormat.category; // Log blob details for debugging console.log('[Preview] Blob details:', { size: job.result.size, type: job.result.type, previewUrl, outputFormat: job.outputFormat.extension, }); switch (category) { case 'image': return (
Converted image preview { console.error('[Preview] Image failed to load:', { src: previewUrl, blobSize: job.result?.size, blobType: job.result?.type, error: e, }); }} onLoad={() => { console.log('[Preview] Image loaded successfully'); }} />
); case 'video': return (
); case 'audio': return (
); default: return null; } }; const formatTime = (ms: number) => { const seconds = Math.floor(ms / 1000); if (seconds < 60) return `${seconds}s`; const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; return `${minutes}m ${remainingSeconds}s`; }; const renderStatus = () => { switch (job.status) { case 'loading': return (
Loading WASM converter...
Elapsed: {formatTime(elapsedTime)}
); case 'processing': return (
Converting...
{job.progress}%
Elapsed: {formatTime(elapsedTime)}
{estimatedTimeRemaining && (
~{formatTime(estimatedTimeRemaining)} remaining
)}
); case 'completed': const inputSize = job.inputFile.size; const outputSize = job.result?.size || 0; const sizeReduction = inputSize > 0 ? ((inputSize - outputSize) / inputSize) * 100 : 0; return (
Conversion complete!
{/* File size comparison */}
Input:
{formatFileSize(inputSize)}
Output:
{formatFileSize(outputSize)} {Math.abs(sizeReduction) > 1 && ( 0 ? "bg-success/10 text-success" : "bg-info/10 text-info" )}> {sizeReduction > 0 ? '-' : '+'}{Math.abs(sizeReduction).toFixed(0)}% )}
); case 'error': return (
Conversion failed
); default: return null; } }; if (job.status === 'pending') { return null; } return ( Conversion Status
{/* Status */} {renderStatus()} {/* Error message */} {job.error && (

{job.error}

)} {/* Retry button */} {job.status === 'error' && onRetry && ( )} {/* Preview */} {job.status === 'completed' && renderPreview()} {/* Download button */} {job.status === 'completed' && job.result && ( )} {/* Duration */} {job.status === 'completed' && job.startTime && job.endTime && (

Completed in {((job.endTime - job.startTime) / 1000).toFixed(2)}s

)}
); }