1"use client";
2
3import { useState } from "react";
4import { useRouter } from "next/navigation";
5import Link from "next/link";
6import { authApi } from "@/lib/api";
7import { toast } from "@/stores/ui-store";
8import { Field, FormError, Input, SubmitButton } from "@/components/ui/form";
9
10type Step = "request" | "confirm" | "done";
11
12export default function ResetPasswordPage() {
13 const router = useRouter();
14 const [step, setStep] = useState<Step>("request");
15 const [email, setEmail] = useState("");
16 const [code, setCode] = useState("");
17 const [password, setPassword] = useState("");
18 const [password2, setPassword2] = useState("");
19 const [error, setError] = useState<string | null>(null);
20 const [busy, setBusy] = useState(false);
21
22 const requestCode = async () => {
23 setError(null);
24 if (!email.trim()) {
25 setError("Enter the email you registered with.");
26 return;
27 }
28 setBusy(true);
29 try {
30
31 await authApi.resetRequest(email.trim());
32 setStep("confirm");
33 } catch (err) {
34 setError(err instanceof Error ? err.message : "Could not send the reset code.");
35 } finally {
36 setBusy(false);
37 }
38 };
39
40 const confirmReset = async () => {
41 setError(null);
42 if (!code.trim()) return setError("Enter the 6-digit code from the email.");
43 if (password.length < 10) return setError("Password must be at least 10 characters.");
44 if (password !== password2) return setError("Passwords do not match.");
45 setBusy(true);
46 try {
47 await authApi.resetConfirm(email.trim(), code.trim(), password);
48 toast("success", "Password updated", "Sign in with your new password.");
49 setStep("done");
50 } catch (err) {
51 setError(err instanceof Error ? err.message : "Reset failed. Check the code and try again.");
52 } finally {
53 setBusy(false);
54 }
55 };
56
57 return (
58 <div className="space-y-5">
59 <div>
60 <h1 className="text-xl font-semibold">Reset password</h1>
61 <p className="mt-1 text-sm text-muted-foreground">
62 {step === "request" && "We'll email you a one-time code."}
63 {step === "confirm" && `Enter the code sent to ${email || "your email"} and choose a new password.`}
64 {step === "done" && "Your password has been reset."}
65 </p>
66 </div>
67
68 <FormError message={error} />
69
70 {step === "request" && (
71 <form
72 className="space-y-4"
73 noValidate
74 onSubmit={(e) => {
75 e.preventDefault();
76 void requestCode();
77 }}
78 >
79 <Field label="Email" htmlFor="reset-email">
80 <Input
81 id="reset-email"
82 type="email"
83 autoComplete="email"
84 placeholder="you@company.com"
85 value={email}
86 onChange={(e) => setEmail(e.target.value)}
87 />
88 </Field>
89 <SubmitButton busy={busy}>Send reset code</SubmitButton>
90 </form>
91 )}
92
93 {step === "confirm" && (
94 <form
95 className="space-y-4"
96 noValidate
97 onSubmit={(e) => {
98 e.preventDefault();
99 void confirmReset();
100 }}
101 >
102 <Field label="Code" htmlFor="reset-code">
103 <Input
104 id="reset-code"
105 inputMode="numeric"
106 autoComplete="one-time-code"
107 placeholder="123456"
108 value={code}
109 onChange={(e) => setCode(e.target.value)}
110 />
111 </Field>
112 <Field label="New password" htmlFor="reset-password" hint="At least 10 characters.">
113 <Input
114 id="reset-password"
115 type="password"
116 autoComplete="new-password"
117 value={password}
118 onChange={(e) => setPassword(e.target.value)}
119 />
120 </Field>
121 <Field label="Repeat password" htmlFor="reset-password2">
122 <Input
123 id="reset-password2"
124 type="password"
125 autoComplete="new-password"
126 value={password2}
127 onChange={(e) => setPassword2(e.target.value)}
128 />
129 </Field>
130 <SubmitButton busy={busy}>Reset password</SubmitButton>
131 <button
132 type="button"
133 onClick={() => {
134 setStep("request");
135 setError(null);
136 }}
137 className="w-full text-center text-xs text-muted-foreground hover:text-foreground"
138 >
139 Use a different email
140 </button>
141 </form>
142 )}
143
144 {step === "done" && (
145 <button
146 type="button"
147 onClick={() => router.replace("/login")}
148 className="h-9 w-full rounded-md bg-primary text-sm font-medium text-primary-foreground hover:opacity-90"
149 >
150 Back to sign in
151 </button>
152 )}
153
154 <p className="text-center text-sm">
155 <Link href="/login" className="text-muted-foreground hover:text-foreground">
156 Back to sign in
157 </Link>
158 </p>
159 </div>
160 );
161}
162