@@ -5,9 +5,12 @@ import Link from "next/link";
55import { useRouter } from "next/navigation" ;
66import { useEffect , useState } from "react" ;
77import { toast } from "sonner" ;
8+ import { useTranslations } from "next-intl" ;
89import { getAuthErrorDetails , isNetworkError , shouldRetry } from "@/lib/auth-errors" ;
910
1011export function LocalLoginForm ( ) {
12+ const t = useTranslations ( 'auth' ) ;
13+ const tCommon = useTranslations ( 'common' ) ;
1114 const [ username , setUsername ] = useState ( "" ) ;
1215 const [ password , setPassword ] = useState ( "" ) ;
1316 const [ showPassword , setShowPassword ] = useState ( false ) ;
@@ -29,7 +32,7 @@ export function LocalLoginForm() {
2932 setErrorTitle ( null ) ;
3033
3134 // Show loading toast
32- const loadingToast = toast . loading ( "Signing you in..." ) ;
35+ const loadingToast = toast . loading ( tCommon ( 'loading' ) ) ;
3336
3437 try {
3538 // Create form data for the API request
@@ -56,7 +59,7 @@ export function LocalLoginForm() {
5659 }
5760
5861 // Success toast
59- toast . success ( "Login successful!" , {
62+ toast . success ( t ( 'login_success' ) , {
6063 id : loadingToast ,
6164 description : "Redirecting to dashboard..." ,
6265 duration : 2000 ,
@@ -167,84 +170,84 @@ export function LocalLoginForm() {
167170 </ div >
168171 </ motion . div >
169172 ) }
170- </ AnimatePresence >
173+ </ AnimatePresence >
171174
172- < div >
173- < label
174- htmlFor = "email"
175- className = "block text-sm font-medium text-gray-700 dark:text-gray-300"
176- >
177- Email
178- </ label >
175+ < div >
176+ < label
177+ htmlFor = "email"
178+ className = "block text-sm font-medium text-gray-700 dark:text-gray-300"
179+ >
180+ { t ( 'email' ) }
181+ </ label >
182+ < input
183+ id = "email"
184+ type = "email"
185+ required
186+ value = { username }
187+ onChange = { ( e ) => setUsername ( e . target . value ) }
188+ className = { `mt-1 block w-full rounded-md border px-3 py-2 shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 dark:bg-gray-800 dark:text-white transition-colors ${
189+ error
190+ ? "border-red-300 focus:border-red-500 focus:ring-red-500 dark:border-red-700"
191+ : "border-gray-300 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700"
192+ } `}
193+ disabled = { isLoading }
194+ />
195+ </ div >
196+
197+ < div >
198+ < label
199+ htmlFor = "password"
200+ className = "block text-sm font-medium text-gray-700 dark:text-gray-300"
201+ >
202+ { t ( 'password' ) }
203+ </ label >
204+ < div className = "relative" >
179205 < input
180- id = "email "
181- type = "email"
206+ id = "password "
207+ type = { showPassword ? "text" : "password" }
182208 required
183- value = { username }
184- onChange = { ( e ) => setUsername ( e . target . value ) }
185- className = { `mt-1 block w-full rounded-md border px-3 py-2 shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 dark:bg-gray-800 dark:text-white transition-colors ${
209+ value = { password }
210+ onChange = { ( e ) => setPassword ( e . target . value ) }
211+ className = { `mt-1 block w-full rounded-md border pr-10 px-3 py-2 shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 dark:bg-gray-800 dark:text-white transition-colors ${
186212 error
187213 ? "border-red-300 focus:border-red-500 focus:ring-red-500 dark:border-red-700"
188214 : "border-gray-300 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700"
189215 } `}
190216 disabled = { isLoading }
191217 />
192- </ div >
193-
194- < div >
195- < label
196- htmlFor = "password"
197- className = "block text-sm font-medium text-gray-700 dark:text-gray-300"
218+ < button
219+ type = "button"
220+ onClick = { ( ) => setShowPassword ( ( prev ) => ! prev ) }
221+ className = "absolute inset-y-0 right-0 flex items-center pr-3 mt-1 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
222+ aria-label = { showPassword ? t ( 'hide_password' ) : t ( 'show_password' ) }
198223 >
199- Password
200- </ label >
201- < div className = "relative" >
202- < input
203- id = "password"
204- type = { showPassword ? "text" : "password" }
205- required
206- value = { password }
207- onChange = { ( e ) => setPassword ( e . target . value ) }
208- className = { `mt-1 block w-full rounded-md border pr-10 px-3 py-2 shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 dark:bg-gray-800 dark:text-white transition-colors ${
209- error
210- ? "border-red-300 focus:border-red-500 focus:ring-red-500 dark:border-red-700"
211- : "border-gray-300 focus:border-blue-500 focus:ring-blue-500 dark:border-gray-700"
212- } `}
213- disabled = { isLoading }
214- />
215- < button
216- type = "button"
217- onClick = { ( ) => setShowPassword ( ( prev ) => ! prev ) }
218- className = "absolute inset-y-0 right-0 flex items-center pr-3 mt-1 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
219- aria-label = { showPassword ? "Hide password" : "Show password" }
220- >
221- { showPassword ? < EyeOff className = "h-4 w-4" /> : < Eye className = "h-4 w-4" /> }
222- </ button >
223- </ div >
224+ { showPassword ? < EyeOff className = "h-4 w-4" /> : < Eye className = "h-4 w-4" /> }
225+ </ button >
224226 </ div >
225-
226- < button
227- type = "submit"
228- disabled = { isLoading }
229- className = "w-full rounded-md bg-blue-600 px-4 py-2 text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors"
230- >
231- { isLoading ? "Signing in..." : "Sign in" }
232- </ button >
233- </ form >
234-
235- { authType === "LOCAL" && (
236- < div className = "mt-4 text-center text-sm" >
237- < p className = "text-gray-600 dark:text-gray-400" >
238- Don't have an account?{ " " }
239- < Link
240- href = "/register"
241- className = "font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400"
242- >
243- Register here
244- </ Link >
245- </ p >
246- </ div >
247- ) }
227+ </ div >
228+
229+ < button
230+ type = "submit"
231+ disabled = { isLoading }
232+ className = "w-full rounded-md bg-blue-600 px-4 py-2 text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors"
233+ >
234+ { isLoading ? tCommon ( 'loading' ) : t ( 'sign_in' ) }
235+ </ button >
236+ </ form >
237+
238+ { authType === "LOCAL" && (
239+ < div className = "mt-4 text-center text-sm" >
240+ < p className = "text-gray-600 dark:text-gray-400" >
241+ { t ( 'dont_have_account' ) } { " " }
242+ < Link
243+ href = "/register"
244+ className = "font-medium text-blue-600 hover:text-blue-500 dark:text-blue-400"
245+ >
246+ { t ( 'sign_up' ) }
247+ </ Link >
248+ </ p >
249+ </ div >
250+ ) }
248251 </ div >
249252 ) ;
250253}
0 commit comments