weiterer fortschritt mit tamagui und dem neuen mobile event admin
This commit is contained in:
@@ -10,13 +10,16 @@ import { MobileShell, renderEventLocation } from './components/MobileShell';
|
||||
import { MobileCard, CTAButton, KpiTile, ActionTile, PillBadge } from './components/Primitives';
|
||||
import { adminPath } from '../constants';
|
||||
import { useEventContext } from '../context/EventContext';
|
||||
import { getEventStats, EventStats, TenantEvent } from '../api';
|
||||
import { getEventStats, EventStats, TenantEvent, getEvents } from '../api';
|
||||
import { formatEventDate, resolveEventDisplayName } from '../lib/events';
|
||||
|
||||
export default function MobileDashboardPage() {
|
||||
const navigate = useNavigate();
|
||||
const { t, i18n } = useTranslation('management');
|
||||
const { events, activeEvent, hasEvents, hasMultipleEvents, isLoading } = useEventContext();
|
||||
const { events, activeEvent, hasEvents, hasMultipleEvents, isLoading, selectEvent } = useEventContext();
|
||||
const [fallbackEvents, setFallbackEvents] = React.useState<TenantEvent[]>([]);
|
||||
const [fallbackLoading, setFallbackLoading] = React.useState(false);
|
||||
const [fallbackAttempted, setFallbackAttempted] = React.useState(false);
|
||||
|
||||
const { data: stats, isLoading: statsLoading } = useQuery<EventStats | null>({
|
||||
queryKey: ['mobile', 'dashboard', 'stats', activeEvent?.slug],
|
||||
@@ -28,8 +31,36 @@ export default function MobileDashboardPage() {
|
||||
});
|
||||
|
||||
const locale = i18n.language?.startsWith('en') ? 'en-GB' : 'de-DE';
|
||||
const { data: dashboardEvents } = useQuery<TenantEvent[]>({
|
||||
queryKey: ['mobile', 'dashboard', 'events'],
|
||||
queryFn: () => getEvents({ force: true }),
|
||||
staleTime: 60_000,
|
||||
});
|
||||
const effectiveEvents = events.length ? events : dashboardEvents?.length ? dashboardEvents : fallbackEvents;
|
||||
const effectiveHasEvents = hasEvents || Boolean(dashboardEvents?.length) || fallbackEvents.length > 0;
|
||||
const effectiveMultiple =
|
||||
hasMultipleEvents || (dashboardEvents?.length ?? 0) > 1 || fallbackEvents.length > 1;
|
||||
|
||||
if (isLoading) {
|
||||
React.useEffect(() => {
|
||||
if (events.length || isLoading || fallbackLoading || fallbackAttempted) {
|
||||
return;
|
||||
}
|
||||
setFallbackAttempted(true);
|
||||
setFallbackLoading(true);
|
||||
getEvents({ force: true })
|
||||
.then((list: TenantEvent[]) => {
|
||||
setFallbackEvents(list ?? []);
|
||||
if (list?.length === 1 && !activeEvent) {
|
||||
selectEvent(list[0]?.slug ?? null);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
setFallbackEvents([]);
|
||||
})
|
||||
.finally(() => setFallbackLoading(false));
|
||||
}, [events.length, isLoading, activeEvent, selectEvent, fallbackLoading, fallbackAttempted]);
|
||||
|
||||
if (isLoading || fallbackLoading) {
|
||||
return (
|
||||
<MobileShell activeTab="home" title={t('events.list.dashboardTitle', 'Dashboard')}>
|
||||
<YStack space="$2">
|
||||
@@ -41,7 +72,7 @@ export default function MobileDashboardPage() {
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasEvents) {
|
||||
if (!effectiveHasEvents) {
|
||||
return (
|
||||
<MobileShell activeTab="home" title={t('events.list.dashboardTitle', 'Dashboard')}>
|
||||
<OnboardingEmptyState />
|
||||
@@ -49,10 +80,14 @@ export default function MobileDashboardPage() {
|
||||
);
|
||||
}
|
||||
|
||||
if (hasMultipleEvents && !activeEvent) {
|
||||
if (effectiveMultiple && !activeEvent) {
|
||||
return (
|
||||
<MobileShell activeTab="home" title={t('events.list.dashboardTitle', 'Dashboard')}>
|
||||
<EventPickerList events={events} locale={locale} />
|
||||
<MobileShell
|
||||
activeTab="home"
|
||||
title={t('events.list.dashboardTitle', 'Dashboard')}
|
||||
subtitle={t('header.selectEvent', 'Select an event to continue')}
|
||||
>
|
||||
<EventPickerList events={effectiveEvents} locale={locale} />
|
||||
</MobileShell>
|
||||
);
|
||||
}
|
||||
@@ -123,16 +158,39 @@ function OnboardingEmptyState() {
|
||||
function EventPickerList({ events, locale }: { events: TenantEvent[]; locale: string }) {
|
||||
const { t } = useTranslation('management');
|
||||
const { selectEvent } = useEventContext();
|
||||
const navigate = useNavigate();
|
||||
const [localEvents, setLocalEvents] = React.useState<TenantEvent[]>(events);
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
setLocalEvents(events);
|
||||
}, [events]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (events.length > 0 || loading) {
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
getEvents({ force: true })
|
||||
.then((list) => setLocalEvents(list ?? []))
|
||||
.catch(() => setLocalEvents([]))
|
||||
.finally(() => setLoading(false));
|
||||
}, [events.length, loading]);
|
||||
|
||||
return (
|
||||
<YStack space="$2">
|
||||
<Text fontSize="$sm" color="#111827" fontWeight="700">
|
||||
{t('events.detail.pickEvent', 'Select an event')}
|
||||
</Text>
|
||||
{events.map((event) => (
|
||||
{localEvents.map((event) => (
|
||||
<Pressable
|
||||
key={event.slug}
|
||||
onPress={() => selectEvent(event.slug ?? null)}
|
||||
onPress={() => {
|
||||
selectEvent(event.slug ?? null);
|
||||
if (event.slug) {
|
||||
navigate(adminPath(`/mobile/events/${event.slug}`));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MobileCard borderColor="#e5e7eb" space="$2">
|
||||
<XStack alignItems="center" justifyContent="space-between">
|
||||
|
||||
Reference in New Issue
Block a user