'use client'; import * as React from 'react'; import { ArrowRight } from 'lucide-react'; import { Button } from '@/components/ui/Button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/Card'; import { FileUpload } from './FileUpload'; import { FormatSelector } from './FormatSelector'; import { ConversionPreview } from './ConversionPreview'; import { useToast } from '@/components/ui/Toast'; import { SUPPORTED_FORMATS, getFormatByExtension, getFormatByMimeType, getCompatibleFormats, } from '@/lib/utils/formatMappings'; import { convertWithFFmpeg } from '@/lib/converters/ffmpegService'; import { convertWithImageMagick } from '@/lib/converters/imagemagickService'; import { convertWithPandoc } from '@/lib/converters/pandocService'; import { addToHistory } from '@/lib/storage/history'; import type { ConversionJob, ConversionFormat } from '@/types/conversion'; export function FileConverter() { const { addToast } = useToast(); const [selectedFile, setSelectedFile] = React.useState(); const [inputFormat, setInputFormat] = React.useState(); const [outputFormat, setOutputFormat] = React.useState(); const [compatibleFormats, setCompatibleFormats] = React.useState([]); const [conversionJob, setConversionJob] = React.useState(); // Detect input format when file is selected React.useEffect(() => { if (!selectedFile) { setInputFormat(undefined); setOutputFormat(undefined); setCompatibleFormats([]); setConversionJob(undefined); return; } // Try to detect format from extension const ext = selectedFile.name.split('.').pop()?.toLowerCase(); let format = ext ? getFormatByExtension(ext) : undefined; // Fallback to MIME type if (!format) { format = getFormatByMimeType(selectedFile.type); } if (format) { setInputFormat(format); const compatible = getCompatibleFormats(format); setCompatibleFormats(compatible); // Auto-select first compatible format if (compatible.length > 0 && !outputFormat) { setOutputFormat(compatible[0]); } addToast(`Detected format: ${format.name}`, 'success'); } else { addToast('Could not detect file format', 'error'); setInputFormat(undefined); setCompatibleFormats([]); } }, [selectedFile]); const handleConvert = async () => { if (!selectedFile || !inputFormat || !outputFormat) { addToast('Please select a file and output format', 'error'); return; } // Create conversion job const job: ConversionJob = { id: Math.random().toString(36).substring(7), inputFile: selectedFile, inputFormat, outputFormat, options: {}, status: 'loading', progress: 0, startTime: Date.now(), }; setConversionJob(job); try { // Update status to processing setConversionJob((prev) => prev && { ...prev, status: 'processing', progress: 10 }); // Call appropriate converter let result; switch (outputFormat.converter) { case 'ffmpeg': result = await convertWithFFmpeg(selectedFile, outputFormat.extension, {}, (progress) => { setConversionJob((prev) => prev && { ...prev, progress }); }); break; case 'imagemagick': result = await convertWithImageMagick( selectedFile, outputFormat.extension, {}, (progress) => { setConversionJob((prev) => prev && { ...prev, progress }); } ); break; case 'pandoc': result = await convertWithPandoc(selectedFile, outputFormat.extension, {}, (progress) => { setConversionJob((prev) => prev && { ...prev, progress }); }); break; default: throw new Error(`Unknown converter: ${outputFormat.converter}`); } // Update job with result if (result.success && result.blob) { setConversionJob((prev) => prev && { ...prev, status: 'completed', progress: 100, result: result.blob, endTime: Date.now(), }); addToast('Conversion completed successfully!', 'success'); // Add to history addToHistory({ inputFileName: selectedFile.name, inputFormat: inputFormat.name, outputFormat: outputFormat.name, outputFileName: `output.${outputFormat.extension}`, fileSize: result.blob.size, result: result.blob, }); } else { setConversionJob((prev) => prev && { ...prev, status: 'error', error: result.error || 'Unknown error', endTime: Date.now(), }); addToast(result.error || 'Conversion failed', 'error'); } } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; setConversionJob((prev) => prev && { ...prev, status: 'error', error: errorMessage, endTime: Date.now(), }); addToast(`Conversion failed: ${errorMessage}`, 'error'); } }; const handleReset = () => { setSelectedFile(undefined); setInputFormat(undefined); setOutputFormat(undefined); setCompatibleFormats([]); setConversionJob(undefined); }; const isConvertDisabled = !selectedFile || !outputFormat || conversionJob?.status === 'loading' || conversionJob?.status === 'processing'; return (
{/* Header */} File Converter Convert videos, images, and documents directly in your browser using WebAssembly {/* File upload */} {/* Format selection */} {inputFormat && compatibleFormats.length > 0 && (
{/* Input format */}

{inputFormat.name}

{inputFormat.description}

{/* Arrow */}
{/* Output format */}
)} {/* Convert button */} {inputFormat && outputFormat && (
)}
{/* Conversion preview */} {conversionJob && }
); }