Unify setup status block
This commit is contained in:
@@ -50,6 +50,7 @@
|
|||||||
"readiness": {
|
"readiness": {
|
||||||
"title": "Bereit für den Eventstart",
|
"title": "Bereit für den Eventstart",
|
||||||
"description": "Erledige diese Schritte, damit Gäste ohne Reibung loslegen können.",
|
"description": "Erledige diese Schritte, damit Gäste ohne Reibung loslegen können.",
|
||||||
|
"nextStepTitle": "Nächster Schritt",
|
||||||
"pending": "Noch offen",
|
"pending": "Noch offen",
|
||||||
"complete": "Erledigt",
|
"complete": "Erledigt",
|
||||||
"items": {
|
"items": {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
"readiness": {
|
"readiness": {
|
||||||
"title": "Ready for event day",
|
"title": "Ready for event day",
|
||||||
"description": "Complete these steps so guests can join without friction.",
|
"description": "Complete these steps so guests can join without friction.",
|
||||||
|
"nextStepTitle": "Next step",
|
||||||
"pending": "Pending",
|
"pending": "Pending",
|
||||||
"complete": "Done",
|
"complete": "Done",
|
||||||
"items": {
|
"items": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import { AlertCircle, Bell, CalendarDays, Camera, CheckCircle2, ChevronRight, Download, Image as ImageIcon, Layout, ListTodo, Megaphone, QrCode, Settings, ShieldCheck, Sparkles, TrendingUp, Tv, Users } from 'lucide-react';
|
import { AlertCircle, Bell, CalendarDays, Camera, CheckCircle2, ChevronRight, Circle, Download, Image as ImageIcon, Layout, ListTodo, Megaphone, QrCode, Settings, ShieldCheck, Sparkles, TrendingUp, Tv, Users } from 'lucide-react';
|
||||||
import { Button } from '@tamagui/button';
|
import { Button } from '@tamagui/button';
|
||||||
import { Card } from '@tamagui/card';
|
import { Card } from '@tamagui/card';
|
||||||
import { YGroup } from '@tamagui/group';
|
import { YGroup } from '@tamagui/group';
|
||||||
@@ -218,15 +218,6 @@ export default function MobileDashboardPage() {
|
|||||||
variant="embedded"
|
variant="embedded"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 1b. SETUP CHECKLIST */}
|
|
||||||
{phase === 'setup' && (
|
|
||||||
<SetupChecklist
|
|
||||||
steps={readiness.steps}
|
|
||||||
title={t('dashboard:readiness.title', 'Bereit für den Eventstart')}
|
|
||||||
variant="embedded"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 2. PULSE STRIP */}
|
{/* 2. PULSE STRIP */}
|
||||||
<Separator backgroundColor={theme.border} opacity={0.6} />
|
<Separator backgroundColor={theme.border} opacity={0.6} />
|
||||||
<PulseStrip event={activeEvent} stats={stats} />
|
<PulseStrip event={activeEvent} stats={stats} />
|
||||||
@@ -398,9 +389,7 @@ function LifecycleHero({ event, stats, locale, navigate, readiness, variant = 'd
|
|||||||
|
|
||||||
// SETUP
|
// SETUP
|
||||||
const nextStep = readiness.nextStep;
|
const nextStep = readiness.nextStep;
|
||||||
const ctaLabel = nextStep ? nextStep.ctaLabel : t('dashboard:onboarding.hero.cta', 'Setup Complete');
|
const showNextStep = Boolean(nextStep);
|
||||||
const ctaAction = nextStep ? () => navigate(adminPath(nextStep.targetPath)) : undefined;
|
|
||||||
const showCta = Boolean(nextStep);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<YStack space="$2">
|
<YStack space="$2">
|
||||||
@@ -424,24 +413,52 @@ function LifecycleHero({ event, stats, locale, navigate, readiness, variant = 'd
|
|||||||
</YStack>
|
</YStack>
|
||||||
</XStack>
|
</XStack>
|
||||||
|
|
||||||
{showCta ? <Separator backgroundColor={theme.border} opacity={0.6} /> : null}
|
{showNextStep ? (
|
||||||
|
<YStack space="$2">
|
||||||
{showCta ? (
|
<Text fontSize="$xs" fontWeight="700" color={theme.muted} textTransform="uppercase" letterSpacing={1}>
|
||||||
<Button
|
{t('dashboard:readiness.nextStepTitle', 'Next step')}
|
||||||
onPress={ctaAction}
|
</Text>
|
||||||
backgroundColor={theme.primary}
|
<YGroup {...({ borderRadius: "$4", borderWidth: 1, borderColor: theme.border, overflow: "hidden" } as any)}>
|
||||||
borderColor="transparent"
|
<YGroup.Item>
|
||||||
height={48}
|
<ListItem
|
||||||
borderRadius={16}
|
hoverTheme
|
||||||
>
|
pressTheme
|
||||||
<XStack alignItems="center" space="$2">
|
paddingVertical="$2"
|
||||||
<Text fontSize="$sm" fontWeight="800" color="white">
|
paddingHorizontal="$3"
|
||||||
{ctaLabel}
|
onPress={() => navigate(adminPath(nextStep.targetPath))}
|
||||||
</Text>
|
title={
|
||||||
<ChevronRight size={16} color="white" />
|
<XStack alignItems="center" space="$2">
|
||||||
</XStack>
|
<Circle size={18} color={theme.primary} strokeWidth={2.5} />
|
||||||
</Button>
|
<Text fontSize="$sm" fontWeight="700" color={theme.textStrong}>
|
||||||
|
{nextStep.label}
|
||||||
|
</Text>
|
||||||
|
</XStack>
|
||||||
|
}
|
||||||
|
subTitle={
|
||||||
|
nextStep.description ? (
|
||||||
|
<Text fontSize="$xs" color={theme.muted}>
|
||||||
|
{nextStep.description}
|
||||||
|
</Text>
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
|
iconAfter={
|
||||||
|
<XStack alignItems="center" space="$1">
|
||||||
|
<PillBadge tone="success">{nextStep.ctaLabel}</PillBadge>
|
||||||
|
<ChevronRight size={16} color={theme.muted} />
|
||||||
|
</XStack>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</YGroup.Item>
|
||||||
|
</YGroup>
|
||||||
|
</YStack>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
|
<Separator backgroundColor={theme.border} opacity={0.6} />
|
||||||
|
<SetupChecklist
|
||||||
|
steps={readiness.steps}
|
||||||
|
title={t('dashboard:readiness.title', 'Bereit für den Eventstart')}
|
||||||
|
variant="inline"
|
||||||
|
/>
|
||||||
</YStack>
|
</YStack>
|
||||||
</DashboardCard>
|
</DashboardCard>
|
||||||
</YStack>
|
</YStack>
|
||||||
|
|||||||
@@ -22,32 +22,21 @@ export function SetupChecklist({
|
|||||||
}: {
|
}: {
|
||||||
steps: ReadinessStep[];
|
steps: ReadinessStep[];
|
||||||
title: string;
|
title: string;
|
||||||
variant?: 'card' | 'embedded';
|
variant?: 'card' | 'inline';
|
||||||
}) {
|
}) {
|
||||||
const theme = useAdminTheme();
|
const theme = useAdminTheme();
|
||||||
const { t } = useTranslation('dashboard');
|
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(true);
|
||||||
const isEmbedded = variant === 'embedded';
|
const isInline = variant === 'inline';
|
||||||
|
|
||||||
const completedCount = steps.filter(s => s.isComplete).length;
|
const completedCount = steps.filter(s => s.isComplete).length;
|
||||||
const totalSteps = steps.length;
|
const totalSteps = steps.length;
|
||||||
const progressValue = totalSteps > 0 ? Math.round((completedCount / totalSteps) * 100) : 0;
|
const progressValue = totalSteps > 0 ? Math.round((completedCount / totalSteps) * 100) : 0;
|
||||||
|
|
||||||
return (
|
const content = (
|
||||||
<Card
|
<YStack>
|
||||||
backgroundColor={theme.surface}
|
|
||||||
borderRadius={isEmbedded ? 16 : 20}
|
|
||||||
borderWidth={1}
|
|
||||||
borderColor={theme.border}
|
|
||||||
padding="$0"
|
|
||||||
overflow="hidden"
|
|
||||||
shadowColor={theme.shadow}
|
|
||||||
shadowOpacity={isEmbedded ? 0 : 0.16}
|
|
||||||
shadowRadius={isEmbedded ? 0 : 16}
|
|
||||||
shadowOffset={isEmbedded ? { width: 0, height: 0 } : { width: 0, height: 10 }}
|
|
||||||
>
|
|
||||||
<Pressable onPress={() => setCollapsed(!collapsed)}>
|
<Pressable onPress={() => setCollapsed(!collapsed)}>
|
||||||
<YStack padding="$3" paddingVertical="$2.5" space="$2">
|
<YStack padding="$3" paddingVertical="$2.5" space="$2">
|
||||||
<XStack alignItems="center" justifyContent="space-between">
|
<XStack alignItems="center" justifyContent="space-between">
|
||||||
@@ -132,6 +121,27 @@ export function SetupChecklist({
|
|||||||
</YGroup>
|
</YGroup>
|
||||||
</YStack>
|
</YStack>
|
||||||
)}
|
)}
|
||||||
|
</YStack>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isInline) {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
backgroundColor={theme.surface}
|
||||||
|
borderRadius={20}
|
||||||
|
borderWidth={1}
|
||||||
|
borderColor={theme.border}
|
||||||
|
padding="$0"
|
||||||
|
overflow="hidden"
|
||||||
|
shadowColor={theme.shadow}
|
||||||
|
shadowOpacity={0.16}
|
||||||
|
shadowRadius={16}
|
||||||
|
shadowOffset={{ width: 0, height: 10 }}
|
||||||
|
>
|
||||||
|
{content}
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user