import { defineStore } from "pinia"; import { ref, computed } from "vue"; import FileService, { type FileResource, type FileListParams, type CreateFilePayload, type UpdateFilePayload, type FileListResponse, type OrganizedFileStructure, type StorageStatistics, } from "@/services/file"; export const useFileStore = defineStore("file", () => { // State const files = ref([]); const currentFile = ref(null); const loading = ref(false); const error = ref(null); const uploadProgress = ref(0); const selectedFiles = ref([]); // Pagination state const pagination = ref({ current_page: 1, last_page: 1, per_page: 15, total: 0, }); // Filter state const filters = ref({ search: '', category: '', client_id: undefined, mime_type: '', date_from: '', date_to: '', sort_by: 'uploaded_at', sort_direction: 'desc', }); // Organization state const organizedFiles = ref({}); const storageStats = ref(null); // Getters const allFiles = computed(() => files.value); const filesByCategory = computed(() => { const grouped: Record = {}; files.value.forEach(file => { const category = file.category || 'general'; if (!grouped[category]) { grouped[category] = []; } grouped[category].push(file); }); return grouped; }); const filesByClient = computed(() => { const grouped: Record = {}; files.value.forEach(file => { const clientId = extractClientIdFromPath(file.storage_uri); if (clientId) { if (!grouped[clientId]) { grouped[clientId] = []; } grouped[clientId].push(file); } }); return grouped; }); const imageFiles = computed(() => files.value.filter(file => file.is_image) ); const pdfFiles = computed(() => files.value.filter(file => file.is_pdf) ); const recentFiles = computed(() => [...files.value] .sort((a, b) => new Date(b.uploaded_at).getTime() - new Date(a.uploaded_at).getTime()) .slice(0, 10) ); const isLoading = computed(() => loading.value); const hasError = computed(() => error.value !== null); const getError = computed(() => error.value); const hasFiles = computed(() => files.value.length > 0); const getPagination = computed(() => pagination.value); const getFilters = computed(() => filters.value); const getUploadProgress = computed(() => uploadProgress.value); const getFileById = computed(() => (id: number) => files.value.find(file => file.id === id) ); const getSelectedFiles = computed(() => files.value.filter(file => selectedFiles.value.includes(file.id)) ); const totalSizeFormatted = computed(() => { const totalSize = files.value.reduce((sum, file) => sum + (file.size_bytes || 0), 0); return FileService.formatFileSize(totalSize); }); // Actions const setLoading = (isLoading: boolean) => { loading.value = isLoading; }; const setError = (err: string | null) => { error.value = err; }; const clearError = () => { error.value = null; }; const setFiles = (newFiles: FileResource[]) => { files.value = newFiles; }; const setCurrentFile = (file: FileResource | null) => { currentFile.value = file; }; const setPagination = (meta: any) => { if (meta) { pagination.value = { current_page: meta.current_page || 1, last_page: meta.last_page || 1, per_page: meta.per_page || 15, total: meta.total || 0, }; } }; const setFilters = (newFilters: Partial) => { filters.value = { ...filters.value, ...newFilters }; }; const clearFilters = () => { filters.value = { search: '', category: '', client_id: undefined, mime_type: '', date_from: '', date_to: '', sort_by: 'uploaded_at', sort_direction: 'desc', }; }; const setUploadProgress = (progress: number) => { uploadProgress.value = progress; }; const selectFile = (fileId: number) => { if (!selectedFiles.value.includes(fileId)) { selectedFiles.value.push(fileId); } }; const deselectFile = (fileId: number) => { selectedFiles.value = selectedFiles.value.filter(id => id !== fileId); }; const selectAllFiles = () => { selectedFiles.value = files.value.map(file => file.id); }; const deselectAllFiles = () => { selectedFiles.value = []; }; /** * Récupérer tous les fichiers avec pagination et filtres */ const fetchFiles = async (params?: FileListParams) => { setLoading(true); setError(null); try { const queryParams = { ...filters.value, ...params }; const response = await FileService.getAllFiles(queryParams); setFiles(response.data); setPagination(response.pagination); return response; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec du chargement des fichiers"; setError(errorMessage); throw err; } finally { setLoading(false); } }; /** * Récupérer un seul fichier par ID */ const fetchFile = async (id: number) => { setLoading(true); setError(null); try { const response = await FileService.getFile(id); setCurrentFile(response.data); return response.data; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec du chargement du fichier"; setError(errorMessage); throw err; } finally { setLoading(false); } }; /** * Télécharger un nouveau fichier */ const uploadFile = async (payload: CreateFilePayload) => { setLoading(true); setError(null); setUploadProgress(0); try { // Validate file before upload const validation = FileService.validateFile(payload.file); if (!validation.valid) { throw new Error(validation.error); } const response = await FileService.uploadFile(payload); // Add the new file to the beginning of the list files.value.unshift(response.data); setCurrentFile(response.data); return response.data; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec du téléchargement du fichier"; setError(errorMessage); throw err; } finally { setLoading(false); setUploadProgress(0); } }; /** * Mettre à jour les métadonnées d'un fichier */ const updateFile = async (payload: UpdateFilePayload) => { setLoading(true); setError(null); try { const response = await FileService.updateFile(payload); const updatedFile = response.data; // Update in files list const index = files.value.findIndex(file => file.id === updatedFile.id); if (index !== -1) { files.value[index] = updatedFile; } // Update current file if it's the one being edited if (currentFile.value && currentFile.value.id === updatedFile.id) { setCurrentFile(updatedFile); } return updatedFile; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec de la mise à jour du fichier"; setError(errorMessage); throw err; } finally { setLoading(false); } }; /** * Supprimer un fichier */ const deleteFile = async (id: number) => { setLoading(true); setError(null); try { await FileService.deleteFile(id); // Remove from files list files.value = files.value.filter(file => file.id !== id); // Remove from selection if selected deselectFile(id); // Clear current file if it's the one being deleted if (currentFile.value && currentFile.value.id === id) { setCurrentFile(null); } return { success: true, message: "Fichier supprimé avec succès" }; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec de la suppression du fichier"; setError(errorMessage); throw err; } finally { setLoading(false); } }; /** * Supprimer plusieurs fichiers */ const deleteMultipleFiles = async (fileIds: number[]) => { setLoading(true); setError(null); try { const results = await Promise.allSettled( fileIds.map(id => FileService.deleteFile(id)) ); // Filter out successful deletions const successfulIds = fileIds.filter((_, index) => results[index].status === 'fulfilled' ); // Remove successful deletions from the list files.value = files.value.filter(file => !successfulIds.includes(file.id)); // Clear selections successfulIds.forEach(id => deselectFile(id)); return { success: true, deleted: successfulIds.length, total: fileIds.length }; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec de la suppression des fichiers"; setError(errorMessage); throw err; } finally { setLoading(false); } }; /** * Récupérer les fichiers par catégorie */ const fetchFilesByCategory = async (category: string, params?: { page?: number; per_page?: number }) => { setLoading(true); setError(null); try { const response = await FileService.getFilesByCategory(category, params); setFiles(response.data); setPagination(response.pagination); return response; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec du chargement des fichiers par catégorie"; setError(errorMessage); throw err; } finally { setLoading(false); } }; /** * Récupérer les fichiers par client */ const fetchFilesByClient = async (clientId: number, params?: { page?: number; per_page?: number }) => { setLoading(true); setError(null); try { const response = await FileService.getFilesByClient(clientId, params); setFiles(response.data); setPagination(response.pagination); return response; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec du chargement des fichiers du client"; setError(errorMessage); throw err; } finally { setLoading(false); } }; /** * Récupérer la structure organisée des fichiers */ const fetchOrganizedStructure = async () => { setLoading(true); setError(null); try { const response = await FileService.getOrganizedStructure(); organizedFiles.value = response.data; return response.data; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec du chargement de la structure organisée"; setError(errorMessage); throw err; } finally { setLoading(false); } }; /** * Récupérer les statistiques de stockage */ const fetchStorageStatistics = async () => { setLoading(true); setError(null); try { const response = await FileService.getStorageStatistics(); storageStats.value = response.data; return response.data; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec du chargement des statistiques"; setError(errorMessage); throw err; } finally { setLoading(false); } }; /** * Générer une URL de téléchargement */ const generateDownloadUrl = async (fileId: number) => { try { const response = await FileService.generateDownloadUrl(fileId); return response.data.download_url; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec de la génération de l'URL de téléchargement"; setError(errorMessage); throw err; } }; /** * Rechercher des fichiers */ const searchFiles = async (query: string, params?: { page?: number; per_page?: number }) => { setLoading(true); setError(null); try { const searchParams = { ...filters.value, search: query, ...params }; const response = await FileService.getAllFiles(searchParams); setFiles(response.data); setPagination(response.pagination); return response; } catch (err: any) { const errorMessage = err.response?.data?.message || err.message || "Échec de la recherche de fichiers"; setError(errorMessage); throw err; } finally { setLoading(false); } }; /** * Télécharger un fichier */ const downloadFile = async (fileId: number) => { try { const downloadUrl = await generateDownloadUrl(fileId); // Create a temporary link to trigger download const link = document.createElement('a'); link.href = downloadUrl; link.download = ''; document.body.appendChild(link); link.click(); document.body.removeChild(link); return { success: true }; } catch (err: any) { throw err; } }; /** * Extraire l'ID client du chemin de stockage */ const extractClientIdFromPath = (storageUri: string): number | null => { const pathParts = storageUri.split('/'); if (pathParts.length >= 4 && pathParts[0] === 'client') { const clientId = parseInt(pathParts[1]); return isNaN(clientId) ? null : clientId; } return null; }; /** * Réinitialiser l'état */ const resetState = () => { files.value = []; currentFile.value = null; loading.value = false; error.value = null; uploadProgress.value = 0; selectedFiles.value = []; pagination.value = { current_page: 1, last_page: 1, per_page: 15, total: 0, }; clearFilters(); organizedFiles.value = {}; storageStats.value = null; }; return { // State files, currentFile, loading, error, uploadProgress, selectedFiles, pagination, filters, organizedFiles, storageStats, // Getters allFiles, filesByCategory, filesByClient, imageFiles, pdfFiles, recentFiles, isLoading, hasError, getError, hasFiles, getPagination, getFilters, getUploadProgress, getFileById, getSelectedFiles, totalSizeFormatted, // Actions setLoading, setError, clearError, setFiles, setCurrentFile, setPagination, setFilters, clearFilters, setUploadProgress, selectFile, deselectFile, selectAllFiles, deselectAllFiles, fetchFiles, fetchFile, uploadFile, updateFile, deleteFile, deleteMultipleFiles, fetchFilesByCategory, fetchFilesByClient, fetchOrganizedStructure, fetchStorageStatistics, generateDownloadUrl, searchFiles, downloadFile, resetState, }; }); export default useFileStore;