2025-12-21 16:55:12 +01:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import {useMutation} from "@tanstack/react-query";
|
|
|
|
|
import {toast} from "sonner";
|
|
|
|
|
|
|
|
|
|
import {FormControl, FormField, FormItem, FormLabel, useZodForm} from "@/components/ui/form";
|
|
|
|
|
import {Form} from "@/components/ui/form";
|
2026-05-24 17:09:12 +02:00
|
|
|
import {ButtonWithLoading} from "@/components/common/button-with-loading";
|
2025-12-21 16:55:12 +01:00
|
|
|
import Link from "next/link";
|
|
|
|
|
import {ResetPasswordSchema, ResetPasswordType} from "./reset-password-form.schema";
|
|
|
|
|
import {PasswordStrengthInput} from "@/components/ui/password-input-indicator";
|
|
|
|
|
import {useRouter, useSearchParams} from "next/navigation";
|
|
|
|
|
import {ArrowLeft} from "lucide-react";
|
|
|
|
|
import {authClient} from "@/lib/auth/auth-client";
|
|
|
|
|
import {BetterAuthError} from "@/types/auth";
|
|
|
|
|
import {PasswordInput} from "@/components/ui/password-input";
|
|
|
|
|
|
|
|
|
|
export type ResetPasswordFormProps = {
|
|
|
|
|
defaultValues?: ResetPasswordType;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const ResetPasswordForm = (props: ResetPasswordFormProps) => {
|
|
|
|
|
const searchParams = useSearchParams();
|
|
|
|
|
|
|
|
|
|
const form = useZodForm({
|
|
|
|
|
schema: ResetPasswordSchema,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const router = useRouter();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const mutation = useMutation({
|
|
|
|
|
mutationFn: async (values: ResetPasswordType) => {
|
|
|
|
|
|
|
|
|
|
const {data, error} = await authClient.resetPassword({
|
|
|
|
|
newPassword: values.password,
|
|
|
|
|
token: searchParams.get("token") || "",
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (error) throw error;
|
|
|
|
|
},
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
toast.success("Password successfully reset!");
|
|
|
|
|
setTimeout(() => router.push("/"), 1400);
|
|
|
|
|
},
|
|
|
|
|
onError: (error: BetterAuthError) => {
|
|
|
|
|
toast.error("An error occurred while resetting password");
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Form
|
|
|
|
|
form={form}
|
|
|
|
|
className="flex flex-col gap-4 mb-1"
|
|
|
|
|
onSubmit={async (values) => {
|
|
|
|
|
await mutation.mutateAsync(values);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="password"
|
|
|
|
|
defaultValue=""
|
|
|
|
|
render={({field}) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<PasswordStrengthInput label={"New password"} field={field}/>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
<FormField
|
|
|
|
|
control={form.control}
|
|
|
|
|
name="confirmPassword"
|
|
|
|
|
defaultValue=""
|
|
|
|
|
render={({field}) => (
|
|
|
|
|
<FormItem>
|
|
|
|
|
<FormLabel>Confirmation password</FormLabel>
|
|
|
|
|
<FormControl>
|
|
|
|
|
<PasswordInput placeholder={"Enter your conformation password"} {...field} />
|
|
|
|
|
</FormControl>
|
|
|
|
|
</FormItem>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-col items-center gap-y-6 w-full">
|
2026-02-12 15:48:51 +01:00
|
|
|
<ButtonWithLoading className="mt-2 w-full h-11" isPending={mutation.isPending}>
|
2025-12-21 16:55:12 +01:00
|
|
|
Reset
|
|
|
|
|
</ButtonWithLoading>
|
|
|
|
|
<Link href="/login" className="group flex items-center text-sm hover:underline">
|
|
|
|
|
<ArrowLeft
|
|
|
|
|
className="mr-1 size-4 text-muted-foreground transition-transform group-hover:-translate-x-1"/>
|
|
|
|
|
Back to login
|
|
|
|
|
</Link>
|
|
|
|
|
</div>
|
|
|
|
|
</Form>
|
|
|
|
|
);
|
|
|
|
|
};
|