weiterer fortschritt mit tamagui und dem neuen mobile event admin

This commit is contained in:
Codex Agent
2025-12-10 20:01:47 +01:00
parent 73e550ee87
commit 7b01a77083
26 changed files with 761 additions and 139 deletions

View File

@@ -5,16 +5,15 @@ import { CalendarDays, MapPin, Settings, Users, Camera, Sparkles, QrCode, Image,
import { YStack, XStack } from '@tamagui/stacks';
import { SizableText as Text } from '@tamagui/text';
import { Pressable } from '@tamagui/react-native-web-lite';
import { MobileScaffold } from './components/Scaffold';
import { MobileShell } from './components/MobileShell';
import { MobileCard, PillBadge, KpiTile, ActionTile } from './components/Primitives';
import { BottomNav } from './components/BottomNav';
import { TenantEvent, EventStats, EventToolkit, getEvent, getEventStats, getEventToolkit } from '../api';
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 { useMobileNav } from './hooks/useMobileNav';
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 }>();
@@ -27,10 +26,14 @@ export default function MobileEventDetailPage() {
const [toolkit, setToolkit] = React.useState<EventToolkit | null>(null);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState<string | null>(null);
const { go } = useMobileNav(slug);
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 () => {
@@ -43,7 +46,18 @@ export default function MobileEventDetailPage() {
setError(null);
} catch (err) {
if (!isAuthError(err)) {
setError(getApiErrorMessage(err, t('events.errors.loadFailed', 'Event konnte nicht geladen werden.')));
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);
@@ -53,8 +67,8 @@ export default function MobileEventDetailPage() {
const kpis = [
{
label: t('events.detail.kpi.tasks', 'Tasks Completed'),
value: toolkit?.tasks?.summary ? `${toolkit.tasks.summary.completed}/${toolkit.tasks.summary.total}` : '—',
label: t('events.detail.kpi.tasks', 'Active Tasks'),
value: event?.tasks_count ?? toolkit?.tasks?.summary?.total ?? '—',
icon: Sparkles,
},
{
@@ -70,19 +84,17 @@ export default function MobileEventDetailPage() {
];
return (
<MobileScaffold
title={t('events.detail.title', 'Event Details Dashboard')}
onBack={() => navigate(adminPath('/mobile/events'))}
rightSlot={
<MobileShell
activeTab="home"
title={resolveEventDisplayName(event ?? activeEvent ?? undefined)}
subtitle={
event?.event_date || activeEvent?.event_date
? formatDate(event?.event_date ?? activeEvent?.event_date)
: undefined
}
onBack={() => navigate(-1)}
headerActions={
<XStack space="$3" alignItems="center">
<Pressable onPress={() => setShowEventPicker(true)}>
<XStack alignItems="center" space="$1.5">
<Text fontSize="$sm" color="#007AFF" fontWeight="600">
{activeEvent?.name ?? t('events.detail.pickEvent', 'Event wählen')}
</Text>
<ChevronDown size={14} color="#007AFF" />
</XStack>
</Pressable>
<Pressable onPress={() => navigate(adminPath('/settings'))}>
<Settings size={18} color="#0f172a" />
</Pressable>
@@ -91,9 +103,6 @@ export default function MobileEventDetailPage() {
</Pressable>
</XStack>
}
footer={
<BottomNav active="home" onNavigate={go} />
}
>
{error ? (
<MobileCard>
@@ -225,7 +234,7 @@ export default function MobileEventDetailPage() {
/>
</XStack>
</YStack>
</MobileScaffold>
</MobileShell>
);
}