diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 80c29ce..0db8f5a 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -1,4 +1,4 @@ -import { Outlet, NavLink } from 'react-router-dom' +import { Outlet, NavLink, useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { useAuthStore } from '@/store/authStore' import { apiClient } from '@/services/api' @@ -20,6 +20,7 @@ import { export default function Layout() { const { t } = useTranslation() + const navigate = useNavigate() const logout = useAuthStore((state) => state.logout) const user = useAuthStore((state) => state.user) @@ -38,6 +39,7 @@ export default function Layout() { console.error('Logout error:', error) } finally { logout() + navigate('/login') } } diff --git a/frontend/src/pages/UploadPage.tsx b/frontend/src/pages/UploadPage.tsx index eb33149..99fe318 100644 --- a/frontend/src/pages/UploadPage.tsx +++ b/frontend/src/pages/UploadPage.tsx @@ -7,7 +7,7 @@ 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 { apiClient } from '@/services/api' +import { apiClientV2 } from '@/services/apiV2' import { FileText, X, Upload, Trash2, CheckCircle2, ArrowRight } from 'lucide-react' export default function UploadPage() { @@ -18,13 +18,24 @@ export default function UploadPage() { const { setBatchId, setFiles, setUploadProgress } = useUploadStore() const uploadMutation = useMutation({ - mutationFn: (files: File[]) => apiClient.uploadFiles(files), - onSuccess: (data) => { - setBatchId(data.batch_id) - setFiles(data.files) + 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) => { + // For now, just use the first task_id as batch_id + // TODO: Update store to handle multiple tasks + if (tasks.length > 0) { + setBatchId(tasks[0].task_id as any) // temporary workaround + } toast({ title: t('upload.uploadSuccess'), - description: t('upload.fileCount', { count: data.files.length }), + description: `成功上傳 ${tasks.length} 個檔案`, variant: 'success', }) navigate('/processing') diff --git a/frontend/src/services/apiV2.ts b/frontend/src/services/apiV2.ts index 9a26720..820a085 100644 --- a/frontend/src/services/apiV2.ts +++ b/frontend/src/services/apiV2.ts @@ -284,6 +284,24 @@ class ApiClientV2 { return response.data.sessions } + // ==================== File Upload ==================== + + /** + * Upload a file + */ + async uploadFile(file: File): Promise<{ task_id: string; filename: string; file_size: number; file_type: string; status: string }> { + const formData = new FormData() + formData.append('file', file) + + const response = await this.client.post('/upload', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }) + + return response.data + } + // ==================== Task Management ==================== /**