feat(admin): add delete functionality for areas, categories, and teams in admin panel

This commit is contained in:
gabdevele
2026-06-15 17:06:20 +02:00
committed by reloia
Unverified
parent 00b0f97505
commit b38ba74cc0
9 changed files with 538 additions and 45 deletions
+136 -1
View File
@@ -17,7 +17,7 @@ if (!reportId) {
}
const { getReportDetail, getMessages, addMessage, flagMessage } = useReports()
const { getInterventionSummary, updateReportStatus, assignTeam, getTeams } = useOperator()
const { getInterventionSummary, updateReportStatus, assignTeam, getTeams, createInterventionLink, revokeInterventionLink } = useOperator()
const { user } = useAuth()
// Dati principali
@@ -52,6 +52,13 @@ const isUpdatingStatus = ref(false)
const isAssignModalOpen = ref(false)
const selectedTeamId = ref<number | null>(null)
const isAssigning = ref(false)
const interventionLink = ref('')
const interventionLinkExpiresAt = ref('')
const isGeneratingInterventionLink = ref(false)
const isRevokingInterventionLink = ref(false)
const interventionLinkError = ref('')
const interventionLinkSuccess = ref('')
const isRevokeInterventionModalOpen = ref(false)
// Messaggi
const isSubmittingMessage = ref(false)
@@ -109,6 +116,72 @@ const handleAssignTeam = async () => {
}
}
const copyInterventionLink = async () => {
if (!interventionLink.value || !navigator?.clipboard) return
try {
await navigator.clipboard.writeText(interventionLink.value)
interventionLinkSuccess.value = 'Link copiato negli appunti.'
interventionLinkError.value = ''
} catch {
interventionLinkError.value = 'Copia automatica non riuscita.'
interventionLinkSuccess.value = ''
}
}
const handleCreateInterventionLink = async () => {
isGeneratingInterventionLink.value = true
interventionLinkError.value = ''
interventionLinkSuccess.value = ''
try {
const res = await createInterventionLink(reportId)
if (res.ok) {
interventionLink.value = res.url
interventionLinkExpiresAt.value = res.expires_at
interventionLinkSuccess.value = 'Link intervento generato.'
}
} catch (e: any) {
console.error('Failed to create intervention link', e)
interventionLinkError.value = e?.data?.message || 'Generazione link non riuscita.'
} finally {
isGeneratingInterventionLink.value = false
}
}
const openRevokeInterventionLinkModal = () => {
if (!interventionLink.value) return
isRevokeInterventionModalOpen.value = true
}
const closeRevokeInterventionLinkModal = () => {
if (isRevokingInterventionLink.value) return
isRevokeInterventionModalOpen.value = false
}
const handleRevokeInterventionLink = async () => {
if (!interventionLink.value) return
isRevokingInterventionLink.value = true
interventionLinkError.value = ''
interventionLinkSuccess.value = ''
try {
const res = await revokeInterventionLink(reportId)
if (res.ok) {
interventionLink.value = ''
interventionLinkExpiresAt.value = ''
interventionLinkSuccess.value = 'Link intervento revocato.'
isRevokeInterventionModalOpen.value = false
}
} catch (e: any) {
console.error('Failed to revoke intervention link', e)
interventionLinkError.value = e?.data?.message || 'Revoca link non riuscita.'
} finally {
isRevokingInterventionLink.value = false
}
}
const handleSendMessage = async (msgText: string, files: File[]) => {
if (!msgText.trim() && files.length === 0) return
isSubmittingMessage.value = true
@@ -158,6 +231,10 @@ const latestCitizenMessage = computed(() => {
.reverse()
.find((message) => message.user_id === reportUserId) || null
})
const formattedInterventionLinkExpiry = computed(() =>
interventionLinkExpiresAt.value ? formatDate(interventionLinkExpiresAt.value) : ''
)
</script>
<template>
@@ -292,6 +369,54 @@ const latestCitizenMessage = computed(() => {
</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>
@@ -375,6 +500,16 @@ const latestCitizenMessage = computed(() => {
</div>
</div>
<ConfirmModal
:open="isRevokeInterventionModalOpen"
title="Revoca link intervento"
message="Vuoi revocare link pubblico per team esterno? Link non sara piu utilizzabile."
confirm-label="Revoca link"
confirm-class="btn-danger"
:pending="isRevokingInterventionLink"
@cancel="closeRevokeInterventionLinkModal"
@confirm="handleRevokeInterventionLink"
/>
</div>
<div v-else class="text-center py-5">
<div class="spinner-border text-primary" role="status"></div>