import { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { Helmet } from 'react-helmet-async'; import { FileImage } from 'lucide-react'; import AdSlot from '@/components/layout/AdSlot'; import ProgressBar from '@/components/shared/ProgressBar'; import DownloadButton from '@/components/shared/DownloadButton'; import { useTaskPolling } from '@/hooks/useTaskPolling'; import { generateToolSchema } from '@/utils/seo'; import { useFileStore } from '@/stores/fileStore'; export default function ImagesToPdf() { const { t } = useTranslation(); const [phase, setPhase] = useState<'upload' | 'processing' | 'done'>('upload'); const [files, setFiles] = useState([]); const [isUploading, setIsUploading] = useState(false); const [taskId, setTaskId] = useState(null); const [error, setError] = useState(null); const { status, result, error: taskError } = useTaskPolling({ taskId, onComplete: () => setPhase('done'), onError: () => setPhase('done'), }); // Accept file from homepage smart upload const storeFile = useFileStore((s) => s.file); const clearStoreFile = useFileStore((s) => s.clearFile); useEffect(() => { if (storeFile) { setFiles((prev) => [...prev, storeFile]); clearStoreFile(); } }, []); // eslint-disable-line react-hooks/exhaustive-deps const acceptedTypes = ['image/png', 'image/jpeg', 'image/webp', 'image/bmp']; const handleFilesSelect = (newFiles: FileList | File[]) => { const fileArray = Array.from(newFiles).filter((f) => acceptedTypes.includes(f.type) ); if (fileArray.length === 0) { setError(t('tools.imagesToPdf.invalidFiles')); return; } setFiles((prev) => [...prev, ...fileArray]); setError(null); }; const removeFile = (index: number) => { setFiles((prev) => prev.filter((_, i) => i !== index)); }; const handleUpload = async () => { if (files.length < 1) { setError(t('tools.imagesToPdf.minFiles')); return; } setIsUploading(true); setError(null); try { const formData = new FormData(); files.forEach((f) => formData.append('files', f)); const response = await fetch('/api/pdf-tools/images-to-pdf', { method: 'POST', body: formData, }); const data = await response.json(); if (!response.ok) { throw new Error(data.error || 'Upload failed.'); } setTaskId(data.task_id); setPhase('processing'); } catch (err) { setError(err instanceof Error ? err.message : 'Upload failed.'); } finally { setIsUploading(false); } }; const handleReset = () => { setFiles([]); setPhase('upload'); setTaskId(null); setError(null); }; const schema = generateToolSchema({ name: t('tools.imagesToPdf.title'), description: t('tools.imagesToPdf.description'), url: `${window.location.origin}/tools/images-to-pdf`, }); return ( <> {t('tools.imagesToPdf.title')} — {t('common.appName')}

{t('tools.imagesToPdf.title')}

{t('tools.imagesToPdf.description')}

{phase === 'upload' && (
{/* Drop zone */}
document.getElementById('images-file-input')?.click()} onDragOver={(e) => e.preventDefault()} onDrop={(e) => { e.preventDefault(); if (e.dataTransfer.files) handleFilesSelect(e.dataTransfer.files); }} > { if (e.target.files) handleFilesSelect(e.target.files); e.target.value = ''; }} />

{t('common.dragDrop')}

PNG, JPG, WebP, BMP

{t('common.maxSize', { size: 10 })}

{/* File list */} {files.length > 0 && (
{files.map((f, idx) => (
{idx + 1}. {f.name}
))}

{files.length} {t('tools.imagesToPdf.imagesSelected')}

)} {error && (

{error}

)} {files.length >= 1 && ( )}
)} {phase === 'processing' && !result && ( )} {phase === 'done' && result && result.status === 'completed' && ( )} {phase === 'done' && taskError && (

{taskError}

)}
); }