// Copyright (c) 2026 Probo Inc . // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. import { formatError } from "@probo/helpers"; import { usePageTitle } from "@probo/hooks"; import { useTranslate } from "@probo/i18n"; import { Button, Field, useToast } from "@probo/ui"; import { useMutation } from "react-relay"; import { Link, useNavigate, useSearchParams } from "react-router"; import { graphql } from "relay-runtime"; import { z } from "zod"; import type { ResetPasswordPageMutation } from "#/__generated__/iam/ResetPasswordPageMutation.graphql"; import { useFormWithSchema } from "#/hooks/useFormWithSchema"; const resetPasswordMutation = graphql` mutation ResetPasswordPageMutation($input: ResetPasswordInput!) { resetPassword(input: $input) { success } } `; const schema = z .object({ password: z.string().min(8), confirmPassword: z.string().min(8), }) .refine(data => data.password === data.confirmPassword, { message: "Passwords don't match", path: ["confirmPassword"], }); export default function ResetPasswordPage() { const { __ } = useTranslate(); const { toast } = useToast(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const token = searchParams.get("token"); usePageTitle(__("Reset password")); const { register, handleSubmit, formState } = useFormWithSchema(schema, { defaultValues: { password: "", confirmPassword: "", }, }); const [resetPassword] = useMutation( resetPasswordMutation, ); const onSubmit = handleSubmit((data) => { if (!token) { toast({ title: __("Reset failed"), description: __("Invalid or missing reset token"), variant: "error", }); return; } resetPassword({ variables: { input: { password: data.password, token, }, }, onError: (e: Error) => { toast({ title: __("Reset failed"), description: e.message, variant: "error", }); }, onCompleted: (_, e) => { if (e) { toast({ title: __("Reset failed"), description: formatError( __("Password reset failed"), e, ), variant: "error", }); return; } toast({ title: __("Success"), description: __("Password reset successfully"), variant: "success", }); void navigate("/auth/login", { replace: true }); }, }); }); return (

{__("Reset password")}

{__("Enter your new password to reset your account")}

void onSubmit(e)} className="space-y-4">

{__("Remember your password?")} {" "} {__("Log in here")}

); }