feat: enhance feedback handling and status checks in report management
This commit is contained in:
@@ -46,6 +46,10 @@ const isTakenByCurrentOperator = computed(() => report.value?.assigned_operator_
|
||||
const isOpenAndUnassigned = computed(() => report.value?.status === 'OPEN' && !report.value?.assigned_operator_id)
|
||||
const isReadOnlyPreview = computed(() => !isTakenByCurrentOperator.value)
|
||||
const canTakeReport = computed(() => isOpenAndUnassigned.value && !isTakenByCurrentOperator.value)
|
||||
const isFinalStatus = computed(() => ['REJECTED', 'RESOLVED', 'CLOSED'].includes(report.value?.status || ''))
|
||||
const canAssignTeam = computed(() => !isReadOnlyPreview.value && !isFinalStatus.value && teams.value.length > 0)
|
||||
const canSendMessage = computed(() => !isReadOnlyPreview.value && !isFinalStatus.value)
|
||||
const canChangeStatus = computed(() => !isReadOnlyPreview.value && !isFinalStatus.value && selectableStatuses.value.length > 0)
|
||||
|
||||
const statusMeta: Record<string, string> = {
|
||||
OPEN: 'Aperta',
|
||||
@@ -108,6 +112,8 @@ const interventionLinkError = ref('')
|
||||
const interventionLinkSuccess = ref('')
|
||||
const isRevokeInterventionModalOpen = ref(false)
|
||||
const copyFeedback = ref('')
|
||||
const actionError = ref('')
|
||||
const actionSuccess = ref('')
|
||||
|
||||
const isSubmittingMessage = ref(false)
|
||||
const flaggedMessageIds = ref<number[]>([])
|
||||
@@ -140,6 +146,11 @@ const resetReportFlagForm = () => {
|
||||
reportFlagError.value = ''
|
||||
}
|
||||
|
||||
const clearActionFeedback = () => {
|
||||
actionError.value = ''
|
||||
actionSuccess.value = ''
|
||||
}
|
||||
|
||||
const setPublicInterventionLink = (url?: string) => {
|
||||
if (!url) {
|
||||
interventionPublicLink.value = ''
|
||||
@@ -158,21 +169,25 @@ const handleTakeReport = async () => {
|
||||
if (!canTakeReport.value || !report.value) return
|
||||
|
||||
isTakingReport.value = true
|
||||
clearActionFeedback()
|
||||
try {
|
||||
const res = await takeReport(report.value.id)
|
||||
if (res.ok) {
|
||||
await Promise.all([refreshReport(), refreshSummary()])
|
||||
actionSuccess.value = 'Segnalazione presa in carico.'
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
console.error('Failed to take report', e)
|
||||
actionError.value = e?.data?.message || 'Presa in carico non riuscita.'
|
||||
} finally {
|
||||
isTakingReport.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleStatusUpdate = async () => {
|
||||
if (isReadOnlyPreview.value) return
|
||||
if (!canChangeStatus.value) return
|
||||
isUpdatingStatus.value = true
|
||||
clearActionFeedback()
|
||||
try {
|
||||
const res = await updateReportStatus(reportId, {
|
||||
status: newStatus.value,
|
||||
@@ -181,19 +196,22 @@ const handleStatusUpdate = async () => {
|
||||
if (res.ok) {
|
||||
statusNote.value = ''
|
||||
await Promise.all([refreshReport(), refreshSummary()])
|
||||
actionSuccess.value = 'Stato aggiornato con successo.'
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
console.error('Failed to update status', e)
|
||||
actionError.value = e?.data?.message || 'Aggiornamento stato non riuscito.'
|
||||
} finally {
|
||||
isUpdatingStatus.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleAssignTeam = async () => {
|
||||
if (isReadOnlyPreview.value) return
|
||||
if (!canAssignTeam.value) return
|
||||
if (!selectedTeamId.value) return
|
||||
|
||||
isAssigning.value = true
|
||||
clearActionFeedback()
|
||||
try {
|
||||
const res = await assignTeam(reportId, {
|
||||
team_id: selectedTeamId.value
|
||||
@@ -202,9 +220,11 @@ const handleAssignTeam = async () => {
|
||||
isAssignModalOpen.value = false
|
||||
selectedTeamId.value = null
|
||||
await Promise.all([refreshReport(), refreshSummary()])
|
||||
actionSuccess.value = 'Team assegnato con successo.'
|
||||
}
|
||||
} catch (e) {
|
||||
} catch (e: any) {
|
||||
console.error('Failed to assign team', e)
|
||||
actionError.value = e?.data?.message || 'Assegnazione team non riuscita.'
|
||||
} finally {
|
||||
isAssigning.value = false
|
||||
}
|
||||
@@ -231,6 +251,7 @@ const copyInterventionLink = async () => {
|
||||
const handleCreateInterventionLink = async () => {
|
||||
if (!canCreateInterventionLink.value) return
|
||||
isGeneratingInterventionLink.value = true
|
||||
clearActionFeedback()
|
||||
interventionLinkError.value = ''
|
||||
interventionLinkSuccess.value = ''
|
||||
|
||||
@@ -264,6 +285,7 @@ const handleRevokeInterventionLink = async () => {
|
||||
if (!interventionLink.value) return
|
||||
|
||||
isRevokingInterventionLink.value = true
|
||||
clearActionFeedback()
|
||||
interventionLinkError.value = ''
|
||||
interventionLinkSuccess.value = ''
|
||||
|
||||
@@ -285,14 +307,17 @@ const handleRevokeInterventionLink = async () => {
|
||||
}
|
||||
|
||||
const handleSendMessage = async (msgText: string, files: File[]) => {
|
||||
if (isReadOnlyPreview.value) return
|
||||
if (!canSendMessage.value) return
|
||||
if (!msgText.trim() && files.length === 0) return
|
||||
isSubmittingMessage.value = true
|
||||
clearActionFeedback()
|
||||
try {
|
||||
await addMessage(reportId, { body: msgText })
|
||||
await refreshMessages()
|
||||
} catch (e) {
|
||||
actionSuccess.value = 'Messaggio inviato.'
|
||||
} catch (e: any) {
|
||||
console.error('Failed to send message', e)
|
||||
actionError.value = e?.data?.message || 'Invio messaggio non riuscito.'
|
||||
} finally {
|
||||
isSubmittingMessage.value = false
|
||||
}
|
||||
@@ -325,8 +350,10 @@ const executeFlagMessage = async () => {
|
||||
flaggedMessageIds.value.push(messageToFlag.value.id)
|
||||
isFlagMessageModalOpen.value = false
|
||||
messageToFlag.value = null
|
||||
} catch (e) {
|
||||
actionSuccess.value = 'Messaggio segnalato alla moderazione.'
|
||||
} catch (e: any) {
|
||||
console.error('Failed to flag message', e)
|
||||
actionError.value = e?.data?.message || 'Segnalazione messaggio non riuscita.'
|
||||
} finally {
|
||||
isFlaggingMessage.value = false
|
||||
}
|
||||
@@ -419,6 +446,13 @@ const formattedInterventionLinkExpiry = computed(() =>
|
||||
</div>
|
||||
|
||||
<div class="container my-5">
|
||||
<div v-if="actionError" class="alert alert-danger mb-4">
|
||||
{{ actionError }}
|
||||
</div>
|
||||
<div v-if="actionSuccess" class="alert alert-success mb-4">
|
||||
{{ actionSuccess }}
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-12 col-xl-7">
|
||||
<div class="card card-bg border-0 shadow-sm mb-4">
|
||||
@@ -495,9 +529,12 @@ const formattedInterventionLinkExpiry = computed(() =>
|
||||
@flag="handleFlagMessage"
|
||||
/>
|
||||
<div v-if="isReadOnlyPreview" class="alert alert-secondary mt-3 mb-0 small">
|
||||
Messaggistica disponibile dopo la presa in carico.
|
||||
{{ isFinalStatus ? 'Messaggistica non disponibile per segnalazioni concluse o rifiutate.' : 'Messaggistica disponibile dopo la presa in carico.' }}
|
||||
</div>
|
||||
<MessageComposer v-else-if="canSendMessage" @send="handleSendMessage" />
|
||||
<div v-else class="alert alert-secondary mt-3 mb-0 small">
|
||||
Messaggistica non disponibile per segnalazioni concluse o rifiutate.
|
||||
</div>
|
||||
<MessageComposer v-else @send="handleSendMessage" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -529,9 +566,12 @@ const formattedInterventionLinkExpiry = computed(() =>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-0" v-if="!isReadOnlyPreview">
|
||||
<button class="btn btn-outline-primary w-100" @click="isAssignModalOpen = true" :disabled="teams.length === 0">
|
||||
<button class="btn btn-outline-primary w-100" @click="isAssignModalOpen = true" :disabled="!canAssignTeam">
|
||||
Assegna team
|
||||
</button>
|
||||
<div v-if="isFinalStatus" class="small text-muted mt-2">
|
||||
Assegnazione team non disponibile per segnalazioni concluse o rifiutate.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -597,7 +637,7 @@ const formattedInterventionLinkExpiry = computed(() =>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else-if="selectableStatuses.length > 0">
|
||||
<template v-else-if="canChangeStatus">
|
||||
<form @submit.prevent="handleStatusUpdate">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Nuovo Stato</label>
|
||||
|
||||
Reference in New Issue
Block a user