feat(operator): add status transitions, flag message modal, and intervention link guards
This commit is contained in:
+227
-148
@@ -33,6 +33,7 @@ const messages = computed(() => (messagesData.value as any)?.messages || [])
|
|||||||
const summary = computed(() => (summaryData.value as any)?.summary)
|
const summary = computed(() => (summaryData.value as any)?.summary)
|
||||||
const summaryMedia = computed(() => (summaryData.value as any)?.media || [])
|
const summaryMedia = computed(() => (summaryData.value as any)?.media || [])
|
||||||
const teams = computed(() => teamsData.value?.teams || [])
|
const teams = computed(() => teamsData.value?.teams || [])
|
||||||
|
|
||||||
const statusMeta: Record<string, string> = {
|
const statusMeta: Record<string, string> = {
|
||||||
OPEN: 'Aperta',
|
OPEN: 'Aperta',
|
||||||
UNDER_REVIEW: 'In revisione',
|
UNDER_REVIEW: 'In revisione',
|
||||||
@@ -43,6 +44,43 @@ const statusMeta: Record<string, string> = {
|
|||||||
CLOSED: 'Chiusa'
|
CLOSED: 'Chiusa'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mappa delle transizioni (Equivalente al backend C++)
|
||||||
|
const statusTransitions: Record<string, string[]> = {
|
||||||
|
OPEN: ['UNDER_REVIEW', 'REJECTED'],
|
||||||
|
UNDER_REVIEW: ['ASSIGNED', 'REJECTED'],
|
||||||
|
ASSIGNED: ['IN_PROGRESS', 'REJECTED'],
|
||||||
|
IN_PROGRESS: ['RESOLVED', 'REJECTED'],
|
||||||
|
RESOLVED: ['CLOSED'],
|
||||||
|
REJECTED: ['CLOSED'],
|
||||||
|
CLOSED: []
|
||||||
|
}
|
||||||
|
|
||||||
|
const availableStatuses: { value: ReportStatus, label: string }[] = [
|
||||||
|
{ value: 'OPEN', label: 'Aperta' },
|
||||||
|
{ value: 'UNDER_REVIEW', label: 'In Revisione' },
|
||||||
|
{ value: 'ASSIGNED', label: 'Assegnata' },
|
||||||
|
{ value: 'IN_PROGRESS', label: 'In Lavorazione' },
|
||||||
|
{ value: 'RESOLVED', label: 'Risolta' },
|
||||||
|
{ value: 'REJECTED', label: 'Rifiutata' },
|
||||||
|
{ value: 'CLOSED', label: 'Chiusa' }
|
||||||
|
]
|
||||||
|
|
||||||
|
// Computed per ottenere solo gli stati di destinazione validi
|
||||||
|
const selectableStatuses = computed(() => {
|
||||||
|
if (!report.value?.status) return []
|
||||||
|
const allowed = statusTransitions[report.value.status] || []
|
||||||
|
return availableStatuses.filter(s => allowed.includes(s.value))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Logica per consentire il link di intervento
|
||||||
|
// Corrisponde alla query: SELECT id FROM assignments WHERE report_id = ? AND ended_at IS NULL
|
||||||
|
const canCreateInterventionLink = computed(() => {
|
||||||
|
if (summary.value?.assignments && Array.isArray(summary.value.assignments)) {
|
||||||
|
return summary.value.assignments.some((a: any) => !a.ended_at)
|
||||||
|
}
|
||||||
|
return ['ASSIGNED', 'IN_PROGRESS'].includes(report.value?.status)
|
||||||
|
})
|
||||||
|
|
||||||
// Form Cambia Stato
|
// Form Cambia Stato
|
||||||
const newStatus = ref<ReportStatus>('IN_PROGRESS')
|
const newStatus = ref<ReportStatus>('IN_PROGRESS')
|
||||||
const statusNote = ref('')
|
const statusNote = ref('')
|
||||||
@@ -62,21 +100,20 @@ const isRevokeInterventionModalOpen = ref(false)
|
|||||||
|
|
||||||
// Messaggi
|
// Messaggi
|
||||||
const isSubmittingMessage = ref(false)
|
const isSubmittingMessage = ref(false)
|
||||||
const isFlaggingMessageId = ref<number | null>(null)
|
const flaggedMessageIds = ref<number[]>([]) // Array locale per evitare lo spam di segnalazioni
|
||||||
|
const isFlagMessageModalOpen = ref(false)
|
||||||
|
const messageToFlag = ref<Message | null>(null)
|
||||||
|
const isFlaggingMessage = ref(false)
|
||||||
|
const isFlaggingMessageId = computed(() => isFlaggingMessage.value ? messageToFlag.value?.id : null)
|
||||||
|
|
||||||
const availableStatuses: { value: ReportStatus, label: string }[] = [
|
// Inizializza lo stato nel form (seleziona automaticamente la prima transizione disponibile)
|
||||||
{ value: 'OPEN', label: 'Aperta' },
|
|
||||||
{ value: 'UNDER_REVIEW', label: 'In Revisione' },
|
|
||||||
{ value: 'ASSIGNED', label: 'Assegnata' },
|
|
||||||
{ value: 'IN_PROGRESS', label: 'In Lavorazione' },
|
|
||||||
{ value: 'RESOLVED', label: 'Risolta' },
|
|
||||||
{ value: 'REJECTED', label: 'Rifiutata' },
|
|
||||||
{ value: 'CLOSED', label: 'Chiusa' }
|
|
||||||
]
|
|
||||||
|
|
||||||
// Inizializza lo stato nel form
|
|
||||||
watch(() => report.value?.status, (val) => {
|
watch(() => report.value?.status, (val) => {
|
||||||
if (val) newStatus.value = val as ReportStatus
|
if (val) {
|
||||||
|
const allowed = statusTransitions[val] || []
|
||||||
|
if (allowed.length > 0) {
|
||||||
|
newStatus.value = allowed[0] as ReportStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
}, { immediate: true })
|
}, { immediate: true })
|
||||||
|
|
||||||
const handleStatusUpdate = async () => {
|
const handleStatusUpdate = async () => {
|
||||||
@@ -130,6 +167,7 @@ const copyInterventionLink = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleCreateInterventionLink = async () => {
|
const handleCreateInterventionLink = async () => {
|
||||||
|
if (!canCreateInterventionLink.value) return
|
||||||
isGeneratingInterventionLink.value = true
|
isGeneratingInterventionLink.value = true
|
||||||
interventionLinkError.value = ''
|
interventionLinkError.value = ''
|
||||||
interventionLinkSuccess.value = ''
|
interventionLinkSuccess.value = ''
|
||||||
@@ -197,21 +235,37 @@ const handleSendMessage = async (msgText: string, files: File[]) => {
|
|||||||
|
|
||||||
const canFlagMessage = (message: Message) => {
|
const canFlagMessage = (message: Message) => {
|
||||||
if (!user.value) return false
|
if (!user.value) return false
|
||||||
return message.user_id !== user.value.id && message.user_id === report.value?.user_id
|
const isCitizenMessage = message.user_id !== user.value.id && message.user_id === report.value?.user_id
|
||||||
|
// Non permettere di segnalare se l'id del messaggio è già nell'array (anti-spam)
|
||||||
|
const isAlreadyFlagged = flaggedMessageIds.value.includes(message.id)
|
||||||
|
return isCitizenMessage && !isAlreadyFlagged
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFlagMessage = async (message: Message) => {
|
const handleFlagMessage = (message: Message) => {
|
||||||
if (!canFlagMessage(message)) return
|
if (!canFlagMessage(message)) return
|
||||||
|
|
||||||
isFlaggingMessageId.value = message.id
|
// Apri il modale per chiedere conferma
|
||||||
|
messageToFlag.value = message
|
||||||
|
isFlagMessageModalOpen.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const executeFlagMessage = async () => {
|
||||||
|
if (!messageToFlag.value) return
|
||||||
|
|
||||||
|
isFlaggingMessage.value = true
|
||||||
try {
|
try {
|
||||||
await flagMessage(reportId, message.id, {
|
await flagMessage(reportId, messageToFlag.value.id, {
|
||||||
reason: 'Messaggio segnalato da operatore responsabile per verifica moderazione',
|
reason: 'Messaggio segnalato da operatore responsabile per verifica moderazione',
|
||||||
})
|
})
|
||||||
|
// Aggiungi l'id all'array anti-spam locale così l'utente non può più segnalarlo in questa sessione
|
||||||
|
flaggedMessageIds.value.push(messageToFlag.value.id)
|
||||||
|
|
||||||
|
isFlagMessageModalOpen.value = false
|
||||||
|
messageToFlag.value = null
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to flag message', e)
|
console.error('Failed to flag message', e)
|
||||||
} finally {
|
} finally {
|
||||||
isFlaggingMessageId.value = null
|
isFlaggingMessage.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,12 +282,12 @@ const latestCitizenMessage = computed(() => {
|
|||||||
if (!reportUserId) return null
|
if (!reportUserId) return null
|
||||||
|
|
||||||
return [...messages.value]
|
return [...messages.value]
|
||||||
.reverse()
|
.reverse()
|
||||||
.find((message) => message.user_id === reportUserId) || null
|
.find((message) => message.user_id === reportUserId) || null
|
||||||
})
|
})
|
||||||
|
|
||||||
const formattedInterventionLinkExpiry = computed(() =>
|
const formattedInterventionLinkExpiry = computed(() =>
|
||||||
interventionLinkExpiresAt.value ? formatDate(interventionLinkExpiresAt.value) : ''
|
interventionLinkExpiresAt.value ? formatDate(interventionLinkExpiresAt.value) : ''
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -326,10 +380,10 @@ const formattedInterventionLinkExpiry = computed(() =>
|
|||||||
<span class="badge bg-light text-dark border">{{ messages.length }} messaggi</span>
|
<span class="badge bg-light text-dark border">{{ messages.length }} messaggi</span>
|
||||||
</div>
|
</div>
|
||||||
<MessageList
|
<MessageList
|
||||||
:messages="messages"
|
:messages="messages"
|
||||||
:can-flag-message="canFlagMessage"
|
:can-flag-message="canFlagMessage"
|
||||||
:is-flagging-message-id="isFlaggingMessageId"
|
:is-flagging-message-id="isFlaggingMessageId"
|
||||||
@flag="handleFlagMessage"
|
@flag="handleFlagMessage"
|
||||||
/>
|
/>
|
||||||
<MessageComposer @send="handleSendMessage" />
|
<MessageComposer @send="handleSendMessage" />
|
||||||
</div>
|
</div>
|
||||||
@@ -338,126 +392,139 @@ const formattedInterventionLinkExpiry = computed(() =>
|
|||||||
|
|
||||||
<div class="col-12 col-xl-5">
|
<div class="col-12 col-xl-5">
|
||||||
<div class="report-sidebar">
|
<div class="report-sidebar">
|
||||||
<div class="card card-bg border-0 shadow-sm mb-4" v-if="summary">
|
<div class="card card-bg border-0 shadow-sm mb-4" v-if="summary">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="h6 mb-3">Quadro operativo</h2>
|
<h2 class="h6 mb-3">Quadro operativo</h2>
|
||||||
<ul class="report-summary-list list-unstyled mb-4">
|
<ul class="report-summary-list list-unstyled mb-4">
|
||||||
<li>
|
<li>
|
||||||
<span>Operatore</span>
|
<span>Operatore</span>
|
||||||
<strong>{{ summary.assigned_operator_id ? `#${summary.assigned_operator_id}` : 'Nessuno' }}</strong>
|
<strong>{{ summary.assigned_operator_id ? `#${summary.assigned_operator_id}` : 'Nessuno' }}</strong>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span>Team disponibili</span>
|
<span>Team disponibili</span>
|
||||||
<strong>{{ teams.length }}</strong>
|
<strong>{{ teams.length }}</strong>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span>Allegati</span>
|
<span>Allegati</span>
|
||||||
<strong>{{ summaryMedia.length || media.length }}</strong>
|
<strong>{{ summaryMedia.length || media.length }}</strong>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="report-description">
|
<div class="report-description">
|
||||||
<h3 class="h6 mb-2">Ultimo messaggio cittadino</h3>
|
<h3 class="h6 mb-2">Ultimo messaggio cittadino</h3>
|
||||||
<p class="small mb-0">
|
<p class="small mb-0">
|
||||||
{{ latestCitizenMessage?.body || 'Nessun messaggio del cittadino disponibile.' }}
|
{{ latestCitizenMessage?.body || 'Nessun messaggio del cittadino disponibile.' }}
|
||||||
</p>
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="card-body pt-0">
|
||||||
<div class="card-body pt-0">
|
<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="teams.length === 0">
|
Assegna team
|
||||||
Assegna team
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card card-bg border-0 shadow-sm mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<h2 class="h6 mb-3">Link intervento pubblico</h2>
|
|
||||||
<p class="text-muted small mb-3">Genera link temporaneo per team esterno. Nuova generazione ruota link esistente.</p>
|
|
||||||
|
|
||||||
<div v-if="interventionLinkError" class="alert alert-danger py-2" role="alert">
|
|
||||||
{{ interventionLinkError }}
|
|
||||||
</div>
|
|
||||||
<div v-if="interventionLinkSuccess" class="alert alert-success py-2" role="alert">
|
|
||||||
{{ interventionLinkSuccess }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template v-if="interventionLink">
|
|
||||||
<label class="form-label">URL attivo</label>
|
|
||||||
<div class="input-group mb-2">
|
|
||||||
<input type="text" class="form-control" :value="interventionLink" readonly />
|
|
||||||
<button type="button" class="btn btn-outline-primary" @click="copyInterventionLink">
|
|
||||||
Copia
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<p class="small text-muted mb-3">
|
|
||||||
Scade: {{ formattedInterventionLinkExpiry || '-' }}
|
|
||||||
</p>
|
|
||||||
<div class="d-grid gap-2">
|
|
||||||
<button type="button" class="btn btn-outline-primary" :disabled="isGeneratingInterventionLink" @click="handleCreateInterventionLink">
|
|
||||||
<span v-if="isGeneratingInterventionLink" class="spinner-border spinner-border-sm me-2"></span>
|
|
||||||
Rigenera link
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-outline-danger" :disabled="isRevokingInterventionLink" @click="openRevokeInterventionLinkModal">
|
|
||||||
<span v-if="isRevokingInterventionLink" class="spinner-border spinner-border-sm me-2"></span>
|
|
||||||
Revoca link
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<button
|
|
||||||
v-else
|
|
||||||
type="button"
|
|
||||||
class="btn btn-outline-primary w-100"
|
|
||||||
:disabled="isGeneratingInterventionLink"
|
|
||||||
@click="handleCreateInterventionLink"
|
|
||||||
>
|
|
||||||
<span v-if="isGeneratingInterventionLink" class="spinner-border spinner-border-sm me-2"></span>
|
|
||||||
Genera link
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card card-bg border-0 shadow-sm mb-4">
|
|
||||||
<div class="card-body">
|
|
||||||
<h2 class="h6 mb-3">Aggiorna stato</h2>
|
|
||||||
<form @submit.prevent="handleStatusUpdate">
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label">Nuovo Stato</label>
|
|
||||||
<select class="form-select" v-model="newStatus">
|
|
||||||
<option v-for="st in availableStatuses" :key="st.value" :value="st.value">
|
|
||||||
{{ st.label }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label">Nota (visibile nella cronologia)</label>
|
|
||||||
<textarea class="form-control" v-model="statusNote" rows="2" placeholder="Motivazione o dettaglio..."></textarea>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary w-100" :disabled="isUpdatingStatus || newStatus === report.status">
|
|
||||||
<span v-if="isUpdatingStatus" class="spinner-border spinner-border-sm me-2"></span>
|
|
||||||
Aggiorna Stato
|
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card card-bg border-0 shadow-sm">
|
<div class="card card-bg border-0 shadow-sm mb-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h2 class="h6 mb-3">Cronologia eventi</h2>
|
<h2 class="h6 mb-3">Link intervento pubblico</h2>
|
||||||
<div v-if="statusHistory.length === 0" class="small text-muted">Nessun evento registrato.</div>
|
<p class="text-muted small mb-3">Genera link temporaneo per team esterno. Nuova generazione ruota link esistente.</p>
|
||||||
<ul class="list-unstyled mb-0 ms-2">
|
|
||||||
<li v-for="item in statusHistory" :key="item.id" class="mb-3 border-start border-primary border-3 ps-3">
|
<div v-if="interventionLinkError" class="alert alert-danger py-2" role="alert">
|
||||||
<small class="text-muted d-block">{{ formatDate(item.created_at) }}</small>
|
{{ interventionLinkError }}
|
||||||
<div class="d-flex align-items-center gap-2 mt-1">
|
</div>
|
||||||
<StatusBadge :status="item.old_status" />
|
<div v-if="interventionLinkSuccess" class="alert alert-success py-2" role="alert">
|
||||||
<BIIcon name="it-arrow-right" size="xs" />
|
{{ interventionLinkSuccess }}
|
||||||
<StatusBadge :status="item.new_status" />
|
</div>
|
||||||
|
|
||||||
|
<template v-if="interventionLink">
|
||||||
|
<label class="form-label">URL attivo</label>
|
||||||
|
<div class="input-group mb-2">
|
||||||
|
<input type="text" class="form-control" :value="interventionLink" readonly />
|
||||||
|
<button type="button" class="btn btn-outline-primary" @click="copyInterventionLink">
|
||||||
|
Copia
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="item.note" class="small mt-1 bg-light p-1 rounded">{{ item.note }}</div>
|
<p class="small text-muted mb-3">
|
||||||
</li>
|
Scade: {{ formattedInterventionLinkExpiry || '-' }}
|
||||||
</ul>
|
</p>
|
||||||
|
<div class="d-grid gap-2">
|
||||||
|
<button type="button" class="btn btn-outline-primary" :disabled="isGeneratingInterventionLink || !canCreateInterventionLink" @click="handleCreateInterventionLink">
|
||||||
|
<span v-if="isGeneratingInterventionLink" class="spinner-border spinner-border-sm me-2"></span>
|
||||||
|
Rigenera link
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-danger" :disabled="isRevokingInterventionLink" @click="openRevokeInterventionLinkModal">
|
||||||
|
<span v-if="isRevokingInterventionLink" class="spinner-border spinner-border-sm me-2"></span>
|
||||||
|
Revoca link
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<button
|
||||||
|
v-else
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline-primary w-100"
|
||||||
|
:disabled="isGeneratingInterventionLink || !canCreateInterventionLink"
|
||||||
|
@click="handleCreateInterventionLink"
|
||||||
|
>
|
||||||
|
<span v-if="isGeneratingInterventionLink" class="spinner-border spinner-border-sm me-2"></span>
|
||||||
|
Genera link
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div v-if="!canCreateInterventionLink" class="text-danger small mt-2">
|
||||||
|
È necessaria un'assegnazione in corso per generare o rigenerare questo link.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-bg border-0 shadow-sm mb-4">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="h6 mb-3">Aggiorna stato</h2>
|
||||||
|
|
||||||
|
<template v-if="selectableStatuses.length > 0">
|
||||||
|
<form @submit.prevent="handleStatusUpdate">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Nuovo Stato</label>
|
||||||
|
<select class="form-select" v-model="newStatus">
|
||||||
|
<option v-for="st in selectableStatuses" :key="st.value" :value="st.value">
|
||||||
|
{{ st.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Nota (visibile nella cronologia)</label>
|
||||||
|
<textarea class="form-control" v-model="statusNote" rows="2" placeholder="Motivazione o dettaglio..."></textarea>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary w-100" :disabled="isUpdatingStatus">
|
||||||
|
<span v-if="isUpdatingStatus" class="spinner-border spinner-border-sm me-2"></span>
|
||||||
|
Aggiorna Stato
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<div class="alert alert-info mb-0 small">
|
||||||
|
La segnalazione è attualmente in stato <strong>{{ statusMeta[report.status] }}</strong>. Non sono consentite ulteriori transizioni.
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card card-bg border-0 shadow-sm">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="h6 mb-3">Cronologia eventi</h2>
|
||||||
|
<div v-if="statusHistory.length === 0" class="small text-muted">Nessun evento registrato.</div>
|
||||||
|
<ul class="list-unstyled mb-0 ms-2">
|
||||||
|
<li v-for="item in statusHistory" :key="item.id" class="mb-3 border-start border-primary border-3 ps-3">
|
||||||
|
<small class="text-muted d-block">{{ formatDate(item.created_at) }}</small>
|
||||||
|
<div class="d-flex align-items-center gap-2 mt-1">
|
||||||
|
<StatusBadge :status="item.old_status" />
|
||||||
|
<BIIcon name="it-arrow-right" size="xs" />
|
||||||
|
<StatusBadge :status="item.new_status" />
|
||||||
|
</div>
|
||||||
|
<div v-if="item.note" class="small mt-1 bg-light p-1 rounded">{{ item.note }}</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -501,14 +568,26 @@ const formattedInterventionLinkExpiry = computed(() =>
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
:open="isRevokeInterventionModalOpen"
|
:open="isRevokeInterventionModalOpen"
|
||||||
title="Revoca link intervento"
|
title="Revoca link intervento"
|
||||||
message="Vuoi revocare link pubblico per team esterno? Link non sara piu utilizzabile."
|
message="Vuoi revocare link pubblico per team esterno? Link non sara piu utilizzabile."
|
||||||
confirm-label="Revoca link"
|
confirm-label="Revoca link"
|
||||||
confirm-class="btn-danger"
|
confirm-class="btn-danger"
|
||||||
:pending="isRevokingInterventionLink"
|
:pending="isRevokingInterventionLink"
|
||||||
@cancel="closeRevokeInterventionLinkModal"
|
@cancel="closeRevokeInterventionLinkModal"
|
||||||
@confirm="handleRevokeInterventionLink"
|
@confirm="handleRevokeInterventionLink"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Nuovo Modale per Conferma Segnalazione -->
|
||||||
|
<ConfirmModal
|
||||||
|
:open="isFlagMessageModalOpen"
|
||||||
|
title="Segnala messaggio"
|
||||||
|
message="Sei sicuro di voler segnalare questo messaggio al team di moderazione per una verifica?"
|
||||||
|
confirm-label="Segnala"
|
||||||
|
confirm-class="btn-warning"
|
||||||
|
:pending="isFlaggingMessage"
|
||||||
|
@cancel="isFlagMessageModalOpen = false; messageToFlag = null"
|
||||||
|
@confirm="executeFlagMessage"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="text-center py-5">
|
<div v-else class="text-center py-5">
|
||||||
@@ -629,4 +708,4 @@ const formattedInterventionLinkExpiry = computed(() =>
|
|||||||
position: static;
|
position: static;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
Reference in New Issue
Block a user