feat: refactor onboarding into a multi-step flow with dedicated routes and session state management
This commit is contained in:
79
apps/frontend/src/features/onboard/onboard-start-page.tsx
Normal file
79
apps/frontend/src/features/onboard/onboard-start-page.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import { OnboardingLayout } from '@/features/onboard/components/onboarding-layout';
|
||||
import { OnboardingStartStep } from '@/features/onboard/components/onboarding-start-step';
|
||||
import {
|
||||
OTP_MAX_ATTEMPTS,
|
||||
defaultCompleteFormValues,
|
||||
defaultVerifyOtpFormValues,
|
||||
getOnboardingSessionState,
|
||||
updateOnboardingSessionState,
|
||||
} from '@/features/onboard/onboarding-session';
|
||||
import type { StartValues } from '@/features/onboard/onboarding.types';
|
||||
import { apiClient } from '@/lib/api-client';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { onboardingStartSchema } from '@repo/api-contract';
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
|
||||
export function OnboardStartPage() {
|
||||
const navigate = useNavigate();
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
||||
const [infoMessage, setInfoMessage] = useState<string | null>(null);
|
||||
const initialState = useMemo(() => getOnboardingSessionState(), []);
|
||||
|
||||
const form = useForm<StartValues>({
|
||||
resolver: zodResolver(onboardingStartSchema),
|
||||
mode: 'onChange',
|
||||
defaultValues: initialState.startForm,
|
||||
});
|
||||
const values = useWatch({ control: form.control });
|
||||
|
||||
useEffect(() => {
|
||||
updateOnboardingSessionState((current) => ({
|
||||
...current,
|
||||
startForm: {
|
||||
fullName: values.fullName ?? '',
|
||||
email: values.email ?? '',
|
||||
},
|
||||
}));
|
||||
}, [values.email, values.fullName]);
|
||||
|
||||
const onSubmit = async (payload: StartValues) => {
|
||||
setErrorMessage(null);
|
||||
setInfoMessage(null);
|
||||
|
||||
try {
|
||||
const result = await apiClient.onboarding.start(payload);
|
||||
|
||||
updateOnboardingSessionState((current) => ({
|
||||
...current,
|
||||
requestId: result.requestId,
|
||||
onboardingEmail: result.email,
|
||||
verifiedEmail: null,
|
||||
remainingAttempts: OTP_MAX_ATTEMPTS,
|
||||
resendCooldownSeconds: result.cooldownSeconds,
|
||||
startForm: {
|
||||
fullName: payload.fullName,
|
||||
email: payload.email,
|
||||
},
|
||||
verifyOtpForm: defaultVerifyOtpFormValues,
|
||||
completeForm: defaultCompleteFormValues,
|
||||
}));
|
||||
|
||||
await navigate({ to: '/onboard/verify' });
|
||||
} catch {
|
||||
setErrorMessage('No pudimos iniciar el onboarding. Intenta nuevamente.');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<OnboardingLayout title="Onboarding" description="Ingresa tu nombre y email para comenzar.">
|
||||
<OnboardingStartStep
|
||||
form={form}
|
||||
errorMessage={errorMessage}
|
||||
infoMessage={infoMessage}
|
||||
onSubmit={onSubmit}
|
||||
/>
|
||||
</OnboardingLayout>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user