Compact dashboard overview
This commit is contained in:
@@ -199,16 +199,15 @@ export default function MobileDashboardPage() {
|
|||||||
return (
|
return (
|
||||||
<MobileShell activeTab="home" title={t('mobileDashboard.title', 'Dashboard')}>
|
<MobileShell activeTab="home" title={t('mobileDashboard.title', 'Dashboard')}>
|
||||||
<DashboardCard padding="$0">
|
<DashboardCard padding="$0">
|
||||||
<YStack padding="$3.5" space="$2">
|
<YStack padding="$3" space="$2">
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title={t('dashboard:overview.title', 'At a glance')}
|
title={t('dashboard:overview.title', 'At a glance')}
|
||||||
subtitle={t('dashboard:overview.description', 'Key customer metrics at a glance.')}
|
|
||||||
showSeparator={false}
|
showSeparator={false}
|
||||||
compact
|
compact
|
||||||
/>
|
/>
|
||||||
</YStack>
|
</YStack>
|
||||||
<Separator backgroundColor={theme.border} opacity={0.6} />
|
<Separator backgroundColor={theme.border} opacity={0.6} />
|
||||||
<YStack padding="$3.5" space="$2.5">
|
<YStack padding="$3" space="$2.5">
|
||||||
{/* 1. LIFECYCLE HERO */}
|
{/* 1. LIFECYCLE HERO */}
|
||||||
<LifecycleHero
|
<LifecycleHero
|
||||||
event={activeEvent}
|
event={activeEvent}
|
||||||
@@ -223,12 +222,13 @@ export default function MobileDashboardPage() {
|
|||||||
{phase === 'setup' && (
|
{phase === 'setup' && (
|
||||||
<SetupChecklist
|
<SetupChecklist
|
||||||
steps={readiness.steps}
|
steps={readiness.steps}
|
||||||
title={t('management:photobooth.checklist.title', 'Checklist')}
|
title={t('dashboard:readiness.title', 'Bereit für den Eventstart')}
|
||||||
variant="embedded"
|
variant="embedded"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 2. PULSE STRIP */}
|
{/* 2. PULSE STRIP */}
|
||||||
|
<Separator backgroundColor={theme.border} opacity={0.6} />
|
||||||
<PulseStrip event={activeEvent} stats={stats} />
|
<PulseStrip event={activeEvent} stats={stats} />
|
||||||
</YStack>
|
</YStack>
|
||||||
</DashboardCard>
|
</DashboardCard>
|
||||||
@@ -400,6 +400,7 @@ function LifecycleHero({ event, stats, locale, navigate, readiness, variant = 'd
|
|||||||
const nextStep = readiness.nextStep;
|
const nextStep = readiness.nextStep;
|
||||||
const ctaLabel = nextStep ? nextStep.ctaLabel : t('dashboard:onboarding.hero.cta', 'Setup Complete');
|
const ctaLabel = nextStep ? nextStep.ctaLabel : t('dashboard:onboarding.hero.cta', 'Setup Complete');
|
||||||
const ctaAction = nextStep ? () => navigate(adminPath(nextStep.targetPath)) : undefined;
|
const ctaAction = nextStep ? () => navigate(adminPath(nextStep.targetPath)) : undefined;
|
||||||
|
const showCta = Boolean(nextStep);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<YStack space="$2">
|
<YStack space="$2">
|
||||||
@@ -423,9 +424,9 @@ function LifecycleHero({ event, stats, locale, navigate, readiness, variant = 'd
|
|||||||
</YStack>
|
</YStack>
|
||||||
</XStack>
|
</XStack>
|
||||||
|
|
||||||
<Separator backgroundColor={theme.border} opacity={0.6} />
|
{showCta ? <Separator backgroundColor={theme.border} opacity={0.6} /> : null}
|
||||||
|
|
||||||
{!readiness.isReady ? (
|
{showCta ? (
|
||||||
<Button
|
<Button
|
||||||
onPress={ctaAction}
|
onPress={ctaAction}
|
||||||
backgroundColor={theme.primary}
|
backgroundColor={theme.primary}
|
||||||
@@ -440,14 +441,7 @@ function LifecycleHero({ event, stats, locale, navigate, readiness, variant = 'd
|
|||||||
<ChevronRight size={16} color="white" />
|
<ChevronRight size={16} color="white" />
|
||||||
</XStack>
|
</XStack>
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : null}
|
||||||
<XStack alignItems="center" space="$2">
|
|
||||||
<CheckCircle2 size={18} color={theme.successText} />
|
|
||||||
<Text fontSize="$sm" color={theme.successText} fontWeight="700">
|
|
||||||
{t('management:mobileDashboard.readyForLiftoff', 'Ready for Liftoff')}
|
|
||||||
</Text>
|
|
||||||
</XStack>
|
|
||||||
)}
|
|
||||||
</YStack>
|
</YStack>
|
||||||
</DashboardCard>
|
</DashboardCard>
|
||||||
</YStack>
|
</YStack>
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Card } from '@tamagui/card';
|
import { Card } from '@tamagui/card';
|
||||||
import { YGroup } from '@tamagui/group';
|
import { YGroup } from '@tamagui/group';
|
||||||
import { ListItem } from '@tamagui/list-item';
|
import { ListItem } from '@tamagui/list-item';
|
||||||
|
import { Progress } from '@tamagui/progress';
|
||||||
import { YStack, XStack } from '@tamagui/stacks';
|
import { YStack, XStack } from '@tamagui/stacks';
|
||||||
import { SizableText as Text } from '@tamagui/text';
|
import { SizableText as Text } from '@tamagui/text';
|
||||||
import { Pressable } from '@tamagui/react-native-web-lite';
|
import { Pressable } from '@tamagui/react-native-web-lite';
|
||||||
@@ -23,12 +25,15 @@ export function SetupChecklist({
|
|||||||
variant?: 'card' | 'embedded';
|
variant?: 'card' | 'embedded';
|
||||||
}) {
|
}) {
|
||||||
const theme = useAdminTheme();
|
const theme = useAdminTheme();
|
||||||
|
const { t } = useTranslation('dashboard');
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const isAllComplete = steps.every(s => s.isComplete);
|
const isAllComplete = steps.every(s => s.isComplete);
|
||||||
const [collapsed, setCollapsed] = React.useState(isAllComplete);
|
const [collapsed, setCollapsed] = React.useState(isAllComplete);
|
||||||
const isEmbedded = variant === 'embedded';
|
const isEmbedded = variant === 'embedded';
|
||||||
|
|
||||||
const completedCount = steps.filter(s => s.isComplete).length;
|
const completedCount = steps.filter(s => s.isComplete).length;
|
||||||
|
const totalSteps = steps.length;
|
||||||
|
const progressValue = totalSteps > 0 ? Math.round((completedCount / totalSteps) * 100) : 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
@@ -44,23 +49,37 @@ export function SetupChecklist({
|
|||||||
shadowOffset={isEmbedded ? { width: 0, height: 0 } : { width: 0, height: 10 }}
|
shadowOffset={isEmbedded ? { width: 0, height: 0 } : { width: 0, height: 10 }}
|
||||||
>
|
>
|
||||||
<Pressable onPress={() => setCollapsed(!collapsed)}>
|
<Pressable onPress={() => setCollapsed(!collapsed)}>
|
||||||
<XStack padding="$3" paddingVertical="$2.5" alignItems="center" justifyContent="space-between">
|
<YStack padding="$3" paddingVertical="$2.5" space="$2">
|
||||||
<XStack alignItems="center" space="$2">
|
<XStack alignItems="center" justifyContent="space-between">
|
||||||
<Text fontSize="$xs" fontWeight="700" color={theme.muted} textTransform="uppercase" letterSpacing={1}>
|
<XStack alignItems="center" space="$2">
|
||||||
|
<Text fontSize="$xs" fontWeight="700" color={theme.muted} textTransform="uppercase" letterSpacing={1}>
|
||||||
{title}
|
{title}
|
||||||
</Text>
|
</Text>
|
||||||
{isAllComplete && (
|
<PillBadge tone={isAllComplete ? 'success' : 'warning'}>
|
||||||
<CheckCircle2 size={14} color={theme.successText} />
|
{isAllComplete ? t('readiness.complete', 'Erledigt') : t('readiness.pending', 'Noch offen')}
|
||||||
)}
|
</PillBadge>
|
||||||
</XStack>
|
</XStack>
|
||||||
|
|
||||||
<XStack alignItems="center" space="$2">
|
<XStack alignItems="center" space="$2">
|
||||||
<Text fontSize="$xs" color={theme.muted} fontWeight="600">
|
<Text fontSize="$xs" color={theme.muted} fontWeight="600">
|
||||||
{completedCount}/{steps.length}
|
{completedCount}/{steps.length}
|
||||||
</Text>
|
</Text>
|
||||||
{collapsed ? <ChevronDown size={16} color={theme.muted} /> : <ChevronUp size={16} color={theme.muted} />}
|
{collapsed ? <ChevronDown size={16} color={theme.muted} /> : <ChevronUp size={16} color={theme.muted} />}
|
||||||
</XStack>
|
</XStack>
|
||||||
</XStack>
|
</XStack>
|
||||||
|
|
||||||
|
<Progress
|
||||||
|
value={progressValue}
|
||||||
|
size="$1"
|
||||||
|
backgroundColor={theme.surfaceMuted}
|
||||||
|
height={6}
|
||||||
|
>
|
||||||
|
<Progress.Indicator
|
||||||
|
backgroundColor={isAllComplete ? theme.success : theme.primary}
|
||||||
|
animation="bouncy"
|
||||||
|
/>
|
||||||
|
</Progress>
|
||||||
|
</YStack>
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
|
||||||
{!collapsed && (
|
{!collapsed && (
|
||||||
|
|||||||
Reference in New Issue
Block a user