11import React , { useState } from "react" ;
2- import { Eye , EyeOff , Mail } from "lucide-react" ;
3- import InputField from "./shared/InputField" ;
4- import { useNavigate } from 'react-router-dom' ; // <-- Import useNavigate
2+ import { FaEye , FaEyeSlash } from "react-icons/fa" ;
3+ import { Mail } from "lucide-react" ;
4+ import { useNavigate } from 'react-router-dom' ;
5+ import "../../styles/auth.css" ;
6+
7+ const isStrongPassword = ( password ) => {
8+ // At least one lowercase, uppercase, digit, symbol, min 8 char
9+ const regex = / ^ (? = .* [ a - z ] ) (? = .* [ A - Z ] ) (? = .* \d ) (? = .* [ ^ \w \s ] ) .{ 8 , } $ / ;
10+ return regex . test ( password ) ;
11+ } ;
512
6- // Remove onSwitchToSignUp from props
713const SignIn = ( { onAuthSuccess } ) => {
814 const [ formData , setFormData ] = useState ( { email : "" , password : "" } ) ;
915 const [ showPassword , setShowPassword ] = useState ( false ) ;
1016 const [ errors , setErrors ] = useState ( { } ) ;
1117 const [ isLoading , setIsLoading ] = useState ( false ) ;
12-
13- const navigate = useNavigate ( ) ; // <-- Initialize useNavigate
18+ const navigate = useNavigate ( ) ;
1419
1520 const handleInputChange = ( e ) => {
1621 const { name, value } = e . target ;
@@ -20,12 +25,19 @@ const SignIn = ({ onAuthSuccess }) => {
2025 }
2126 } ;
2227
28+ const validateEmail = ( email ) =>
29+ / ^ [ ^ \s @ ] + @ [ ^ \s @ ] + \. [ ^ \s @ ] + $ / . test ( email ) ;
30+
2331 const handleSubmit = async ( ) => {
2432 const newErrors = { } ;
2533 if ( ! formData . email ) newErrors . email = 'Email is required' ;
26- else if ( ! formData . email . includes ( '@' ) ) newErrors . email = 'Invalid email' ;
34+ else if ( ! validateEmail ( formData . email ) ) newErrors . email = 'Invalid email' ;
2735
2836 if ( ! formData . password ) newErrors . password = 'Password is required' ;
37+ else if ( ! isStrongPassword ( formData . password ) ) {
38+ newErrors . password =
39+ 'Password must be at least 8 characters, include uppercase, lowercase, number, and symbol.' ;
40+ }
2941
3042 setErrors ( newErrors ) ;
3143
@@ -34,100 +46,103 @@ const SignIn = ({ onAuthSuccess }) => {
3446 setTimeout ( ( ) => {
3547 setIsLoading ( false ) ;
3648 alert ( 'Sign in successful!' ) ;
37- onAuthSuccess ( ) ;
38- // The App.js's handleAuthSuccess now calls navigate('/')
39- // So you don't need navigate here unless you want to override it.
40- // For clarity, keep the navigation in App.js.
49+ onAuthSuccess && onAuthSuccess ( ) ;
4150 } , 1500 ) ;
4251 }
4352 } ;
4453
4554 return (
46- < div className = "auth-wrapper min-h-screen bg-white flex items-center justify-center p-4 " >
47- < div className = "auth-card bg-white rounded-xl shadow-2xl p-8 max-w-md w-full " >
55+ < div className = "auth-wrapper" >
56+ < div className = "auth-card" >
4857 < div className = "text-center mb-8" >
49- < h1 className = "text-3xl font-bold text-gray-900 mb-2" >
50- Welcome Back
51- </ h1 >
52- < p className = "text-gray-600" > Sign in to your account</ p >
58+ < h1 > Welcome Back</ h1 >
59+ < p > Please enter your email and password to Login</ p >
5360 </ div >
5461
5562 < form
63+ className = "auth-form"
5664 onSubmit = { ( e ) => {
5765 e . preventDefault ( ) ;
5866 handleSubmit ( ) ;
5967 } }
6068 >
6169 < div className = "space-y-6" >
62- { /* Email Input */ }
63- < InputField
64- icon = { Mail }
65- id = "signin-email"
66- name = "email"
67- type = "email"
68- value = { formData . email }
69- onChange = { handleInputChange }
70- error = { errors . email }
71- placeholder = "Email Address"
72- />
73-
74- { /* Password Field with Toggle Button */ }
75- < div >
76- < label
77- htmlFor = "signin-password"
78- className = "block text-sm font-medium text-gray-700 mb-2"
79- >
80- Password
81- </ label >
82- < div className = "flex items-center" >
83- < input
84- id = "signin-password"
85- name = "password"
86- type = { showPassword ? "text" : "password" }
87- value = { formData . password }
88- onChange = { handleInputChange }
89- placeholder = "Enter your password"
90- className = "flex-1 h-12 px-4 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
91- />
92- < button
93- type = "button"
94- onClick = { ( ) => setShowPassword ( ! showPassword ) }
95- className = "w-10 h-10 px-2 bg-green-700 text-white rounded-md ml-2 hover:bg-green-800 focus:outline-none focus:ring-2 focus:ring-green-500 flex items-center justify-center"
96- aria-label = { showPassword ? "Hide password" : "Show password" }
97- >
98- { showPassword ? (
99- < EyeOff className = "h-4 w-4" />
100- ) : (
101- < Eye className = "h-4 w-4" />
102- ) }
103- </ button >
104- </ div >
10570
71+ { /* EMAIL INPUT */ }
72+ < div className = "email-input-container" >
73+ < input
74+ id = "signin-email"
75+ name = "email"
76+ type = "email"
77+ value = { formData . email }
78+ onChange = { handleInputChange }
79+ placeholder = "Email"
80+ className = "login-email"
81+ required
82+ />
83+ < Mail className = "email-icon-right" />
84+ { errors . email && (
85+ < p className = "mt-1 text-sm text-red-600" > { errors . email } </ p >
86+ ) }
87+ </ div >
88+
89+ { /* PASSWORD INPUT */ }
90+ < div className = "password-input-container" >
91+ < input
92+ id = "signin-password"
93+ name = "password"
94+ type = { showPassword ? "text" : "password" }
95+ value = { formData . password }
96+ onChange = { handleInputChange }
97+ placeholder = "Password"
98+ className = "login-password"
99+ required
100+ />
101+ < span
102+ className = "password-icon"
103+ onClick = { ( ) => setShowPassword ( ! showPassword ) }
104+ role = "button"
105+ aria-label = "Toggle password visibility"
106+ tabIndex = { 0 }
107+ onKeyDown = { ( e ) =>
108+ e . key === 'Enter' && setShowPassword ( ! showPassword )
109+ }
110+ data-testid = "password-toggle"
111+ >
112+ { showPassword ? < FaEyeSlash size = { 18 } /> : < FaEye size = { 18 } /> }
113+ </ span >
106114 { errors . password && (
107115 < p className = "mt-1 text-sm text-red-600" > { errors . password } </ p >
108116 ) }
109117 </ div >
110118
111- { /* Submit Button */ }
112119 < button
113120 type = "submit"
114121 disabled = { isLoading }
115- className = "w-full bg-green-700 text-white py-3 px-4 rounded-lg hover:bg-green-800 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors font-medium "
122+ className = "auth-submit-button "
116123 >
117- { isLoading ? "Signing in..." : "Sign In " }
124+ { isLoading ? "Signing in..." : "Login " }
118125 </ button >
119126 </ div >
120127 </ form >
121128
122129 < div className = "mt-8 text-center" >
130+ < button
131+ type = "button"
132+ onClick = { ( ) => navigate ( '/forgotpassword' ) }
133+ className = "forgot-password"
134+ >
135+ Forgot password?
136+ </ button >
137+
123138 < p className = "text-sm text-gray-600" >
124- Don't have an account?{ " " }
139+ Don't have an account?{ ' ' }
125140 < button
126141 type = "button"
127- onClick = { ( ) => navigate ( '/signup' ) } // <-- Use navigate
128- className = "text-green-700 hover:text-green-600 font-medium focus:outline-none "
142+ onClick = { ( ) => navigate ( '/signup' ) }
143+ className = "link-button "
129144 >
130- Sign up
145+ Register
131146 </ button >
132147 </ p >
133148 </ div >
@@ -136,4 +151,4 @@ const SignIn = ({ onAuthSuccess }) => {
136151 ) ;
137152} ;
138153
139- export default SignIn ;
154+ export default SignIn ;
0 commit comments