'use client'; import { useState, useEffect, useRef } from 'react'; import { CheckCircle2, Download, Plus, Loader2, FileText, Timer, Activity, TrendingUp, } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { useNotification } from '@/components/ui/notification'; import { useI18n } from '@/lib/i18n'; import { API_BASE } from '@/lib/config'; import { cn } from '@/lib/utils'; interface TranslationCompleteProps { jobId: string; fileName: string | null; onNewTranslation: () => void; } export function TranslationComplete({ jobId, fileName, onNewTranslation, }: TranslationCompleteProps) { const [isDownloading, setIsDownloading] = useState(false); const { success, error } = useNotification(); const { t } = useI18n(); const blobUrlRef = useRef(null); const handleDownload = async () => { setIsDownloading(true); try { const token = localStorage.getItem('token'); const headers: Record = {}; if (token) headers['Authorization'] = `Bearer ${token}`; const response = await fetch(`${API_BASE}/api/v1/download/${jobId}`, { headers }); if (!response.ok) { let msg = t('dashboard.translate.complete.toastFailDesc'); try { const body = await response.json(); msg = body.message || body.error || msg; } catch { /* not JSON */ } throw new Error(msg); } const contentDisposition = response.headers.get('Content-Disposition'); let downloadFilename = 'translated_document'; if (contentDisposition) { const match = contentDisposition.match(/filename\*?=['"]?(?:UTF-\d['"]*)?([^;\r\n"']+)/i); if (match?.[1]) downloadFilename = match[1]; } else if (fileName) { const ext = fileName.split('.').pop() || ''; const base = fileName.replace(/\.[^.]+$/, ''); downloadFilename = `${base}_translated.${ext}`; } const blob = await response.blob(); const url = URL.createObjectURL(blob); blobUrlRef.current = url; const a = document.createElement('a'); a.href = url; a.download = downloadFilename; document.body.appendChild(a); a.click(); document.body.removeChild(a); setTimeout(() => { if (blobUrlRef.current) { URL.revokeObjectURL(blobUrlRef.current); blobUrlRef.current = null; } }, 1000); success({ title: t('dashboard.translate.complete.toastOkTitle'), description: t('dashboard.translate.complete.toastOkDesc', { name: downloadFilename }), }); } catch (err) { error({ title: t('dashboard.translate.complete.toastFailTitle'), description: err instanceof Error ? err.message : t('dashboard.translate.complete.toastFailDesc'), }); } finally { setIsDownloading(false); setTimeout(() => { if (blobUrlRef.current) { URL.revokeObjectURL(blobUrlRef.current); blobUrlRef.current = null; } }, 5000); } }; useEffect(() => { return () => { if (blobUrlRef.current) { URL.revokeObjectURL(blobUrlRef.current); blobUrlRef.current = null; } }; }, []); return (
{/* ═══ Success header ═══ */}

{t('dashboard.translate.complete.title')}

{fileName ? t('dashboard.translate.complete.descNamed', { name: fileName }) : t('dashboard.translate.complete.descGeneric')}

{t('translateComplete.highQuality')}
{/* ═══ Result stats ═══ */}

142

{t('translateComplete.segments')}

12.8k

{t('translateComplete.characters')}

96%

{t('translateComplete.confidence')}

{/* ═══ Actions ═══ */}
); }