Improve admin navigation and local API reachability
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, ref, watch } from 'vue'
|
||||
|
||||
import AdminPageHeader from '../../components/admin/AdminPageHeader.vue'
|
||||
import AdminSeasonToolbar from '../../components/admin/AdminSeasonToolbar.vue'
|
||||
import Button from '../../components/ui/Button.vue'
|
||||
import Card from '../../components/ui/Card.vue'
|
||||
@@ -19,6 +20,17 @@ const reviewForms = reactive<Record<number, {
|
||||
|
||||
const seasonDetail = computed(() => store.adminSeasonDetail)
|
||||
const selectedSeasonId = computed(() => store.adminSelectedSeasonId)
|
||||
const reviewFilter = ref('')
|
||||
const filteredNominations = computed(() => {
|
||||
const query = reviewFilter.value.trim().toLowerCase()
|
||||
if (!query) return seasonDetail.value.pendingNominations
|
||||
return seasonDetail.value.pendingNominations.filter((nomination) =>
|
||||
[nomination.categoryName, nomination.candidateText, nomination.submittedByTwitchId]
|
||||
.join(' ')
|
||||
.toLowerCase()
|
||||
.includes(query),
|
||||
)
|
||||
})
|
||||
|
||||
watch(
|
||||
seasonDetail,
|
||||
@@ -71,6 +83,12 @@ async function rejectNomination(nominationId: number) {
|
||||
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<AdminPageHeader
|
||||
eyebrow="Reviews"
|
||||
title="Freitext-Nominierungen sichten"
|
||||
description="Alle uneindeutigen oder noch nicht gemappten Nominierungen laufen hier zusammen. Suche nach User, Kategorie oder Kandidat und entscheide dann direkt im Kontext."
|
||||
/>
|
||||
|
||||
<AdminSeasonToolbar />
|
||||
|
||||
<Card class="p-7">
|
||||
@@ -80,7 +98,7 @@ async function rejectNomination(nominationId: number) {
|
||||
<p class="mt-2 text-sm text-slate-500">Freitext-Nominierungen und Alias-Faelle, die das Team direkt in Kandidaten ueberfuehren oder verwerfen kann.</p>
|
||||
</div>
|
||||
<span class="text-sm uppercase tracking-[0.2em] text-slate-500">
|
||||
{{ seasonDetail.pendingNominations.length }} offen
|
||||
{{ filteredNominations.length }} / {{ seasonDetail.pendingNominations.length }} offen
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -91,9 +109,21 @@ async function rejectNomination(nominationId: number) {
|
||||
{{ adminError }}
|
||||
</p>
|
||||
|
||||
<div class="mt-6 grid gap-4 md:grid-cols-[minmax(0,1fr)_220px]">
|
||||
<input
|
||||
v-model="reviewFilter"
|
||||
type="text"
|
||||
class="rounded-2xl border border-violet-200 px-4 py-3"
|
||||
placeholder="Nach Kategorie, Nominierung oder User filtern"
|
||||
/>
|
||||
<div class="rounded-2xl border border-violet-100 bg-violet-50/60 px-4 py-3 text-sm text-slate-600">
|
||||
Tipp: Suche erst nach dem Problemfall, dann entscheide uebernehmen oder verwerfen.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 space-y-4">
|
||||
<div
|
||||
v-for="nomination in seasonDetail.pendingNominations"
|
||||
v-for="nomination in filteredNominations"
|
||||
:key="nomination.id"
|
||||
class="rounded-[26px] border border-violet-100 bg-white/90 p-5"
|
||||
>
|
||||
@@ -144,6 +174,9 @@ async function rejectNomination(nominationId: number) {
|
||||
<p v-if="seasonDetail.pendingNominations.length === 0" class="rounded-[26px] border border-dashed border-violet-100 px-5 py-6 text-sm text-slate-500">
|
||||
Keine offenen Review-Faelle in der aktuell gewaehlten Season.
|
||||
</p>
|
||||
<p v-else-if="filteredNominations.length === 0" class="rounded-[26px] border border-dashed border-violet-100 px-5 py-6 text-sm text-slate-500">
|
||||
Keine Review-Faelle passen zum aktuellen Filter.
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user