import { useState } from 'react' import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { useMutation } from '@tanstack/react-query' import FileUpload from '@/components/FileUpload' import { Button } from '@/components/ui/button' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { useToast } from '@/components/ui/toast' import { useUploadStore } from '@/store/uploadStore' import { apiClientV2 } from '@/services/apiV2' import { FileText, X, Upload, Trash2, CheckCircle2, ArrowRight } from 'lucide-react' export default function UploadPage() { const { t } = useTranslation() const navigate = useNavigate() const { toast } = useToast() const [selectedFiles, setSelectedFiles] = useState([]) const { setBatchId, setUploadProgress } = useUploadStore() const uploadMutation = useMutation({ mutationFn: async (files: File[]) => { // Upload files one by one and collect task IDs const tasks = [] for (const file of files) { const result = await apiClientV2.uploadFile(file) tasks.push(result) } return tasks }, onSuccess: (tasks) => { // Use the first task_id as the current batch identifier // Note: Type assertion needed - store expects number but API returns string UUID if (tasks.length > 0) { setBatchId(tasks[0].task_id as unknown as number) } toast({ title: t('upload.uploadSuccess'), description: `成功上傳 ${tasks.length} 個檔案`, variant: 'success', }) navigate('/processing') }, onError: (error: any) => { toast({ title: t('upload.uploadError'), description: error.response?.data?.detail || t('errors.networkError'), variant: 'destructive', }) }, }) const handleFilesSelected = (files: File[]) => { setSelectedFiles((prev) => [...prev, ...files]) } const handleRemoveFile = (index: number) => { setSelectedFiles((prev) => prev.filter((_, i) => i !== index)) } const handleClearAll = () => { setSelectedFiles([]) setUploadProgress(0) } const handleUpload = () => { if (selectedFiles.length === 0) { toast({ title: t('errors.validationError'), description: '請選擇至少一個檔案', variant: 'destructive', }) return } uploadMutation.mutate(selectedFiles) } const formatFileSize = (bytes: number) => { if (bytes === 0) return '0 Bytes' const k = 1024 const sizes = ['Bytes', 'KB', 'MB', 'GB'] const i = Math.floor(Math.log(bytes) / Math.log(k)) return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i] } const getFileIcon = (filename: string) => { const ext = filename.split('.').pop()?.toLowerCase() const colors = { pdf: 'text-red-500', doc: 'text-blue-500', docx: 'text-blue-500', ppt: 'text-orange-500', pptx: 'text-orange-500', jpg: 'text-green-500', jpeg: 'text-green-500', png: 'text-green-500', } return colors[ext as keyof typeof colors] || 'text-gray-500' } const totalSize = selectedFiles.reduce((acc, file) => acc + file.size, 0) return (
{/* Page Header */}

{t('upload.title')}

選擇要進行 OCR 處理的檔案,支援圖片、PDF 和 Office 文件

{/* Step Indicator */}
{selectedFiles.length === 0 ? '1' : }
選擇檔案
上傳要處理的文件
0 ? 'bg-primary text-white' : 'bg-muted text-muted-foreground' }`}> 2
0 ? 'text-foreground' : 'text-muted-foreground' }`}>確認並上傳
檢查並開始處理
3
處理完成
查看結果並導出
{/* Upload Area */}
{/* Selected Files Section */} {selectedFiles.length > 0 && (
{/* Summary Card */}
{t('upload.selectedFiles')}

已選擇 {selectedFiles.length} 個檔案,總大小 {formatFileSize(totalSize)}

{/* Files Table */}
{selectedFiles.map((file, index) => (
{/* File icon */}
{/* File info */}

{file.name}

{formatFileSize(file.size)} · {file.type || '未知類型'}

{/* Status badge */}
準備就緒
{/* Remove button */}
))}
{/* Action Bar */}
請確認檔案無誤後點擊上傳按鈕開始處理
)}
) }