120 lines
4.2 KiB
TypeScript
120 lines
4.2 KiB
TypeScript
import { Button } from '@/components/ui/button';
|
|
import { Field, FieldError, FieldLabel } from '@/components/ui/field';
|
|
import { Input } from '@/components/ui/input';
|
|
import type { CompleteValues } from '@/features/onboard/onboarding.types';
|
|
import type { PlanSummary } from '@repo/api-contract';
|
|
import { Controller, type UseFormReturn } from 'react-hook-form';
|
|
|
|
type OnboardingCompleteStepProps = {
|
|
form: UseFormReturn<CompleteValues>;
|
|
plans: PlanSummary[];
|
|
verifiedEmail: string | null;
|
|
errorMessage: string | null;
|
|
infoMessage: string | null;
|
|
planPlaceholder: string;
|
|
onSubmit: (values: CompleteValues) => Promise<void>;
|
|
};
|
|
|
|
export function OnboardingCompleteStep({
|
|
form,
|
|
plans,
|
|
verifiedEmail,
|
|
errorMessage,
|
|
infoMessage,
|
|
planPlaceholder,
|
|
onSubmit,
|
|
}: OnboardingCompleteStepProps) {
|
|
return (
|
|
<form className="space-y-3" onSubmit={form.handleSubmit(onSubmit)}>
|
|
{verifiedEmail && (
|
|
<Field>
|
|
<FieldLabel htmlFor="verified-email">Email verificado</FieldLabel>
|
|
<Input id="verified-email" type="email" value={verifiedEmail} disabled readOnly />
|
|
</Field>
|
|
)}
|
|
|
|
<Field data-invalid={Boolean(form.formState.errors.password)}>
|
|
<FieldLabel htmlFor="onboard-password">Contraseña</FieldLabel>
|
|
<Input
|
|
id="onboard-password"
|
|
type="password"
|
|
placeholder="********"
|
|
aria-invalid={Boolean(form.formState.errors.password)}
|
|
{...form.register('password')}
|
|
/>
|
|
<FieldError errors={[form.formState.errors.password]} />
|
|
</Field>
|
|
|
|
<Field data-invalid={Boolean(form.formState.errors.complexName)}>
|
|
<FieldLabel htmlFor="complex-name">Nombre del complejo</FieldLabel>
|
|
<Input
|
|
id="complex-name"
|
|
type="text"
|
|
placeholder="Complejo Las Palmeras"
|
|
aria-invalid={Boolean(form.formState.errors.complexName)}
|
|
{...form.register('complexName')}
|
|
/>
|
|
<FieldError errors={[form.formState.errors.complexName]} />
|
|
</Field>
|
|
|
|
<Field data-invalid={Boolean(form.formState.errors.physicalAddress)}>
|
|
<FieldLabel htmlFor="physical-address">Direccion fisica</FieldLabel>
|
|
<Input
|
|
id="physical-address"
|
|
type="text"
|
|
placeholder="Ej: Av. San Martin 1234, Salta"
|
|
aria-invalid={Boolean(form.formState.errors.physicalAddress)}
|
|
{...form.register('physicalAddress')}
|
|
/>
|
|
<FieldError errors={[form.formState.errors.physicalAddress]} />
|
|
</Field>
|
|
|
|
<Field data-invalid={Boolean(form.formState.errors.planCode)}>
|
|
<FieldLabel htmlFor="plan-code">Plan</FieldLabel>
|
|
<Controller
|
|
control={form.control}
|
|
name="planCode"
|
|
render={({ field }) => (
|
|
<select
|
|
id="plan-code"
|
|
className="h-10 w-full rounded-md border bg-background px-3 text-sm"
|
|
aria-invalid={Boolean(form.formState.errors.planCode)}
|
|
value={field.value ?? ''}
|
|
onChange={(event) => {
|
|
field.onChange(event.target.value);
|
|
}}
|
|
disabled={plans.length === 0}
|
|
>
|
|
<option value="">
|
|
{plans.length > 0 ? planPlaceholder : 'No hay planes disponibles'}
|
|
</option>
|
|
{plans.map((plan) => (
|
|
<option key={plan.code} value={plan.code}>
|
|
{plan.name} - ${plan.price.toFixed(2)}
|
|
</option>
|
|
))}
|
|
</select>
|
|
)}
|
|
/>
|
|
{plans.length === 0 && (
|
|
<p className="text-xs text-muted-foreground">
|
|
Carga planes en la base para continuar con el onboarding.
|
|
</p>
|
|
)}
|
|
<FieldError errors={[form.formState.errors.planCode]} />
|
|
</Field>
|
|
|
|
{errorMessage && <p className="text-sm text-destructive">{errorMessage}</p>}
|
|
{infoMessage && <p className="text-sm text-muted-foreground">{infoMessage}</p>}
|
|
|
|
<Button
|
|
type="submit"
|
|
className="w-full"
|
|
disabled={form.formState.isSubmitting || !form.formState.isValid}
|
|
>
|
|
{form.formState.isSubmitting ? 'Finalizando...' : 'Completar onboarding'}
|
|
</Button>
|
|
</form>
|
|
);
|
|
}
|