11import { zodResolver } from '@hookform/resolvers/zod' ;
2+ import { Link } from 'expo-router' ;
23import type { SubmitHandler } from 'react-hook-form' ;
34import { useForm } from 'react-hook-form' ;
45import { KeyboardAvoidingView } from 'react-native-keyboard-controller' ;
56import z from 'zod' ;
67
8+ import { translate } from '@/core' ;
79import { Button , ControlledInput , Text , View } from '@/ui' ;
810
911const MIN_CHARS = 6 ;
1012const schema = z . object ( {
1113 email : z
12- . string ( { required_error : 'Email is required' } )
13- . email ( 'Invalid email format' ) ,
14+ . string ( {
15+ required_error : translate ( 'auth.signIn.validation.emailRequired' ) ,
16+ } )
17+ . email ( translate ( 'auth.signIn.validation.invalidEmail' ) ) ,
1418 password : z
1519 . string ( {
16- required_error : 'Password is required' ,
20+ required_error : translate ( 'auth.signIn.validation.passwordRequired' ) ,
1721 } )
18- . min ( MIN_CHARS , 'Password must be at least 6 characters' ) ,
22+ . min ( MIN_CHARS , translate ( 'auth.signIn.validation.passwordMinChars' ) ) ,
1923} ) ;
2024
2125export type FormType = z . infer < typeof schema > ;
2226
2327export type LoginFormProps = {
28+ isLoading ?: boolean ;
2429 onSubmit ?: SubmitHandler < FormType > ;
2530} ;
2631
27- export const LoginForm = ( { onSubmit = ( ) => { } } : LoginFormProps ) => {
32+ export const LoginForm = ( {
33+ onSubmit = ( ) => { } ,
34+ isLoading = false ,
35+ } : LoginFormProps ) => {
2836 const { handleSubmit, control } = useForm < FormType > ( {
2937 resolver : zodResolver ( schema ) ,
3038 } ) ;
@@ -34,32 +42,50 @@ export const LoginForm = ({ onSubmit = () => {} }: LoginFormProps) => {
3442 behavior = "padding"
3543 keyboardVerticalOffset = { 10 }
3644 >
37- < View className = "flex-1 justify-center p-4" >
38- < Text testID = "form-title" className = "pb-6 text-center text-2xl" >
39- Sign In
45+ < View className = "flex-1 justify-center gap-8 p-4" >
46+ < Text testID = "form-title" className = "text-center text-2xl" >
47+ { translate ( 'auth.signIn.title' ) }
4048 </ Text >
49+ < View >
50+ < ControlledInput
51+ testID = "email-input"
52+ autoCapitalize = "none"
53+ autoComplete = "email"
54+ control = { control }
55+ name = "email"
56+ label = { translate ( 'auth.signIn.fields.email' ) }
57+ />
58+ < ControlledInput
59+ testID = "password-input"
60+ control = { control }
61+ name = "password"
62+ label = { translate ( 'auth.signIn.fields.password' ) }
63+ placeholder = "***"
64+ secureTextEntry = { true }
65+ />
4166
42- < ControlledInput
43- testID = "email-input"
44- autoCapitalize = "none"
45- autoComplete = "email"
46- control = { control }
47- name = "email"
48- label = "Email"
49- />
50- < ControlledInput
51- testID = "password-input"
52- control = { control }
53- name = "password"
54- label = "Password"
55- placeholder = "***"
56- secureTextEntry = { true }
57- />
58- < Button
59- testID = "login-button"
60- label = "Login"
61- onPress = { handleSubmit ( onSubmit ) }
62- />
67+ < Button
68+ testID = "login-button"
69+ label = { translate ( 'auth.signIn.buttons.login' ) }
70+ onPress = { handleSubmit ( onSubmit ) }
71+ loading = { isLoading }
72+ />
73+ < Text >
74+ { translate ( 'auth.signIn.newAccount' ) } { ' ' }
75+ < Link href = "/sign-up" disabled = { isLoading } >
76+ < Text className = "font-bold text-black" >
77+ { translate ( 'auth.signIn.buttons.signUp' ) }
78+ </ Text >
79+ </ Link >
80+ </ Text >
81+ < Link href = "/forgot-password" disabled = { isLoading } asChild >
82+ < Button
83+ variant = "link"
84+ className = "font-bold text-black"
85+ label = { translate ( 'auth.signIn.forgotPasswordButton' ) }
86+ />
87+ </ Link >
88+ </ View >
6389 </ View >
6490 </ KeyboardAvoidingView >
6591 ) ;
0 commit comments