style(admin): improve moderation UI and catalog button alignment

Added dismissed card styling and reorganized error/empty state rendering in moderation. Added fixed width for catalog action buttons.
This commit is contained in:
2026-06-16 18:30:56 +02:00 Unverified
parent 220f613309
commit 26733b74de
2 changed files with 87 additions and 43 deletions
+7
View File
@@ -444,3 +444,10 @@ const handleDeleteTeam = async () => {
/>
</div>
</template>
<style>
.text-end .btn {
margin: 0 !important;
width: 120px;
}
</style>
+72 -35
View File
@@ -28,9 +28,9 @@ const dismissModal = reactive({
})
const { data: flagsRes, pending, refresh } = useAsyncData(
'admin-moderation-flags',
() => getModerationFlags({ page: page.value, per_page: perPage.value, status: statusFilter.value || undefined }),
{ watch: [page, statusFilter] }
'admin-moderation-flags',
() => getModerationFlags({ page: page.value, per_page: perPage.value, status: statusFilter.value || undefined }),
{ watch: [page, statusFilter] }
)
const openResolveModal = (id: number, rejectReport: boolean) => {
@@ -54,15 +54,14 @@ const handleResolve = async () => {
actionError.value = ''
try {
const res = await updateModerationFlag(resolveModal.flagId, {
await updateModerationFlag(resolveModal.flagId, {
status: 'RESOLVED',
reject_report: resolveModal.rejectReport,
resolution_note: resolveModal.note || undefined
})
if (res.ok) {
await refresh()
closeResolveModal()
}
await refresh()
closeResolveModal()
} catch (err) {
console.error('Failed to resolve flag', err)
actionError.value = 'Errore durante la risoluzione della segnalazione.'
@@ -89,11 +88,10 @@ const handleDismiss = async () => {
actionError.value = ''
try {
const res = await updateModerationFlag(dismissModal.flagId, { status: 'DISMISSED' })
if (res.ok) {
await refresh()
closeDismissModal()
}
await updateModerationFlag(dismissModal.flagId, { status: 'DISMISSED' })
await refresh()
closeDismissModal()
} catch (err) {
console.error('Failed to dismiss flag', err)
actionError.value = 'Errore durante l\'aggiornamento.'
@@ -129,21 +127,28 @@ const formatDate = (dateStr: string) => {
</div>
</div>
<!-- Spostato in modo che non interrompa l'if-else dei caricamenti -->
<div v-if="actionError" class="alert alert-danger mb-4">
{{ actionError }}
</div>
<div v-if="pending" class="text-center py-5">
<div class="spinner-border text-danger" role="status"></div>
</div>
<div v-else-if="!flagsRes?.flags || flagsRes.flags.length === 0" class="alert alert-success">
<div v-else-if="!flagsRes || !flagsRes.flags || flagsRes.flags.length === 0" class="alert alert-success">
Nessun elemento da moderare al momento.
</div>
<div v-if="actionError" class="alert alert-danger">
{{ actionError }}
</div>
<!-- Questo v-else ora è scatenato in modo pulito solo quando i dati esistono davvero -->
<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">
<div
class="card mb-3 border-0"
:class="flag.status === 'DISMISSED' ? 'dismissed-card shadow-none' : 'shadow-sm'"
v-for="flag in flagsRes.flags"
:key="flag.id"
>
<div class="card-header d-flex justify-content-between align-items-center" :class="flag.status === 'DISMISSED' ? 'bg-transparent' : 'bg-light'">
<div>
<strong>Flag #{{ flag.id }}</strong> -
<span class="badge" :class="{
@@ -162,7 +167,7 @@ const formatDate = (dateStr: string) => {
{{ flag.details || 'Nessun dettaglio aggiuntivo fornito.' }}
</p>
<div class="mt-3">
<div class="mt-info">
<span class="badge bg-info me-2">{{ flag.content_type }}</span>
<span v-if="flag.report_id">
Rif:
@@ -175,7 +180,7 @@ const formatDate = (dateStr: string) => {
</span>
</div>
<div class="mt-3 small">
<div class="mt-info small text-muted">
Segnalato da: {{ flag.created_by_email }} (ID: {{ flag.created_by_user_id }})
</div>
@@ -203,11 +208,11 @@ const formatDate = (dateStr: string) => {
</div>
<Pagination
v-if="(flagsRes.total || flagsRes.flags.length) > perPage"
:current-page="page"
:per-page="perPage"
:total-items="flagsRes.total || (page * perPage + 1)"
@page-change="page = $event"
v-if="(flagsRes.total || flagsRes.flags.length) > perPage"
:current-page="page"
:per-page="perPage"
:total-items="flagsRes.total || (page * perPage + 1)"
@page-change="page = $event"
/>
</div>
@@ -235,14 +240,46 @@ const formatDate = (dateStr: string) => {
</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"
: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>
<style scoped>
.dismissed-card {
background-color: #f8f9fa;
opacity: 0.7;
border: 1px solid #e9ecef !important;
}
.dismissed-card .card-header {
padding-top: 0.35rem;
padding-bottom: 0.35rem;
border-bottom: 1px solid rgba(0,0,0,0.05);
}
.dismissed-card .card-body {
padding-top: 0.6rem;
padding-bottom: 0.6rem;
}
.dismissed-card h5.card-title {
font-size: 1rem;
margin-bottom: 0.2rem;
}
.mt-info {
margin-top: 1rem;
}
.dismissed-card .mt-info {
margin-top: 0.4rem;
}
</style>