import { useState } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import * as z from "zod/v4"; import Head from "next/head"; import { Button } from "@/src/components/ui/button"; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/src/components/ui/form"; import { Input } from "@/src/components/ui/input"; import { PasswordInput } from "@/src/components/ui/password-input"; import { LangfuseIcon } from "@/src/components/LangfuseLogo"; import { useSession } from "next-auth/react"; import { ArrowLeft, ShieldCheck } from "lucide-react"; import { api } from "@/src/utils/api"; import { useRouter } from "next/router"; import { RequestResetPasswordEmailButton } from "@/src/features/auth-credentials/components/ResetPasswordButton"; import { TRPCClientError } from "@trpc/client"; import { isEmailVerifiedWithinCutoff } from "@/src/features/auth-credentials/lib/credentialsUtils"; import Link from "next/link"; import { ErrorPage } from "@/src/components/error-page"; import { usePostHogClientCapture } from "@/src/features/posthog-analytics/usePostHogClientCapture"; import { passwordSchema } from "@/src/features/auth/lib/signupSchema"; const resetPasswordSchema = z .object({ email: z.string().email(), password: passwordSchema, confirmPassword: passwordSchema, }) .refine((data) => data.password === data.confirmPassword, { message: "Passwords do not match", path: ["confirmPassword"], }); export function ResetPasswordPage({ passwordResetAvailable, }: { passwordResetAvailable: boolean; }) { const session = useSession(); const router = useRouter(); const [formError, setFormError] = useState(null); const [isSuccess, setIsSuccess] = useState(false); const [showResetPasswordEmailButton, setShowResetPasswordEmailButton] = useState(false); const capture = usePostHogClientCapture(); const mutResetPassword = api.credentials.resetPassword.useMutation(); const emailVerified = isEmailVerifiedWithinCutoff( session.data?.user?.emailVerified, ); const form = useForm({ resolver: zodResolver(resetPasswordSchema), defaultValues: { email: session.data?.user?.email ?? "", password: "", confirmPassword: "", }, }); async function onSubmit(values: z.infer) { setFormError(null); setShowResetPasswordEmailButton(false); setIsSuccess(false); capture("auth:update_password_form_submit"); await mutResetPassword .mutateAsync({ password: values.password }) .then(() => { setIsSuccess(true); setTimeout(() => { router.push("/"); setIsSuccess(false); }, 2000); }) .catch((error) => { console.log(error.message); if (error instanceof TRPCClientError) { if (error.data?.code === "UNAUTHORIZED") { setShowResetPasswordEmailButton(true); } setFormError(error.message); } else { console.error(error); setFormError("An unknown error occurred"); } }); } if (!passwordResetAvailable) return ( ); return ( <> Reset Password | Langfuse

Reset your password

{session.status !== "authenticated" && (
)}
( Email
{emailVerified.verified && ( )}
)} /> {emailVerified.verified && ( <> ( New Password )} /> ( Confirm New Password )} /> )}
{emailVerified.verified ? ( ) : ( )}
{formError ? (
{formError}
) : null} {isSuccess && (
Password successfully updated. Redirecting ...
)} {showResetPasswordEmailButton && ( )}
{session.status !== "authenticated" && (
You will only receive an email if an account with this email exists and you have signed up with email and password. If you used an authentication provider like Google, Gitlab, Okta, or GitHub, please{" "} sign in .
)}
); }