import { ref } from 'vue' import { useApi } from './useApi' import { useToast } from './useToast' import { extractCollection } from '~/shared/utils/apiHelpers' export interface Document { id: string name: string filename: string mimeType: string size: number fileUrl: string downloadUrl: string type?: string /** @deprecated Legacy Base64 data URI — use fileUrl instead */ path?: string createdAt?: string siteId?: string machineId?: string composantId?: string productId?: string pieceId?: string site?: { id: string; name?: string } | null machine?: { id: string; name?: string } | null composant?: { id: string; name?: string } | null piece?: { id: string; name?: string } | null product?: { id: string; name?: string } | null } export interface UploadContext { siteId?: string machineId?: string composantId?: string productId?: string pieceId?: string type?: string } export interface DocumentResult { success: boolean data?: Document | Document[] error?: string } interface LoadDocumentsOptions { search?: string page?: number itemsPerPage?: number orderBy?: string orderDir?: 'asc' | 'desc' attachmentFilter?: string type?: string force?: boolean } const documents = ref([]) const total = ref(0) const loading = ref(false) const loaded = ref(false) const extractTotal = (payload: unknown, fallbackLength: number): number => { const p = payload as Record | null if (typeof p?.totalItems === 'number') return p.totalItems if (typeof p?.['hydra:totalItems'] === 'number') return p['hydra:totalItems'] return fallbackLength } export function useDocuments() { const { get, patch, postFormData, delete: del } = useApi() const { showError, showSuccess } = useToast() const loadFromEndpoint = async ( endpoint: string, { updateStore = false, itemsPerPage }: { updateStore?: boolean; itemsPerPage?: number } = {}, ): Promise => { loading.value = true try { const url = itemsPerPage ? `${endpoint}${endpoint.includes('?') ? '&' : '?'}itemsPerPage=${itemsPerPage}` : endpoint const result = await get(url) if (result.success) { const data = extractCollection(result.data) if (updateStore) { documents.value = data } return { success: true, data } } if (result.error) { showError(result.error) } return result as DocumentResult } catch (error) { const err = error as Error console.error(`Erreur lors du chargement des documents (${endpoint}):`, error) showError('Impossible de charger les documents') return { success: false, error: err.message } } finally { loading.value = false } } const loadDocuments = async (options: LoadDocumentsOptions = {}): Promise => { const { search = '', page = 1, itemsPerPage = 30, orderBy = 'createdAt', orderDir = 'desc', attachmentFilter = 'all', type = 'all', force = false, } = options if (!force && loaded.value && !search && page === 1 && attachmentFilter === 'all' && type === 'all') { return { success: true, data: documents.value } } if (loading.value) { return { success: true, data: documents.value } } loading.value = true try { const params = new URLSearchParams() params.set('itemsPerPage', String(itemsPerPage)) params.set('page', String(page)) if (search && search.trim()) { params.set('name', search.trim()) } if (attachmentFilter && attachmentFilter !== 'all') { params.set(`exists[${attachmentFilter}]`, 'true') } if (type && type !== 'all') { params.set('type', type) } params.set(`order[${orderBy}]`, orderDir) const result = await get(`/documents?${params.toString()}`) if (result.success) { const items = extractCollection(result.data) documents.value = items total.value = extractTotal(result.data, items.length) loaded.value = true return { success: true, data: items } } if (result.error) { showError(result.error) } return result as DocumentResult } catch (error) { const err = error as Error console.error('Erreur lors du chargement des documents:', error) showError('Impossible de charger les documents') return { success: false, error: err.message } } finally { loading.value = false } } const loadDocumentsBySite = async ( siteId: string, options: { updateStore?: boolean } = {}, ): Promise => { if (!siteId) { return { success: false, error: 'Aucun site sélectionné' } } return loadFromEndpoint(`/documents/site/${siteId}`, { updateStore: options.updateStore ?? false }) } const loadDocumentsByMachine = async ( machineId: string, options: { updateStore?: boolean } = {}, ): Promise => { if (!machineId) { return { success: false, error: 'Aucune machine sélectionnée' } } return loadFromEndpoint(`/documents/machine/${machineId}`, { updateStore: options.updateStore ?? false }) } const loadDocumentsByComponent = async ( componentId: string, options: { updateStore?: boolean } = {}, ): Promise => { if (!componentId) { return { success: false, error: 'Aucun composant sélectionné' } } return loadFromEndpoint(`/documents/composant/${componentId}`, { updateStore: options.updateStore ?? false }) } const loadDocumentsByProduct = async ( productId: string, options: { updateStore?: boolean } = {}, ): Promise => { if (!productId) { return { success: false, error: 'Aucun produit sélectionné' } } return loadFromEndpoint(`/documents/product/${productId}`, { updateStore: options.updateStore ?? false }) } const loadDocumentsByPiece = async ( pieceId: string, options: { updateStore?: boolean } = {}, ): Promise => { if (!pieceId) { return { success: false, error: 'Aucune pièce sélectionnée' } } return loadFromEndpoint(`/documents/piece/${pieceId}`, { updateStore: options.updateStore ?? false }) } const uploadDocuments = async ( { files, context = {} }: { files: File[]; context?: UploadContext }, { updateStore = false }: { updateStore?: boolean } = {}, ): Promise => { if (!files.length) { return { success: false, error: 'Aucun fichier sélectionné' } } loading.value = true const created: Document[] = [] try { for (const file of files) { const formData = new FormData() formData.append('file', file) formData.append('name', file.name) if (context.type) formData.append('type', context.type) if (context.siteId) formData.append('siteId', context.siteId) if (context.machineId) formData.append('machineId', context.machineId) if (context.composantId) formData.append('composantId', context.composantId) if (context.productId) formData.append('productId', context.productId) if (context.pieceId) formData.append('pieceId', context.pieceId) const result = await postFormData('/documents', formData) if (result.success) { created.push(result.data as Document) showSuccess(`Document "${file.name}" ajouté`) } else if (result.error) { showError(`Erreur sur ${file.name} : ${result.error}`) } } if (created.length) { if (updateStore) { documents.value = [...created, ...documents.value] } return { success: true, data: created } } return { success: false, error: 'Aucun document ajouté' } } catch (error) { const err = error as Error console.error("Erreur lors de l'upload des documents:", error) showError("Échec de l'ajout des documents") return { success: false, error: err.message } } finally { loading.value = false } } const deleteDocument = async ( id: string | number, { updateStore = false }: { updateStore?: boolean } = {}, ): Promise => { if (!id) { return { success: false, error: 'Identifiant manquant' } } loading.value = true try { const result = await del(`/documents/${id}`) if (result.success) { if (updateStore) { documents.value = documents.value.filter((doc) => doc.id !== id) } showSuccess('Document supprimé') } return result as DocumentResult } catch (error) { const err = error as Error console.error('Erreur lors de la suppression du document:', error) showError('Impossible de supprimer le document') return { success: false, error: err.message } } finally { loading.value = false } } const updateDocument = async ( id: string, data: { name?: string; type?: string }, ): Promise => { loading.value = true try { const result = await patch(`/documents/${id}`, data) if (result.success && result.data) { const updated = result.data as Document const index = documents.value.findIndex((doc) => doc.id === id) if (index !== -1) { documents.value[index] = { ...documents.value[index], ...updated } } showSuccess('Document mis à jour') return { success: true, data: updated } } if (result.error) showError(result.error) return result as DocumentResult } catch (error) { const err = error as Error showError('Impossible de mettre à jour le document') return { success: false, error: err.message } } finally { loading.value = false } } return { documents, total, loading, loaded, loadDocuments, loadDocumentsBySite, loadDocumentsByMachine, loadDocumentsByComponent, loadDocumentsByPiece, loadDocumentsByProduct, uploadDocuments, updateDocument, deleteDocument, } }