- Use real logo/isotype SVGs across app and emails - Token-based color system aligned with landing (brand scale + semantic tokens) - ThemeProvider (light/dark/system) with header toggle and settings card - Embed logo in transactional emails; centralize email colors
130 lines
4.0 KiB
TypeScript
130 lines
4.0 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { useQuery } from '@tanstack/react-query'
|
|
import { useNavigate } from '@tanstack/react-router'
|
|
import { Loader2 } from 'lucide-react'
|
|
import type { ConnectPaymentResult, OnboardingGroupDto } from '@gruperly/shared'
|
|
import { Logo, LogoIcon } from '../components/brand'
|
|
import {
|
|
ConfirmationStep,
|
|
FirstGroupStep,
|
|
PaymentStep,
|
|
Stepper,
|
|
WelcomeStep,
|
|
} from '../components/onboarding'
|
|
import { PAYMENT_PROVIDERS } from '../components/onboarding/constants'
|
|
import { Button } from '../components/ui'
|
|
import { useAuth } from '../context/AuthProvider'
|
|
import { getOnboardingStatus } from '../lib/api'
|
|
|
|
const STEPS = [
|
|
{ label: 'Bienvenida' },
|
|
{ label: 'Cobros' },
|
|
{ label: 'Tu grupo' },
|
|
{ label: 'Listo' },
|
|
]
|
|
|
|
export function OnboardingView() {
|
|
const { user, isPending: authPending } = useAuth()
|
|
const navigate = useNavigate()
|
|
|
|
const [step, setStep] = useState(0)
|
|
const [paymentResult, setPaymentResult] = useState<ConnectPaymentResult | null>(null)
|
|
const [createdGroup, setCreatedGroup] = useState<OnboardingGroupDto | null>(null)
|
|
|
|
const statusQuery = useQuery({
|
|
queryKey: ['onboarding', 'status'],
|
|
queryFn: getOnboardingStatus,
|
|
enabled: !!user,
|
|
})
|
|
|
|
useEffect(() => {
|
|
const status = statusQuery.data
|
|
if (!status) return
|
|
if (status.completed) {
|
|
void navigate({ to: '/' })
|
|
return
|
|
}
|
|
// Si interrumpió después de conectar el cobro, retomamos en el paso del grupo.
|
|
if (status.step === 'PAYMENT_CONNECTED') {
|
|
setStep((current) => (current === 0 ? 2 : current))
|
|
}
|
|
}, [statusQuery.data, navigate])
|
|
|
|
if (authPending) {
|
|
return (
|
|
<div className="flex min-h-dvh items-center justify-center">
|
|
<Loader2 className="size-6 animate-spin text-foreground/40" />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (!user) {
|
|
return (
|
|
<div className="flex min-h-dvh items-center justify-center px-4">
|
|
<div className="w-full max-w-sm space-y-4 text-center">
|
|
<span className="mx-auto flex size-14 items-center justify-center rounded-2xl bg-accent-soft">
|
|
<LogoIcon className="size-8" />
|
|
</span>
|
|
<h1 className="text-2xl font-bold text-primary">Tu cuenta, lista</h1>
|
|
<p className="text-sm text-foreground/60">
|
|
Iniciá sesión para configurar tus cobros y crear tu primer grupo.
|
|
</p>
|
|
<Button variant="primary" className="w-full" onClick={() => void navigate({ to: '/login' })}>
|
|
Iniciar sesión
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
if (statusQuery.isPending) {
|
|
return (
|
|
<div className="flex min-h-dvh items-center justify-center">
|
|
<Loader2 className="size-6 animate-spin text-foreground/40" />
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const firstName = user.name?.trim().split(/\s+/)[0] ?? 'profesor/a'
|
|
const providerName = paymentResult
|
|
? PAYMENT_PROVIDERS.find((p) => p.value === paymentResult.provider)?.name
|
|
: undefined
|
|
|
|
return (
|
|
<main className="mx-auto flex min-h-dvh w-full max-w-md flex-col px-4 pb-12 pt-8 sm:pt-12">
|
|
<header className="mb-6 flex items-center justify-center">
|
|
<Logo className="h-6" />
|
|
</header>
|
|
|
|
<Stepper steps={STEPS} current={step} />
|
|
|
|
<div key={step} className="mt-8 animate-step-enter">
|
|
{step === 0 ? (
|
|
<WelcomeStep name={firstName} onNext={() => setStep(1)} />
|
|
) : null}
|
|
{step === 1 ? (
|
|
<PaymentStep
|
|
initialResult={paymentResult}
|
|
onConnected={(result) => {
|
|
setPaymentResult(result)
|
|
setStep(2)
|
|
}}
|
|
onBack={() => setStep(0)}
|
|
/>
|
|
) : null}
|
|
{step === 2 ? (
|
|
<FirstGroupStep
|
|
onBack={() => setStep(1)}
|
|
onCompleted={(group) => {
|
|
setCreatedGroup(group)
|
|
setStep(3)
|
|
}}
|
|
/>
|
|
) : null}
|
|
{step === 3 && createdGroup ? (
|
|
<ConfirmationStep group={createdGroup} providerName={providerName} />
|
|
) : null}
|
|
</div>
|
|
</main>
|
|
)
|
|
} |