import { useState, useEffect } from 'react'; import { useApiRequest } from './useApi'; // File interfaces export interface FileInfo { id: number; name: string; mimeType: string; size?: number; creationDate: string; fileHash?: string; mandateId?: number; userId?: number; workflowId?: string; source?: string; // 'user_uploaded', 'agent_created', or 'shared_with_me' } export interface UserFile { id: number; file_name: string; action: string; created_at: string; size?: number; source?: string; // 'user_uploaded', 'agent_created', or 'shared_with_me' } // Files list hook export function useUserFiles() { const [files, setFiles] = useState([]); const { request, isLoading: loading, error } = useApiRequest(); const fetchFiles = async () => { try { const data = await request({ url: '/api/files', method: 'get' }); // Map API response to our frontend model const mappedFiles = data.map((apiFile: FileInfo): UserFile => { // Derive a simplified action from the MIME type let action = 'Document'; if (apiFile.mimeType) { const mimePrefix = apiFile.mimeType.split('/')[0]; switch (mimePrefix) { case 'image': action = 'Bild'; break; case 'application': if (apiFile.mimeType.includes('pdf')) { action = 'PDF'; } else if (apiFile.mimeType.includes('word') || apiFile.mimeType.includes('office')) { action = 'Dokument'; } else if (apiFile.mimeType.includes('excel') || apiFile.mimeType.includes('spreadsheet')) { action = 'Tabelle'; } else { action = 'Datei'; } break; case 'text': action = 'Text'; break; case 'video': action = 'Video'; break; case 'audio': action = 'Audio'; break; default: action = 'Datei'; } } return { id: apiFile.id, file_name: apiFile.name, action: action, created_at: apiFile.creationDate, size: apiFile.size, source: apiFile.source }; }); setFiles(mappedFiles); } catch (error) { // Error is already handled by useApiRequest } }; // Optimistically remove a file from the local state const removeFileOptimistically = (fileId: number) => { setFiles(prevFiles => prevFiles.filter(file => file.id !== fileId)); }; // Add a file to the local state (for when upload completes) const addFileOptimistically = (newFile: UserFile) => { setFiles(prevFiles => [newFile, ...prevFiles]); }; useEffect(() => { fetchFiles(); }, []); return { files, loading, error, refetch: fetchFiles, removeFileOptimistically, addFileOptimistically }; } // File operations hook export function useFileOperations() { const [downloadingFiles, setDownloadingFiles] = useState>(new Set()); const [deletingFiles, setDeletingFiles] = useState>(new Set()); const [uploadingFile, setUploadingFile] = useState(false); const { request, error: apiError, isLoading } = useApiRequest(); const [downloadError, setDownloadError] = useState(null); const [deleteError, setDeleteError] = useState(null); const [uploadError, setUploadError] = useState(null); const handleFileDownload = async (fileId: number, fileName: string) => { setDownloadError(null); setDownloadingFiles(prev => new Set(prev).add(fileId)); try { const blob = await request({ url: `/api/files/${fileId}`, method: 'get', // Override axios config for blob response additionalConfig: { responseType: 'blob' } }); // Create a download link and trigger the download const url = window.URL.createObjectURL(new Blob([blob])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', fileName); document.body.appendChild(link); link.click(); document.body.removeChild(link); window.URL.revokeObjectURL(url); return true; } catch (error: any) { setDownloadError(error.message); return false; } finally { setDownloadingFiles(prev => { const newSet = new Set(prev); newSet.delete(fileId); return newSet; }); } }; const handleFileDelete = async (fileId: number, onOptimisticDelete?: () => void) => { setDeleteError(null); setDeletingFiles(prev => new Set(prev).add(fileId)); // Optimistically remove from UI if callback provided if (onOptimisticDelete) { onOptimisticDelete(); } try { await request({ url: `/api/files/${fileId}`, method: 'delete' }); // Add a small delay to ensure backend has time to process await new Promise(resolve => setTimeout(resolve, 300)); return true; } catch (error: any) { setDeleteError(error.message); // If deletion failed and we optimistically removed it, we should refetch to restore the file return false; } finally { setDeletingFiles(prev => { const newSet = new Set(prev); newSet.delete(fileId); return newSet; }); } }; const handleFileUpload = async (file: globalThis.File, workflowId?: string) => { setUploadError(null); setUploadingFile(true); try { const formData = new FormData(); formData.append('file', file); if (workflowId) { formData.append('workflowId', workflowId); } const fileData = await request({ url: '/api/files/upload', method: 'post', data: formData, // Override axios config for form data additionalConfig: { headers: { 'Content-Type': 'multipart/form-data', } } }); return { success: true, fileData }; } catch (error: any) { setUploadError(error.message); return { success: false, error: error.message }; } finally { setUploadingFile(false); } }; return { downloadingFiles, deletingFiles, uploadingFile, downloadError, deleteError, uploadError, handleFileDownload, handleFileDelete, handleFileUpload, isLoading }; }