Files
Starseed/frontend/shared/composables/useUpload.ts
T

54 lines
1.9 KiB
TypeScript

import { ref } from 'vue'
import type { AnyObject } from '~/shared/composables/useApi'
/**
* Réponse JSON-LD de POST /api/uploaded_documents (groupe `uploaded_document:read`).
* Seul l'IRI (`@id`) est exploité pour le poser sur la relation cible.
*/
export interface UploadedDocumentResponse {
'@id': string
originalFilename?: string
mimeType?: string
}
/**
* Upload d'un document générique vers l'infra partagée (ERP-154) :
* POST /api/uploaded_documents en multipart/form-data, champ « file », via
* `useApi()` (cookie JWT, parsing Hydra/erreurs). Renvoie l'IRI du document créé,
* à poser sur la relation cible (ex: `carrier.dischargeDocument` — RG-4.02).
*
* Les erreurs (MIME hors whitelist / fichier trop volumineux → 422) sont relayées
* (rethrow) à l'appelant pour un affichage inline sous le champ. `toast: false` par
* défaut : pas de toast fourre-tout, le formulaire mappe le message au bon champ.
*/
export function useUpload() {
// Indicateur d'upload en cours (désactivation UI / spinner éventuel).
const uploading = ref(false)
/**
* Envoie `file` et renvoie l'IRI du `UploadedDocument` créé.
* @throws relaie l'erreur réseau / 422 (MIME, taille) à l'appelant.
*/
async function upload(file: File, options: { toast?: boolean } = {}): Promise<string> {
const formData = new FormData()
formData.append('file', file)
uploading.value = true
try {
// useApi() détecte le FormData et n'impose pas de Content-Type JSON :
// le navigateur pose lui-même la frontière multipart.
const doc = await useApi().post<UploadedDocumentResponse>(
'/uploaded_documents',
formData as unknown as AnyObject,
{ toast: options.toast ?? false },
)
return doc['@id']
} finally {
uploading.value = false
}
}
return { uploading, upload }
}