Files
playzer/apps/frontend/src/features/onboard/components/onboarding-verify-otp-step.tsx
Jose Selesan f1a7e6c24a feat: enhance public booking page with improved layout and date formatting
- Added new date formatting function for better user experience.
- Updated layout of the public booking page for improved responsiveness and aesthetics.
- Integrated sport selection with visual icons for better clarity.
- Enhanced error handling and loading states for availability queries.

feat: revamp select complex page for better user interaction

- Redesigned the select complex page layout for a more modern look.
- Added contextual information about complex selection.
- Improved button interactions with loading indicators and icons.

style: update CSS variables for a cohesive sports-club theme

- Adjusted color variables to reflect a sports-club identity.
- Enhanced background styles for both light and dark modes.
- Improved overall styling consistency across components.
2026-04-24 14:47:39 -03:00

109 lines
3.3 KiB
TypeScript

import { Button } from '@/components/ui/button';
import { Field, FieldError, FieldLabel } from '@/components/ui/field';
import {
InputOTP,
InputOTPGroup,
InputOTPSeparator,
InputOTPSlot,
} from '@/components/ui/input-otp';
import type { VerifyOtpValues } from '@/features/onboard/onboarding.types';
import { RefreshCw } from 'lucide-react';
import type { UseFormReturn } from 'react-hook-form';
type OnboardingVerifyOtpStepProps = {
form: UseFormReturn<VerifyOtpValues>;
email: string | null;
errorMessage: string | null;
infoMessage: string | null;
remainingAttempts: number;
resendCooldownSeconds: number;
isResending: boolean;
onSubmit: (values: VerifyOtpValues) => Promise<void>;
onResend: () => Promise<void>;
};
export function OnboardingVerifyOtpStep({
form,
email,
errorMessage,
infoMessage,
remainingAttempts,
resendCooldownSeconds,
isResending,
onSubmit,
onResend,
}: OnboardingVerifyOtpStepProps) {
const resendDisabled = resendCooldownSeconds > 0 || isResending;
return (
<form className="space-y-4" onSubmit={form.handleSubmit(onSubmit)}>
<p className="text-sm text-muted-foreground">
Ingresa el código de 6 dígitos que enviamos a{' '}
<span className="font-medium text-foreground">{email ?? 'tu email'}</span>.
</p>
<Field data-invalid={Boolean(form.formState.errors.otp)}>
<div className="mb-2 flex items-center justify-between gap-3">
<FieldLabel htmlFor="onboard-otp">Código de verificación</FieldLabel>
<Button
type="button"
variant="outline"
size="sm"
disabled={resendDisabled}
onClick={() => {
void onResend();
}}
>
<RefreshCw className="mr-1 h-3.5 w-3.5" />
{isResending
? 'Reenviando...'
: resendCooldownSeconds > 0
? `Reenviar en ${resendCooldownSeconds}s`
: 'Reenviar código'}
</Button>
</div>
<InputOTP
id="onboard-otp"
maxLength={6}
inputMode="numeric"
pattern="\d*"
value={form.watch('otp')}
onChange={(value) => {
form.setValue('otp', value, { shouldValidate: true });
}}
>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
<FieldError errors={[form.formState.errors.otp]} />
</Field>
<p className="text-xs text-muted-foreground">
Intentos restantes: <span className="font-medium">{remainingAttempts}</span>
</p>
{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 ? 'Verificando...' : 'Verificar código'}
</Button>
</form>
);
}