rework of the event admin UI

This commit is contained in:
Codex Agent
2025-11-24 17:17:39 +01:00
parent 4667ec8073
commit 8947a37261
37 changed files with 4381 additions and 874 deletions

View File

@@ -5,6 +5,7 @@ import { CalendarDays, ChevronDown, PlusCircle } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { type TenantEvent } from '../api';
import {
Sheet,
SheetContent,
@@ -25,39 +26,8 @@ import {
ADMIN_EVENT_VIEW_PATH,
ADMIN_EVENT_PHOTOBOOTH_PATH,
} from '../constants';
import type { TenantEvent } from '../api';
import { cn } from '@/lib/utils';
function resolveEventName(event: TenantEvent): string {
const name = event.name;
if (typeof name === 'string' && name.trim().length > 0) {
return name;
}
if (name && typeof name === 'object') {
const first = Object.values(name).find((value) => typeof value === 'string' && value.trim().length > 0);
if (first) {
return first;
}
}
return event.slug ?? 'Event';
}
function formatEventDate(value?: string | null, locale = 'de-DE'): string | null {
if (!value) {
return null;
}
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return null;
}
try {
return new Intl.DateTimeFormat(locale, { day: '2-digit', month: 'short', year: 'numeric' }).format(date);
} catch {
return date.toISOString().slice(0, 10);
}
}
import { resolveEventDisplayName, formatEventDate } from '../lib/events';
function buildEventLinks(slug: string, t: ReturnType<typeof useTranslation>['t']) {
return [
@@ -71,14 +41,19 @@ function buildEventLinks(slug: string, t: ReturnType<typeof useTranslation>['t']
];
}
export function EventSwitcher() {
type EventSwitcherProps = {
buttonClassName?: string;
compact?: boolean;
};
export function EventSwitcher({ buttonClassName, compact = false }: EventSwitcherProps = {}) {
const { events, activeEvent, selectEvent } = useEventContext();
const { t, i18n } = useTranslation('common');
const navigate = useNavigate();
const [open, setOpen] = React.useState(false);
const locale = i18n.language?.startsWith('en') ? 'en-GB' : 'de-DE';
const buttonLabel = activeEvent ? resolveEventName(activeEvent) : t('eventSwitcher.placeholder', 'Event auswählen');
const buttonLabel = activeEvent ? resolveEventDisplayName(activeEvent) : t('eventSwitcher.placeholder', 'Event auswählen');
const buttonHint = activeEvent?.event_date
? formatEventDate(activeEvent.event_date, locale)
: events.length > 1
@@ -93,13 +68,24 @@ export function EventSwitcher() {
}
};
const buttonClasses = cn(
'rounded-full border-rose-100 bg-white/80 px-4 text-sm font-semibold text-slate-700 shadow-sm hover:bg-rose-50 dark:border-white/20 dark:bg-white/10 dark:text-white',
compact && 'px-3 text-xs sm:text-sm',
buttonClassName,
);
const buttonLabelClasses = compact ? 'text-sm' : 'hidden sm:inline';
const hintClasses = compact
? 'text-xs text-slate-500 dark:text-slate-300'
: 'text-xs text-slate-500 dark:text-slate-300 sm:ml-2';
return (
<Sheet open={open} onOpenChange={setOpen}>
<SheetTrigger asChild>
<Button variant="outline" size="sm" className="rounded-full border-rose-100 bg-white/80 px-4 text-sm font-semibold text-slate-700 shadow-sm hover:bg-rose-50 dark:border-white/20 dark:bg-white/10 dark:text-white">
<Button variant="outline" size="sm" className={buttonClasses}>
<CalendarDays className="mr-2 h-4 w-4" />
<span className="hidden sm:inline">{buttonLabel}</span>
<span className="text-xs text-slate-500 dark:text-slate-300 sm:ml-2">
<span className={buttonLabelClasses}>{buttonLabel}</span>
<span className={hintClasses}>
{buttonHint}
</span>
<ChevronDown className="ml-2 h-4 w-4" />
@@ -138,7 +124,7 @@ export function EventSwitcher() {
>
<div className="flex items-center justify-between gap-3">
<div>
<p className="text-sm font-semibold">{resolveEventName(event)}</p>
<p className="text-sm font-semibold">{resolveEventDisplayName(event)}</p>
<p className="text-xs text-slate-500 dark:text-slate-300">{date ?? t('eventSwitcher.noDate', 'Kein Datum')}</p>
</div>
{isActive ? (