weiterer fortschritt mit tamagui und dem neuen mobile event admin
This commit is contained in:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user