import axios from "axios"; import apiClient from '@/lib/api/axios-instance'; import { createHeaders } from '@/lib/api'; import { API_BASE_URL } from "@/config"; // Create API_URL from API_BASE_URL const API_URL = `${API_BASE_URL}/api`; export interface Attachment { attachmentId: number; fileName: string; fileType: string; filePath: string; entityType: string; entityId: number; description?: string; createdAt?: string; createdBy?: string; } export interface AttachmentCreateRequest { attachmentId: number; fileName: string; fileType: string; filePath: string; entityType: string; entityId: number; description?: string; _IFormFile: File; } export interface DownloadResult { blob: Blob; fileName: string; contentType: string; } export interface DownloadProgressCallback { (progress: number, totalSize: number): void; } export const attachmentApi = { getAll: async (): Promise => { try { const response = await apiClient.get(`${API_URL}/Attachments`); return response.data; } catch (error) { console.error("Error fetching all attachments:", error); throw error; } }, getById: async (id: number): Promise => { try { const response = await apiClient.get(`${API_URL}/Attachments/${id}`); return response.data; } catch (error) { console.error(`Error fetching attachment with ID ${id}:`, error); throw error; } }, getByEntityTypeAndId: async (entityType: string, entityId: number): Promise => { try { const response = await apiClient.get(`${API_URL}/Attachments/${entityType}/${entityId}`); return response.data; } catch (error) { console.error(`Error fetching attachments for ${entityType} with ID ${entityId}:`, error); throw error; } }, delete: async (id: number): Promise => { try { const response = await apiClient.delete(`${API_URL}/Attachments/${id}`); return response.status === 200; } catch (error) { console.error(`Error deleting attachment with ID ${id}:`, error); throw error; } }, upload: async (data: FormData): Promise => { try { const response = await apiClient.post(`${API_URL}/Attachments/uploadfile`, data, { headers: { 'Content-Type': undefined, }, }); return response.data; } catch (error) { console.error("Error uploading attachment:", error); throw error; } }, download: async (id: number, onProgress?: DownloadProgressCallback): Promise => { try { // First get the attachment info to determine the correct filename const attachmentInfo = await attachmentApi.getById(id); // Download the file with the blob response type const response = await apiClient.get(`${API_URL}/Attachments/download/${id}`, { responseType: 'blob', }); // Extract content type from headers or use default const contentType = response.headers['content-type'] || attachmentInfo.fileType || 'application/octet-stream'; // Extract filename from Content-Disposition header if available const contentDisposition = response.headers['content-disposition'] || ''; let fileName = attachmentInfo.fileName; // Try to extract filename from Content-Disposition header const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/); if (filenameMatch && filenameMatch[1]) { const extractedName = filenameMatch[1].replace(/['"]/g, ''); if (extractedName) { fileName = extractedName; } } console.log(`Downloaded file: ${fileName}, content-type: ${contentType}, size: ${response.data.size} bytes`); return { blob: response.data, fileName, contentType }; } catch (error) { console.error(`Error downloading attachment with ID ${id}:`, error); throw error; } }, // Method to directly trigger a file download downloadAndSave: async (id: number, onProgress?: DownloadProgressCallback): Promise => { try { const result = await attachmentApi.download(id, onProgress); // Create a URL for the blob const url = window.URL.createObjectURL(result.blob); // Create a download link const link = document.createElement('a'); link.href = url; link.download = result.fileName; // Add to document, click and remove document.body.appendChild(link); link.click(); document.body.removeChild(link); // Release the object URL window.URL.revokeObjectURL(url); console.log(`File "${result.fileName}" downloaded successfully`); } catch (error) { console.error(`Error downloading and saving attachment with ID ${id}:`, error); throw error; } }, // Method to get a temporary view URL for an attachment getViewUrl: async (id: number): Promise => { try { // Get attachment info to check file type const attachment = await attachmentApi.getById(id); const fileType = attachment.fileType.toLowerCase(); // Check if it's a viewable file type const isViewableType = fileType.includes('image') || fileType.includes('pdf') || fileType.includes('text') || fileType.includes('html') || fileType.includes('.jpg') || fileType.includes('.jpeg') || fileType.includes('.png') || fileType.includes('.gif') || fileType.includes('.webp') || fileType.includes('.pdf') || fileType.includes('.txt') || fileType.includes('.html'); if (!isViewableType) { throw new Error(`File type ${fileType} is not supported for preview`); } // Download the file as a blob and create a URL const result = await attachmentApi.download(id); const url = window.URL.createObjectURL(result.blob); return url; } catch (error) { console.error(`Error creating view URL for attachment with ID ${id}:`, error); throw error; } }, // Check if file is viewable isViewable: (attachment: Attachment): boolean => { const fileType = attachment.fileType.toLowerCase(); const fileName = attachment.fileName.toLowerCase(); // Check if it's a viewable file type return ( fileType.includes('image') || fileType.includes('pdf') || fileType.includes('text') || fileType.includes('html') || fileName.endsWith('.jpg') || fileName.endsWith('.jpeg') || fileName.endsWith('.png') || fileName.endsWith('.gif') || fileName.endsWith('.webp') || fileName.endsWith('.pdf') || fileName.endsWith('.txt') || fileName.endsWith('.html') ); } };