TypeScript 97.5%
SQL 1.4%
Python 0.8%
1"use client";2import * as React from "react";3import Link from "next/link";4import { useRouter, useSearchParams } from "next/navigation";5import { authClient } from "@/lib/auth-client";6import { AuthCard } from "@/components/auth/auth-card";7import { PasswordInput, PasswordRequirements, passwordStrong } from "@/components/auth/password-input";8import { Button } from "@/components/ui/button";9import { Field, FieldError, Label } from "@/components/ui/label";10import { Alert } from "@/components/ui/alert";1112function ResetForm() {13 const router = useRouter();14 const params = useSearchParams();15 const token = params.get("token");16 const invalid = params.get("error") === "INVALID_TOKEN" || !token;17 const [password, setPassword] = React.useState("");18 const [confirm, setConfirm] = React.useState("");19 const [error, setError] = React.useState<string | null>(null);20 const [loading, setLoading] = React.useState(false);2122 async function onSubmit(e: React.FormEvent) {23 e.preventDefault();24 if (!passwordStrong(password)) return setError("Choose a stronger password.");25 if (password !== confirm) return setError("Passwords do not match.");26 setLoading(true);27 const { error } = await authClient.resetPassword({ newPassword: password, token: token! });28 setLoading(false);29 if (error) return setError(error.message ?? "This link is invalid or expired.");30 router.push("/login?reset=1");31 }3233 if (invalid) {34 return (35 <AuthCard title="Link expired" description="This password reset link is invalid or has expired." footer={<Link href="/forgot-password" className="font-medium text-fg underline-offset-4 hover:underline">Request a new link</Link>}>36 <Alert variant="warning">Reset links are valid for one hour and can only be used once.</Alert>37 </AuthCard>38 );39 }4041 return (42 <AuthCard title="Choose a new password" description="All existing sessions will be signed out.">43 <form onSubmit={onSubmit} className="grid gap-4" noValidate>44 {error ? <Alert variant="danger">{error}</Alert> : null}45 <Field>46 <Label htmlFor="password">New password</Label>47 <PasswordInput id="password" autoComplete="new-password" required value={password} onChange={(e) => setPassword(e.target.value)} autoFocus />48 <PasswordRequirements password={password} />49 </Field>50 <Field>51 <Label htmlFor="confirm">Confirm password</Label>52 <PasswordInput id="confirm" autoComplete="new-password" required value={confirm} onChange={(e) => setConfirm(e.target.value)} />53 <FieldError>{confirm && confirm !== password ? "Passwords do not match." : null}</FieldError>54 </Field>55 <Button type="submit" size="lg" loading={loading} className="w-full">Update password</Button>56 </form>57 </AuthCard>58 );59}6061export default function ResetPasswordPage() {62 return (63 <React.Suspense fallback={null}>64 <ResetForm />65 </React.Suspense>66 );67}68