import React from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { ArrowLeft, Camera, Heart, Loader2, RefreshCw, Share2, Sparkles } from 'lucide-react'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { AdminLayout } from '../components/AdminLayout'; import { createInviteLink, getEvent, getEventStats, TenantEvent, EventStats as TenantEventStats, toggleEvent } from '../api'; import { isAuthError } from '../auth/tokens'; import { adminPath } from '../constants'; interface State { event: TenantEvent | null; stats: TenantEventStats | null; inviteLink: string | null; error: string | null; loading: boolean; busy: boolean; } export default function EventDetailPage() { const [searchParams] = useSearchParams(); const slug = searchParams.get('slug'); const navigate = useNavigate(); const [state, setState] = React.useState({ event: null, stats: null, inviteLink: null, error: null, loading: true, busy: false, }); const load = React.useCallback(async () => { if (!slug) { setState((prev) => ({ ...prev, loading: false, error: 'Kein Event-Slug angegeben.' })); return; } setState((prev) => ({ ...prev, loading: true, error: null })); try { const [eventData, statsData] = await Promise.all([getEvent(slug), getEventStats(slug)]); setState((prev) => ({ ...prev, event: eventData, stats: statsData, loading: false, inviteLink: prev.inviteLink, })); } catch (err) { if (isAuthError(err)) return; setState((prev) => ({ ...prev, error: 'Event konnte nicht geladen werden.', loading: false })); } }, [slug]); React.useEffect(() => { load(); }, [load]); async function handleToggle() { if (!slug) return; setState((prev) => ({ ...prev, busy: true, error: null })); try { const updated = await toggleEvent(slug); setState((prev) => ({ ...prev, event: updated, stats: prev.stats ? { ...prev.stats, status: updated.status, is_active: Boolean(updated.is_active) } : prev.stats, busy: false, })); } catch (err) { if (!isAuthError(err)) { setState((prev) => ({ ...prev, error: 'Status konnte nicht angepasst werden.', busy: false })); } else { setState((prev) => ({ ...prev, busy: false })); } } } async function handleInvite() { if (!slug) return; setState((prev) => ({ ...prev, busy: true, error: null })); try { const { link } = await createInviteLink(slug); setState((prev) => ({ ...prev, inviteLink: link, busy: false })); try { await navigator.clipboard.writeText(link); } catch { // clipboard may be unavailable, ignore silently } } catch (err) { if (!isAuthError(err)) { setState((prev) => ({ ...prev, error: 'Einladungslink konnte nicht erzeugt werden.', busy: false })); } else { setState((prev) => ({ ...prev, busy: false })); } } } const { event, stats, inviteLink, error, loading, busy } = state; const actions = ( <> {event && ( )} ); if (!slug) { return ( Ohne gueltigen Slug koennen wir keine Daten laden. Kehre zur Event-Liste zurueck und waehle dort ein Event aus. ); } return ( {error && ( Aktion fehlgeschlagen {error} )} {loading ? ( ) : event ? (
Eventdaten Grundlegende Informationen fuer Gaeste und Moderation.
Einladungen Generiere Links um Gaeste direkt in das Event zu fuehren. {inviteLink && (

{inviteLink}

)}
Performance Kennzahlen zu Uploads, Highlights und Interaktion.
) : ( Event nicht gefunden Bitte pruefe den Slug und versuche es erneut. )}
); } function DetailSkeleton() { return (
{Array.from({ length: 3 }).map((_, index) => (
))}
); } function InfoRow({ label, value }: { label: string; value: string }) { return (
{label} {value}
); } function StatChip({ label, value }: { label: string; value: string | number }) { return (
{label}
{value}
); } function formatDate(iso: string | null): string { if (!iso) return 'Noch kein Datum'; const date = new Date(iso); if (Number.isNaN(date.getTime())) { return 'Unbekanntes Datum'; } return date.toLocaleDateString('de-DE', { day: '2-digit', month: 'long', year: 'numeric' }); } function renderName(name: TenantEvent['name']): string { if (typeof name === 'string') { return name; } if (name && typeof name === 'object') { return name.de ?? name.en ?? Object.values(name)[0] ?? 'Unbenanntes Event'; } return 'Unbenanntes Event'; }