import { apiFetch, type PaginatedResponse } from './api'; export interface FileResponse { id: string; vehicle_id: string; original_filename: string; stored_filename: string; file_path: string; mime_type: string; file_size: number; thumbnail_path: string | null; created_at?: string; updated_at?: string; } export interface FileListResponse extends PaginatedResponse {} export interface FileDeleteResponse { message: string; id: string; } export const ALLOWED_MIME_TYPES = [ 'image/jpeg', 'image/png', 'image/webp', 'application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', ]; export const MAX_FILE_SIZE_MB = 20; export const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024; export function isImageMime(mime: string): boolean { return mime.startsWith('image/'); } export function formatFileSize(bytes: number): string { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; } export async function listFiles( vehicleId: string, page = 1, pageSize = 20 ): Promise { return apiFetch( `/vehicles/${vehicleId}/files?page=${page}&page_size=${pageSize}` ); } export async function uploadFile( vehicleId: string, file: File ): Promise { const token = typeof window !== 'undefined' ? localStorage.getItem('access_token') : null; const formData = new FormData(); formData.append('file', file); const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api/v1'; const response = await fetch(`${API_BASE_URL}/vehicles/${vehicleId}/files`, { method: 'POST', headers: { ...(token ? { Authorization: `Bearer ${token}` } : {}), }, body: formData, }); if (response.status === 401 && token) { const refreshToken = typeof window !== 'undefined' ? localStorage.getItem('refresh_token') : null; if (refreshToken) { const refreshResult = await apiFetch<{ access_token: string; refresh_token: string }>( '/auth/refresh', { method: 'POST', body: JSON.stringify({ refresh_token: refreshToken }) } ); localStorage.setItem('access_token', refreshResult.access_token); localStorage.setItem('refresh_token', refreshResult.refresh_token); const retryResponse = await fetch(`${API_BASE_URL}/vehicles/${vehicleId}/files`, { method: 'POST', headers: { Authorization: `Bearer ${refreshResult.access_token}` }, body: formData, }); if (!retryResponse.ok) { const err = await retryResponse.json().catch(() => ({ error: { code: 'UNKNOWN', message: 'Upload failed' } })); throw err; } return retryResponse.json(); } } if (!response.ok) { const err = await response.json().catch(() => ({ error: { code: 'UNKNOWN', message: 'Upload failed' } })); throw err; } return response.json(); } export async function deleteFile( vehicleId: string, fileId: string ): Promise { return apiFetch( `/vehicles/${vehicleId}/files/${fileId}`, { method: 'DELETE' } ); } export function getFileDownloadUrl(vehicleId: string, fileId: string): string { const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api/v1'; return `${API_BASE_URL}/vehicles/${vehicleId}/files/${fileId}`; } export function getThumbnailUrl(file: FileResponse): string | null { if (!file.thumbnail_path) return null; const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000/api/v1'; return `${API_BASE_URL}/vehicles/${file.vehicle_id}/files/${file.id}`; }