Fix admin demo review and landing regressions
This commit is contained in:
@@ -86,6 +86,15 @@ export function useAdminCandidateManager() {
|
||||
const categoryOptions = computed(() =>
|
||||
seasonDetail.value.categories.map((category) => ({ label: `${category.groupName} · ${category.name}`, value: category.id })),
|
||||
)
|
||||
const preferredCreateCategoryId = computed(() => {
|
||||
if (categoryFilter.value) {
|
||||
return categoryFilter.value
|
||||
}
|
||||
|
||||
return seasonDetail.value.categories.find((category) =>
|
||||
category.viewerRangeMin !== null || category.viewerRangeMax !== null,
|
||||
)?.id ?? seasonDetail.value.categories[0]?.id ?? 0
|
||||
})
|
||||
const categoryFilterOptions = computed(() => [{ label: 'Alle Kategorien', value: null }, ...categoryOptions.value])
|
||||
const categoryLabelMap = computed<Record<number, string>>(() =>
|
||||
Object.fromEntries(seasonDetail.value.categories.map((category) => [category.id, `${category.groupName} · ${category.name}`])),
|
||||
@@ -307,7 +316,7 @@ export function useAdminCandidateManager() {
|
||||
adminMessage.value = ''
|
||||
adminError.value = ''
|
||||
editingId.value = 'new'
|
||||
form.categoryId = categoryFilter.value ?? seasonDetail.value.categories[0]?.id ?? 0
|
||||
form.categoryId = preferredCreateCategoryId.value
|
||||
form.displayName = ''
|
||||
form.channelSlug = ''
|
||||
form.platform = 'Twitch'
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useAwardsStore } from '../stores/awards'
|
||||
const ADMIN_API_DISCONNECT_TOAST_KEY = 'admin-api-disconnected'
|
||||
const ADMIN_API_DISCONNECT_MESSAGE =
|
||||
'Backend/API nicht erreichbar. Der Admin-Bereich bleibt eingeschränkt, bis die Verbindung wieder da ist.'
|
||||
const ADMIN_API_DISCONNECT_TOAST_DELAY_MS = 1200
|
||||
const RECONNECT_PROBE_INTERVAL_MS = 5000
|
||||
|
||||
export function useAdminApiDisconnectToast(isAdminRoute: ComputedRef<boolean>) {
|
||||
@@ -13,6 +14,7 @@ export function useAdminApiDisconnectToast(isAdminRoute: ComputedRef<boolean>) {
|
||||
const { dismissAdminToast, showAdminToast } = useAdminToast()
|
||||
|
||||
let reconnectTimer: number | undefined
|
||||
let disconnectToastTimer: number | undefined
|
||||
let reconnectProbeRunning = false
|
||||
|
||||
function clearReconnectTimer() {
|
||||
@@ -21,6 +23,12 @@ export function useAdminApiDisconnectToast(isAdminRoute: ComputedRef<boolean>) {
|
||||
reconnectTimer = undefined
|
||||
}
|
||||
|
||||
function clearDisconnectToastTimer() {
|
||||
if (disconnectToastTimer === undefined || typeof window === 'undefined') return
|
||||
window.clearTimeout(disconnectToastTimer)
|
||||
disconnectToastTimer = undefined
|
||||
}
|
||||
|
||||
function scheduleReconnectProbe() {
|
||||
if (reconnectTimer !== undefined || typeof window === 'undefined') return
|
||||
|
||||
@@ -42,18 +50,30 @@ export function useAdminApiDisconnectToast(isAdminRoute: ComputedRef<boolean>) {
|
||||
}, RECONNECT_PROBE_INTERVAL_MS)
|
||||
}
|
||||
|
||||
function scheduleDisconnectToast() {
|
||||
if (disconnectToastTimer !== undefined || typeof window === 'undefined') return
|
||||
|
||||
disconnectToastTimer = window.setTimeout(() => {
|
||||
disconnectToastTimer = undefined
|
||||
if (!isAdminRoute.value || awardsStore.apiMode !== 'fallback') return
|
||||
|
||||
showAdminToast(ADMIN_API_DISCONNECT_MESSAGE, 'error', {
|
||||
key: ADMIN_API_DISCONNECT_TOAST_KEY,
|
||||
persistent: true,
|
||||
})
|
||||
}, ADMIN_API_DISCONNECT_TOAST_DELAY_MS)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => isAdminRoute.value && awardsStore.apiMode === 'fallback',
|
||||
(shouldShowDisconnectToast) => {
|
||||
if (shouldShowDisconnectToast) {
|
||||
showAdminToast(ADMIN_API_DISCONNECT_MESSAGE, 'error', {
|
||||
key: ADMIN_API_DISCONNECT_TOAST_KEY,
|
||||
persistent: true,
|
||||
})
|
||||
scheduleDisconnectToast()
|
||||
scheduleReconnectProbe()
|
||||
return
|
||||
}
|
||||
|
||||
clearDisconnectToastTimer()
|
||||
clearReconnectTimer()
|
||||
dismissAdminToast(ADMIN_API_DISCONNECT_TOAST_KEY)
|
||||
},
|
||||
@@ -61,6 +81,7 @@ export function useAdminApiDisconnectToast(isAdminRoute: ComputedRef<boolean>) {
|
||||
)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearDisconnectToastTimer()
|
||||
clearReconnectTimer()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@ const loginFormElement = ref<HTMLFormElement | null>(null)
|
||||
const passwordChangeFormElement = ref<HTMLFormElement | null>(null)
|
||||
|
||||
const passwordChangeRequired = computed(() => Boolean(authStore.session?.mustChangePassword))
|
||||
const successMessageClass = computed(() =>
|
||||
passwordChangeRequired.value ? 'login-form__warning' : 'login-form__success',
|
||||
)
|
||||
|
||||
const redirectTarget = computed(() => {
|
||||
const redirect = Array.isArray(route.query.redirect)
|
||||
@@ -211,7 +214,7 @@ async function submitPasswordChange() {
|
||||
{{ errorMessage }}
|
||||
</p>
|
||||
|
||||
<p v-if="successMessage" class="login-form__success" role="status">
|
||||
<p v-if="successMessage" :class="successMessageClass" role="status">
|
||||
{{ successMessage }}
|
||||
</p>
|
||||
|
||||
@@ -231,7 +234,7 @@ async function submitPasswordChange() {
|
||||
{{ errorMessage }}
|
||||
</p>
|
||||
|
||||
<p v-if="successMessage" class="login-form__success" role="status">
|
||||
<p v-if="successMessage" :class="successMessageClass" role="status">
|
||||
{{ successMessage }}
|
||||
</p>
|
||||
|
||||
@@ -284,7 +287,7 @@ async function submitPasswordChange() {
|
||||
{{ errorMessage }}
|
||||
</p>
|
||||
|
||||
<p v-if="successMessage" class="login-form__success" role="status">
|
||||
<p v-if="successMessage" :class="successMessageClass" role="status">
|
||||
{{ successMessage }}
|
||||
</p>
|
||||
|
||||
@@ -535,6 +538,16 @@ async function submitPasswordChange() {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.login-form__warning {
|
||||
padding: 13px 15px;
|
||||
border: 1px solid rgba(217, 119, 6, 0.24);
|
||||
border-radius: 18px;
|
||||
background: rgba(255, 251, 235, 0.96);
|
||||
color: #b45309 !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.login-form__submit {
|
||||
min-height: 58px;
|
||||
border: 0;
|
||||
|
||||
@@ -260,13 +260,13 @@ watch(
|
||||
</Teleport>
|
||||
|
||||
<div class="admin-panel pb-10 pt-4 xl:pt-0">
|
||||
<div class="grid gap-6 xl:grid-cols-[292px_minmax(0,1fr)]">
|
||||
<main class="order-1 min-w-0 xl:order-2">
|
||||
<div class="grid gap-6 xl:min-h-[calc(100vh-1rem)] xl:grid-cols-[292px_minmax(0,1fr)]">
|
||||
<main class="order-1 min-w-0 xl:order-2 xl:min-h-0 xl:overflow-y-auto xl:pr-2">
|
||||
<RouterView />
|
||||
</main>
|
||||
|
||||
<!-- Desktop sidebar (hidden on mobile) -->
|
||||
<aside class="order-2 hidden space-y-3 xl:order-1 xl:block xl:sticky xl:top-4 xl:h-fit">
|
||||
<aside class="order-2 hidden space-y-3 xl:order-1 xl:block xl:max-h-[calc(100vh-1rem)] xl:overflow-y-auto xl:pr-1">
|
||||
<Card class="p-3">
|
||||
<nav class="space-y-4">
|
||||
<section v-for="group in navGroups" :key="group.label" class="space-y-1.5">
|
||||
|
||||
Reference in New Issue
Block a user