"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { useState } from "react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from "@/components/ui/input-otp"; import { AxiosResponse } from "axios"; import { RequestPasswordResetBody, RequestPasswordResetResponse, resetPasswordBody, ResetPasswordBody, ResetPasswordResponse } from "@server/routers/auth"; import { Loader2 } from "lucide-react"; import { Alert, AlertDescription } from "../../../components/ui/alert"; import { useToast } from "@app/hooks/useToast"; import { useRouter } from "next/navigation"; import { formatAxiosError } from "@app/lib/utils"; import { createApiClient } from "@app/api"; import { useEnvContext } from "@app/hooks/useEnvContext"; import { passwordSchema } from "@server/auth/passwordSchema"; import { get } from "http"; const requestSchema = z.object({ email: z.string().email() }); const formSchema = z .object({ email: z.string().email({ message: "Invalid email address" }), token: z.string().min(8, { message: "Invalid token" }), password: passwordSchema, confirmPassword: passwordSchema }) .refine((data) => data.password === data.confirmPassword, { path: ["confirmPassword"], message: "Passwords do not match" }); const mfaSchema = z.object({ code: z.string().length(6, { message: "Invalid code" }) }); export type ResetPasswordFormProps = { emailParam?: string; tokenParam?: string; redirect?: string; }; export default function ResetPasswordForm({ emailParam, tokenParam, redirect }: ResetPasswordFormProps) { const router = useRouter(); const [error, setError] = useState(null); const [successMessage, setSuccessMessage] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); function getState() { if (emailParam && !tokenParam) { return "request"; } if (emailParam && tokenParam) { return "reset"; } return "request"; } const [state, setState] = useState<"request" | "reset" | "mfa">(getState()); const { toast } = useToast(); const api = createApiClient(useEnvContext()); const form = useForm>({ resolver: zodResolver(formSchema), defaultValues: { email: emailParam || "", token: tokenParam || "", password: "", confirmPassword: "" } }); const mfaForm = useForm>({ resolver: zodResolver(mfaSchema), defaultValues: { code: "" } }); const requestForm = useForm>({ resolver: zodResolver(requestSchema), defaultValues: { email: emailParam || "" } }); async function onRequest(data: z.infer) { const { email } = data; setIsSubmitting(true); const res = await api .post>( "/auth/reset-password/request", { email } as RequestPasswordResetBody ) .catch((e) => { setError(formatAxiosError(e, "An error occurred")); console.error("Failed to request reset:", e); setIsSubmitting(false); }); if (res && res.data?.data) { setError(null); setState("reset"); setIsSubmitting(false); form.setValue("email", email); } } async function onReset(data: any) { setIsSubmitting(true); const { password, email, token } = form.getValues(); const { code } = mfaForm.getValues(); const res = await api .post>( "/auth/reset-password", { email, token, newPassword: password, code } as ResetPasswordBody ) .catch((e) => { setError(formatAxiosError(e, "An error occurred")); console.error("Failed to reset password:", e); setIsSubmitting(false); }); console.log(res); if (res) { setError(null); if (res.data.data?.codeRequested) { setState("mfa"); setIsSubmitting(false); mfaForm.reset(); return; } setSuccessMessage("Password reset successfully! Back to login..."); setTimeout(() => { if (redirect && redirect.includes("http")) { window.location.href = redirect; } if (redirect) { router.push(redirect); } else { router.push("/login"); } setIsSubmitting(false); }, 1500); } } return (
Reset Password Follow the steps to reset your password
{state === "request" && (
( Email We'll send a password reset code to this email address. )} /> )} {state === "reset" && (
( Email )} /> {!tokenParam && ( ( Reset Code )} /> )} ( New Password )} /> ( Confirm New Password )} /> )} {state === "mfa" && (
( Authenticator Code
)} /> )} {error && ( {error} )} {successMessage && ( {successMessage} )}
{(state === "reset" || state === "mfa") && ( )} {state === "request" && ( )} {state === "mfa" && ( )} {(state === "mfa" || state === "reset") && ( )}
); }