import React from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { CalendarDays, MapPin, Settings, Users, Camera, Sparkles, QrCode, Image, Shield, Layout, RefreshCcw, ChevronDown } from 'lucide-react'; import { YStack, XStack } from '@tamagui/stacks'; import { SizableText as Text } from '@tamagui/text'; import { Pressable } from '@tamagui/react-native-web-lite'; import { MobileShell } from './components/MobileShell'; import { MobileCard, PillBadge, KpiTile, ActionTile } from './components/Primitives'; import { TenantEvent, EventStats, EventToolkit, getEvent, getEventStats, getEventToolkit, getEvents } from '../api'; import { adminPath, ADMIN_EVENT_BRANDING_PATH, ADMIN_EVENT_INVITES_PATH, ADMIN_EVENT_MEMBERS_PATH, ADMIN_EVENT_PHOTOS_PATH, ADMIN_EVENT_TASKS_PATH } from '../constants'; import { isAuthError } from '../auth/tokens'; import { getApiErrorMessage } from '../lib/apiError'; import { MobileSheet } from './components/Sheet'; import { useEventContext } from '../context/EventContext'; import { formatEventDate, resolveEventDisplayName } from '../lib/events'; export default function MobileEventDetailPage() { const { slug: slugParam } = useParams<{ slug?: string }>(); const slug = slugParam ?? null; const navigate = useNavigate(); const { t } = useTranslation('management'); const [event, setEvent] = React.useState(null); const [stats, setStats] = React.useState(null); const [toolkit, setToolkit] = React.useState(null); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(null); const { events, activeEvent, selectEvent } = useEventContext(); const [showEventPicker, setShowEventPicker] = React.useState(false); React.useEffect(() => { if (!slug) return; selectEvent(slug); }, [slug, selectEvent]); React.useEffect(() => { if (!slug) return; (async () => { setLoading(true); try { const [eventData, statsData, toolkitData] = await Promise.all([getEvent(slug), getEventStats(slug), getEventToolkit(slug)]); setEvent(eventData); setStats(statsData); setToolkit(toolkitData); setError(null); } catch (err) { if (!isAuthError(err)) { try { const list = await getEvents({ force: true }); const fallback = list.find((ev: TenantEvent) => ev.slug === slug) ?? null; if (fallback) { setEvent(fallback); setError(null); } else { setError(getApiErrorMessage(err, t('events.errors.loadFailed', 'Event konnte nicht geladen werden.'))); } } catch (fallbackErr) { setError(getApiErrorMessage(fallbackErr, t('events.errors.loadFailed', 'Event konnte nicht geladen werden.'))); } } } finally { setLoading(false); } })(); }, [slug, t]); const kpis = [ { label: t('events.detail.kpi.tasks', 'Active Tasks'), value: event?.tasks_count ?? toolkit?.tasks?.summary?.total ?? '—', icon: Sparkles, }, { label: t('events.detail.kpi.guests', 'Guests Registered'), value: toolkit?.invites?.summary.total ?? event?.active_invites_count ?? '—', icon: Users, }, { label: t('events.detail.kpi.photos', 'Images Uploaded'), value: stats?.uploads_total ?? event?.photo_count ?? '—', icon: Camera, }, ]; return ( navigate(-1)} headerActions={ navigate(adminPath('/mobile/settings'))}> navigate(0)}> } > {error ? ( {error} ) : null} {event ? renderName(event.name) : t('events.placeholders.untitled', 'Unbenanntes Event')} {formatDate(event?.event_date)} {resolveLocation(event)} {event?.status === 'published' ? t('events.status.published', 'Live') : t('events.status.draft', 'Draft')} {loading ? ( {Array.from({ length: 3 }).map((_, idx) => ( ))} ) : ( {kpis.map((kpi) => ( ))} )} setShowEventPicker(false)} title={t('events.detail.pickEvent', 'Event wählen')} footer={null} bottomOffsetPx={120} > {events.length === 0 ? ( {t('events.list.empty.description', 'Starte jetzt mit deinem ersten Event.')} ) : ( events.map((ev) => ( { selectEvent(ev.slug ?? null); setShowEventPicker(false); navigate(adminPath(`/mobile/events/${ev.slug}`)); }} > {renderName(ev.name)} {formatDate(ev.event_date)} {ev.slug === activeEvent?.slug ? t('events.detail.active', 'Aktiv') : t('events.actions.open', 'Öffnen')} )) )} {t('events.detail.managementTitle', 'Event Management')} navigate(adminPath(`/mobile/events/${slug ?? ''}/tasks`))} /> navigate(adminPath(`/mobile/events/${slug ?? ''}/qr`))} /> navigate(adminPath(`/mobile/events/${slug ?? ''}/photos`))} /> navigate(adminPath(`/mobile/events/${slug ?? ''}/members`))} /> navigate(adminPath(`/mobile/events/${slug ?? ''}/branding`))} /> navigate(adminPath(`/mobile/events/${slug ?? ''}/photos`))} /> ); } 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'; } function formatDate(iso?: string | null): string { if (!iso) return 'Date tbd'; const date = new Date(iso); if (Number.isNaN(date.getTime())) return 'Date tbd'; return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }); } function resolveLocation(event: TenantEvent | null): string { if (!event) return 'Location'; const settings = (event.settings ?? {}) as Record; const candidate = (settings.location as string | undefined) ?? (settings.address as string | undefined) ?? (settings.city as string | undefined); if (candidate && candidate.trim()) { return candidate; } return 'Location'; }