refactor(onboarding): restructure onboarding routes and components

- Removed obsolete onboarding routes: complete, create-complex, index, verify-email, and verify.
- Introduced new setup stepper page for onboarding process.
- Created a multi-step setup component to handle complex creation with validation.
- Added new schemas for complex creation and plan features.
- Implemented detailed steps for complex name, location, plan selection, and court setup.
- Enhanced error handling and user feedback during the onboarding process.
This commit is contained in:
Jose Selesan
2026-06-02 10:02:28 -03:00
parent 2aaa91444d
commit 4544911f0e
51 changed files with 1006 additions and 2383 deletions

View File

@@ -17,23 +17,9 @@ function AuthCallbackPage() {
try {
await acceptStoredPendingInvite(apiClient.complexes.acceptPendingInvitations);
const complexes = await apiClient.complexes.listMine();
if (complexes.length === 1) {
await apiClient.complexes.select({ complexId: complexes[0].id });
navigate({ to: '/' });
} else if (complexes.length > 1) {
const current = await apiClient.complexes.getCurrent();
if (current) {
navigate({ to: '/' });
} else {
navigate({ to: '/select-complex' });
}
} else {
navigate({ to: '/onboard/create-complex' });
}
navigate({ to: '/' });
} catch {
navigate({ to: '/onboard' });
navigate({ to: '/login' });
}
}

View File

@@ -1,4 +1,3 @@
import { OnboardLoginPage } from '@/features/onboard/onboard-login-page';
import { apiClient } from '@/lib/api-client';
import { useAuth } from '@/lib/auth';
import { acceptStoredPendingInvite, setPendingInvite } from '@/lib/invitations';
@@ -25,6 +24,7 @@ function InvitePage() {
useEffect(() => {
if (!isAuthenticated) {
navigate({ to: '/login' });
return;
}
@@ -34,15 +34,11 @@ function InvitePage() {
})();
}, [isAuthenticated, navigate]);
if (isAuthenticated) {
return (
<main className="flex min-h-screen w-full items-center justify-center px-3 sm:px-6">
<p className="text-sm text-muted-foreground">Aceptando invitación...</p>
</main>
);
}
return <OnboardLoginPage variant="invite" inviteEmail={search.email ?? null} />;
return (
<main className="flex min-h-screen w-full items-center justify-center px-3 sm:px-6">
<p className="text-sm text-muted-foreground">Aceptando invitación...</p>
</main>
);
}
export const Route = createFileRoute('/invite')({

View File

@@ -1,22 +1,11 @@
import { LoginPage } from '@/features/login/login-page';
import { createFileRoute, redirect } from '@tanstack/react-router';
import { z } from 'zod';
const loginSearchSchema = z.object({
redirect: z.string().optional(),
});
export const Route = createFileRoute('/login')({
validateSearch: loginSearchSchema,
beforeLoad: ({ context }) => {
if (context.auth.isAuthenticated) {
throw redirect({ to: '/' });
}
},
component: LoginRouteComponent,
component: LoginPage,
});
function LoginRouteComponent() {
const search = Route.useSearch();
return <LoginPage redirectTo={search.redirect} />;
}

View File

@@ -1,6 +0,0 @@
import { OnboardCompletePage } from '@/features/onboard/onboard-complete-page';
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/onboard/complete')({
component: OnboardCompletePage,
});

View File

@@ -1,11 +0,0 @@
import { OnboardLoginPage } from '@/features/onboard/onboard-login-page';
import { createFileRoute, redirect } from '@tanstack/react-router';
export const Route = createFileRoute('/onboard/')({
beforeLoad: ({ context }) => {
if (!context.auth.isAuthenticated) {
throw redirect({ to: '/login', search: { redirect: '/onboard/create-complex' } });
}
},
component: OnboardLoginPage,
});

View File

@@ -1,14 +1,14 @@
import { CreateComplexPage } from '@/features/onboard/create-complex-page';
import { SetupStepperPage } from '@/features/onboard/setup-stepper-page';
import { createFileRoute, redirect } from '@tanstack/react-router';
export const Route = createFileRoute('/onboard/create-complex')({
export const Route = createFileRoute('/onboard/setup')({
beforeLoad: ({ context }) => {
const hasSession = context.auth.isAuthenticated;
const hasPendingSignup = Boolean(sessionStorage.getItem('pending-signup-email'));
if (!hasSession && !hasPendingSignup) {
throw redirect({ to: '/onboard' });
throw redirect({ to: '/login' });
}
},
component: CreateComplexPage,
component: SetupStepperPage,
});

View File

@@ -1,18 +0,0 @@
import { VerifyEmailPage } from '@/features/onboard/verify-email-page';
import { createFileRoute, redirect } from '@tanstack/react-router';
import { z } from 'zod';
const verifyEmailSearchSchema = z.object({
email: z.string().email().optional(),
});
export const Route = createFileRoute('/onboard/verify-email')({
validateSearch: verifyEmailSearchSchema,
beforeLoad: () => {
const hasPendingSignup = Boolean(sessionStorage.getItem('pending-signup-email'));
if (!hasPendingSignup) {
throw redirect({ to: '/onboard' });
}
},
component: VerifyEmailPage,
});

View File

@@ -1,6 +0,0 @@
import { OnboardVerifyPage } from '@/features/onboard/onboard-verify-page';
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/onboard/verify')({
component: OnboardVerifyPage,
});