88
99import React , { useState } from 'react' ;
1010import { useAuth } from './useAuth' ;
11+ import type { AuthLinkComponentProps } from './types' ;
12+
13+ /** Translatable labels for the ForgotPasswordForm */
14+ export interface ForgotPasswordFormLabels {
15+ emailLabel ?: string ;
16+ emailPlaceholder ?: string ;
17+ submitButton ?: string ;
18+ submittingButton ?: string ;
19+ successTitle ?: string ;
20+ successDescription ?: string ;
21+ backToSignInText ?: string ;
22+ rememberPasswordText ?: string ;
23+ signInText ?: string ;
24+ }
1125
1226export interface ForgotPasswordFormProps {
1327 /** Callback on successful submission */
@@ -20,8 +34,16 @@ export interface ForgotPasswordFormProps {
2034 title ?: string ;
2135 /** Custom description */
2236 description ?: string ;
37+ /** Custom link component for SPA navigation (e.g. React Router's Link) */
38+ linkComponent ?: React . ComponentType < AuthLinkComponentProps > ;
39+ /** Override default labels for i18n */
40+ labels ?: ForgotPasswordFormLabels ;
2341}
2442
43+ const DefaultLink = ( { href, className, children } : AuthLinkComponentProps ) => (
44+ < a href = { href } className = { className } > { children } </ a >
45+ ) ;
46+
2547/**
2648 * Forgot password form component.
2749 * Sends a password reset email to the user.
@@ -40,12 +62,26 @@ export function ForgotPasswordForm({
4062 loginUrl = '/login' ,
4163 title = 'Reset your password' ,
4264 description = 'Enter your email address and we\'ll send you a link to reset your password' ,
65+ linkComponent : LinkComp = DefaultLink ,
66+ labels = { } ,
4367} : ForgotPasswordFormProps ) {
4468 const { forgotPassword, isLoading } = useAuth ( ) ;
4569 const [ email , setEmail ] = useState ( '' ) ;
4670 const [ error , setError ] = useState < string | null > ( null ) ;
4771 const [ submitted , setSubmitted ] = useState ( false ) ;
4872
73+ const l = {
74+ emailLabel : labels . emailLabel ?? 'Email' ,
75+ emailPlaceholder : labels . emailPlaceholder ?? 'name@example.com' ,
76+ submitButton : labels . submitButton ?? 'Send Reset Link' ,
77+ submittingButton : labels . submittingButton ?? 'Sending...' ,
78+ successTitle : labels . successTitle ?? 'Check your email' ,
79+ successDescription : labels . successDescription ?? `We've sent a password reset link to` ,
80+ backToSignInText : labels . backToSignInText ?? 'Back to sign in' ,
81+ rememberPasswordText : labels . rememberPasswordText ?? 'Remember your password?' ,
82+ signInText : labels . signInText ?? 'Sign in' ,
83+ } ;
84+
4985 const handleSubmit = async ( e : React . FormEvent ) => {
5086 e . preventDefault ( ) ;
5187 setError ( null ) ;
@@ -63,27 +99,26 @@ export function ForgotPasswordForm({
6399
64100 if ( submitted ) {
65101 return (
66- < div className = "mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px ]" >
102+ < div className = "mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[380px ]" >
67103 < div className = "flex flex-col space-y-2 text-center" >
68- < h1 className = "text-2xl font-semibold tracking-tight" > Check your email </ h1 >
104+ < h1 className = "text-2xl font-semibold tracking-tight" > { l . successTitle } </ h1 >
69105 < p className = "text-sm text-muted-foreground" >
70- We've sent a password reset link to < strong > { email } </ strong > .
71- Please check your inbox and follow the instructions.
106+ { l . successDescription } < strong > { email } </ strong > .
72107 </ p >
73108 </ div >
74109 { loginUrl && (
75110 < p className = "px-8 text-center text-sm text-muted-foreground" >
76- < a href = { loginUrl } className = "text-primary underline-offset-4 hover:underline" >
77- Back to sign in
78- </ a >
111+ < LinkComp href = { loginUrl } className = "text-primary underline-offset-4 hover:underline" >
112+ { l . backToSignInText }
113+ </ LinkComp >
79114 </ p >
80115 ) }
81116 </ div >
82117 ) ;
83118 }
84119
85120 return (
86- < div className = "mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[350px ]" >
121+ < div className = "mx-auto flex w-full flex-col justify-center space-y-6 sm:w-[380px ]" >
87122 < div className = "flex flex-col space-y-2 text-center" >
88123 < h1 className = "text-2xl font-semibold tracking-tight" > { title } </ h1 >
89124 < p className = "text-sm text-muted-foreground" > { description } </ p >
@@ -98,12 +133,12 @@ export function ForgotPasswordForm({
98133
99134 < div className = "space-y-2" >
100135 < label htmlFor = "forgot-email" className = "text-sm font-medium leading-none" >
101- Email
136+ { l . emailLabel }
102137 </ label >
103138 < input
104139 id = "forgot-email"
105140 type = "email"
106- placeholder = "name@example.com"
141+ placeholder = { l . emailPlaceholder }
107142 value = { email }
108143 onChange = { ( e ) => setEmail ( e . target . value ) }
109144 required
@@ -118,16 +153,16 @@ export function ForgotPasswordForm({
118153 disabled = { isLoading }
119154 className = "inline-flex h-10 w-full items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground ring-offset-background transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50"
120155 >
121- { isLoading ? 'Sending...' : 'Send Reset Link' }
156+ { isLoading ? l . submittingButton : l . submitButton }
122157 </ button >
123158 </ form >
124159
125160 { loginUrl && (
126161 < p className = "px-8 text-center text-sm text-muted-foreground" >
127- Remember your password? { ' ' }
128- < a href = { loginUrl } className = "text-primary underline-offset-4 hover:underline" >
129- Sign in
130- </ a >
162+ { l . rememberPasswordText } { ' ' }
163+ < LinkComp href = { loginUrl } className = "text-primary underline-offset-4 hover:underline" >
164+ { l . signInText }
165+ </ LinkComp >
131166 </ p >
132167 ) }
133168 </ div >
0 commit comments