fix(frontend) : refresh documents locally after upload/delete and improve progress UX

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-15 18:21:04 +01:00
parent 7bf632c1da
commit 9908f34580
2 changed files with 28 additions and 15 deletions

View File

@@ -28,8 +28,10 @@
<div class="mt-1 h-1.5 w-full overflow-hidden rounded-full bg-neutral-200"> <div class="mt-1 h-1.5 w-full overflow-hidden rounded-full bg-neutral-200">
<div <div
class="h-full rounded-full transition-all" class="h-full rounded-full transition-all"
:class="upload.error ? 'bg-red-500' : 'bg-blue-500'" :class="[
:style="{ width: `${upload.progress}%` }" upload.error ? 'bg-red-500' : upload.uploading ? 'animate-pulse bg-blue-400' : 'bg-green-500',
]"
:style="{ width: upload.uploading ? '70%' : `${upload.progress}%` }"
/> />
</div> </div>
</div> </div>
@@ -64,6 +66,7 @@ const isDragging = ref(false)
type UploadState = { type UploadState = {
name: string name: string
progress: number progress: number
uploading: boolean
error: boolean error: boolean
} }
@@ -99,19 +102,18 @@ async function processFiles(files: File[]) {
const state: UploadState = reactive({ const state: UploadState = reactive({
name: file.name, name: file.name,
progress: 0, progress: 30,
uploading: true,
error: false, error: false,
}) })
uploads.value.push(state) uploads.value.push(state)
try { try {
await uploadFile(props.taskId, file) await uploadFile(props.taskId, file)
state.uploading = false
state.progress = 100 state.progress = 100
toast.success({
title: 'Succès',
message: t('taskDocuments.uploaded'),
})
} catch { } catch {
state.uploading = false
state.error = true state.error = true
state.progress = 100 state.progress = 100
toast.error({ toast.error({
@@ -119,13 +121,13 @@ async function processFiles(files: File[]) {
message: t('taskDocuments.uploadError'), message: t('taskDocuments.uploadError'),
}) })
} }
emit('uploaded')
} }
// Clean up completed uploads after a delay // Clean up completed uploads after a delay
setTimeout(() => { setTimeout(() => {
uploads.value = uploads.value.filter(u => u.error) uploads.value = uploads.value.filter(u => u.error)
}, 2000) }, 1500)
emit('uploaded')
} }
</script> </script>

View File

@@ -375,15 +375,26 @@ watch(() => props.modelValue, async (open) => {
}) })
const { create, update, remove } = useTaskService() const { create, update, remove } = useTaskService()
const { remove: removeDocument } = useTaskDocumentService() const { remove: removeDocument, getByTask: getDocumentsByTask } = useTaskDocumentService()
const { t } = useI18n() const { t } = useI18n()
const authStore = useAuthStore() const authStore = useAuthStore()
const isAdmin = computed(() => authStore.user?.roles?.includes('ROLE_ADMIN') ?? false) const isAdmin = computed(() => authStore.user?.roles?.includes('ROLE_ADMIN') ?? false)
const documents = computed(() => props.task?.documents ?? []) const localDocuments = ref<TaskDocument[]>([])
const documents = computed(() => localDocuments.value)
const previewDoc = ref<TaskDocument | null>(null) const previewDoc = ref<TaskDocument | null>(null)
// Sync documents from task prop when modal opens or task changes
watch(() => props.task?.documents, (docs) => {
localDocuments.value = docs ? [...docs] : []
}, { immediate: true })
async function refreshDocuments() {
if (!props.task) return
localDocuments.value = await getDocumentsByTask(props.task.id)
}
const previewIndex = computed(() => { const previewIndex = computed(() => {
if (!previewDoc.value) return -1 if (!previewDoc.value) return -1
return documents.value.findIndex(d => d.id === previewDoc.value!.id) return documents.value.findIndex(d => d.id === previewDoc.value!.id)
@@ -408,11 +419,11 @@ function nextPreview() {
async function handleDeleteDocument(doc: TaskDocument) { async function handleDeleteDocument(doc: TaskDocument) {
if (!confirm(t('taskDocuments.confirmDeleteMessage'))) return if (!confirm(t('taskDocuments.confirmDeleteMessage'))) return
await removeDocument(doc.id) await removeDocument(doc.id)
emit('saved') await refreshDocuments()
} }
function handleDocumentUploaded() { async function handleDocumentUploaded() {
emit('saved') await refreshDocuments()
} }
async function handleDelete() { async function handleDelete() {