feat: image upload on articles

This commit is contained in:
fsylvain committed 2026-09-28 02:28:20 +02:00
1 parent d4fcfb2bba
commit 938263cd6a
12 files changed
+1436 -65

No files matched your search

+59
View File
@@ -0,0 +1,59 @@
import { ref } from 'vue'
export interface UploadProgress {
loaded: number
total: number
}
export type UploadOutcome =
| { kind: 'success'; location: string }
| { kind: 'rejected'; body: string }
| { kind: 'failed' }
export function useImageUpload() {
const progress = ref<UploadProgress>({ loaded: 0, total: 0 })
let activeRequest: XMLHttpRequest | null = null
function abort() {
activeRequest?.abort()
activeRequest = null
}
function start(articleId: number, file: File): Promise<UploadOutcome> {
progress.value = { loaded: 0, total: file.size }
return new Promise((resolve) => {
const request = new XMLHttpRequest()
activeRequest = request
request.open('POST', `/v1/article/${articleId}/image`)
request.withCredentials = true
request.upload.addEventListener('progress', (event) => {
progress.value = { loaded: event.loaded, total: event.total }
})
request.addEventListener('load', () => {
activeRequest = null
if (request.status === 201) {
const body = JSON.parse(request.responseText) as { location: string }
resolve({ kind: 'success', location: body.location })
return
}
if (request.status === 400) {
resolve({ kind: 'rejected', body: request.responseText })
return
}
resolve({ kind: 'failed' })
})
request.addEventListener('error', () => {
activeRequest = null
resolve({ kind: 'failed' })
})
request.addEventListener('abort', () => {
activeRequest = null
})
const formData = new FormData()
formData.append('file', file)
request.send(formData)
})
}
return { progress, start, abort }
}