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

This commit is contained in:
gabdevele
2026-06-15 15:50:05 +02:00 Unverified
parent caa014b33f
commit 0808f763cf
9 changed files with 538 additions and 45 deletions
+104 -17
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { reactive, ref, watch } from 'vue'
definePageMeta({
middleware: 'auth',
@@ -13,6 +13,19 @@ const { getModerationFlags, updateModerationFlag } = useAdmin()
const page = ref(1)
const perPage = ref(10)
const statusFilter = ref('')
const actionError = ref('')
const resolveModal = reactive({
open: false,
flagId: null as number | null,
rejectReport: false,
note: '',
pending: false,
})
const dismissModal = reactive({
open: false,
flagId: null as number | null,
pending: false,
})
const { data: flagsRes, pending, refresh } = useAsyncData(
'admin-moderation-flags',
@@ -20,36 +33,72 @@ const { data: flagsRes, pending, refresh } = useAsyncData(
{ watch: [page, statusFilter] }
)
const handleResolve = async (id: number, rejectReport: boolean) => {
const note = prompt('Inserisci una nota di risoluzione (opzionale):')
if (note === null) return // cancelled
const openResolveModal = (id: number, rejectReport: boolean) => {
resolveModal.open = true
resolveModal.flagId = id
resolveModal.rejectReport = rejectReport
resolveModal.note = ''
}
const closeResolveModal = () => {
if (resolveModal.pending) return
resolveModal.open = false
resolveModal.flagId = null
resolveModal.note = ''
}
const handleResolve = async () => {
if (!resolveModal.flagId) return
resolveModal.pending = true
actionError.value = ''
try {
const res = await updateModerationFlag(id, {
const res = await updateModerationFlag(resolveModal.flagId, {
status: 'RESOLVED',
reject_report: rejectReport,
resolution_note: note
reject_report: resolveModal.rejectReport,
resolution_note: resolveModal.note || undefined
})
if (res.ok) {
await refresh()
closeResolveModal()
}
} catch (err) {
console.error('Failed to resolve flag', err)
alert('Errore durante la risoluzione della segnalazione.')
actionError.value = 'Errore durante la risoluzione della segnalazione.'
} finally {
resolveModal.pending = false
}
}
const handleDismiss = async (id: number) => {
if (!confirm('Sei sicuro di voler ignorare (dismiss) questo flag?')) return
const openDismissModal = (id: number) => {
dismissModal.open = true
dismissModal.flagId = id
}
const closeDismissModal = () => {
if (dismissModal.pending) return
dismissModal.open = false
dismissModal.flagId = null
}
const handleDismiss = async () => {
if (!dismissModal.flagId) return
dismissModal.pending = true
actionError.value = ''
try {
const res = await updateModerationFlag(id, { status: 'DISMISSED' })
const res = await updateModerationFlag(dismissModal.flagId, { status: 'DISMISSED' })
if (res.ok) {
await refresh()
closeDismissModal()
}
} catch (err) {
console.error('Failed to dismiss flag', err)
alert('Errore durante l\'aggiornamento.')
actionError.value = 'Errore durante l\'aggiornamento.'
} finally {
dismissModal.pending = false
}
}
@@ -88,6 +137,10 @@ const formatDate = (dateStr: string) => {
Nessun elemento da moderare al momento.
</div>
<div v-if="actionError" class="alert alert-danger">
{{ actionError }}
</div>
<div v-else>
<div class="card mb-3 shadow-sm border-0" v-for="flag in flagsRes.flags" :key="flag.id">
<div class="card-header bg-light d-flex justify-content-between align-items-center">
@@ -134,13 +187,13 @@ const formatDate = (dateStr: string) => {
<div class="col-md-4 text-end" v-if="flag.status === 'OPEN'">
<div class="d-flex flex-column gap-2 mt-3 mt-md-0">
<button class="btn btn-outline-danger btn-sm" @click="handleResolve(flag.id, true)">
<button class="btn btn-outline-danger btn-sm" @click="openResolveModal(flag.id, true)">
<BIIcon name="it-ban" size="xs" /> Risolvi & Rigetta Segn.
</button>
<button class="btn btn-outline-warning btn-sm" @click="handleResolve(flag.id, false)">
<button class="btn btn-outline-warning btn-sm" @click="openResolveModal(flag.id, false)">
<BIIcon name="it-check" size="xs" /> Risolvi (Solo Avviso)
</button>
<button class="btn btn-outline-secondary btn-sm" @click="handleDismiss(flag.id)">
<button class="btn btn-outline-secondary btn-sm" @click="openDismissModal(flag.id)">
<BIIcon name="it-close" size="xs" /> Ignora Flag
</button>
</div>
@@ -157,5 +210,39 @@ const formatDate = (dateStr: string) => {
@page-change="page = $event"
/>
</div>
<div v-if="resolveModal.open" class="modal-backdrop fade show d-block" style="background: rgba(0,0,0,0.5); z-index: 1040;"></div>
<div v-if="resolveModal.open" class="modal fade show d-block" tabindex="-1" style="z-index: 1050;">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{{ resolveModal.rejectReport ? 'Risolvi e rigetta segnalazione' : 'Risolvi flag' }}</h5>
<button type="button" class="btn-close" :disabled="resolveModal.pending" @click="closeResolveModal"></button>
</div>
<div class="modal-body">
<label class="form-label">Nota di risoluzione</label>
<textarea v-model="resolveModal.note" class="form-control" rows="4" placeholder="Nota opzionale"></textarea>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" :disabled="resolveModal.pending" @click="closeResolveModal">Annulla</button>
<button type="button" class="btn btn-primary" :disabled="resolveModal.pending" @click="handleResolve">
<span v-if="resolveModal.pending" class="spinner-border spinner-border-sm me-2"></span>
Conferma
</button>
</div>
</div>
</div>
</div>
<ConfirmModal
:open="dismissModal.open"
title="Ignora flag"
message="Vuoi ignorare questo flag? Azione registrata in moderazione."
confirm-label="Ignora flag"
confirm-class="btn-outline-secondary"
:pending="dismissModal.pending"
@cancel="closeDismissModal"
@confirm="handleDismiss"
/>
</div>
</template>