'use client'; import { useState, useTransition } from 'react'; import { zodResolver } from '@hookform/resolvers/zod'; import { ExclamationTriangleIcon } from '@radix-ui/react-icons'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; import { Button } from '@kit/ui/button'; import { Form, FormControl, FormDescription, FormField, FormItem, FormMessage, } from '@kit/ui/form'; import { If } from '@kit/ui/if'; import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, } from '@kit/ui/input-otp'; import { Spinner } from '@kit/ui/spinner'; import { Trans } from '@kit/ui/trans'; import { sendOtpEmailAction } from '../server/server-actions'; // Email form schema const SendOtpSchema = z.object({ email: z.string().email({ message: 'Please enter a valid email address' }), }); // OTP verification schema const VerifyOtpSchema = z.object({ otp: z.string().min(6, { message: 'Please enter a valid OTP code' }).max(6), }); type VerifyOtpFormProps = { // Purpose of the OTP (e.g., 'email-verification', 'password-reset') purpose: string; // Callback when OTP is successfully verified onSuccess: (otp: string) => void; // Email address to send the OTP to email: string; // Customize form appearance className?: string; // Optional cancel button CancelButton?: React.ReactNode; }; export function VerifyOtpForm({ purpose, email, className, CancelButton, onSuccess, }: VerifyOtpFormProps) { // Track the current step (email entry or OTP verification) const [step, setStep] = useState<'email' | 'otp'>('email'); const [isPending, startTransition] = useTransition(); // Track errors const [error, setError] = useState(null); // Track verification success const [, setVerificationSuccess] = useState(false); // Email form const emailForm = useForm>({ resolver: zodResolver(SendOtpSchema), defaultValues: { email, }, }); // OTP verification form const otpForm = useForm>({ resolver: zodResolver(VerifyOtpSchema), defaultValues: { otp: '', }, }); // Handle sending OTP email const handleSendOtp = () => { setError(null); startTransition(async () => { try { const result = await sendOtpEmailAction({ purpose, email, }); if (result.success) { setStep('otp'); } else { setError(result.error || 'Failed to send OTP. Please try again.'); } } catch (err) { setError('An unexpected error occurred. Please try again.'); console.error('Error sending OTP:', err); } }); }; // Handle OTP verification const handleVerifyOtp = (data: z.infer) => { setVerificationSuccess(true); onSuccess(data.otp); }; return (
{step === 'email' ? (

{error}
{CancelButton}
) : (
{error} ( )} />
{CancelButton}
)}
); }