1+ import TextField from '@mui/material/TextField' ;
2+ import { useState } from 'react' ;
3+ import { Link , useNavigate } from 'react-router-dom' ;
4+ import Button from '@mui/material/Button' ;
5+ import { styled } from '@mui/material/styles' ;
6+
7+ const Login = ( ) => {
8+ const navigate = useNavigate ( ) ;
9+ const [ formData , setFormData ] = useState ( {
10+ email : '' ,
11+ password : '' ,
12+ } ) ;
13+ const [ error , setError ] = useState ( null ) ;
14+ const [ isLoading , setIsLoading ] = useState ( false ) ;
15+
16+ const handleChange = ( e ) => {
17+ const { name, value } = e . target ;
18+ setFormData ( {
19+ ...formData ,
20+ [ name ] : value ,
21+ } ) ;
22+ } ;
23+
24+ const handleSubmit = async ( e ) => {
25+ e . preventDefault ( ) ;
26+ setError ( null ) ;
27+ setIsLoading ( true ) ;
28+ try {
29+ const response = await fetch ( "http://localhost:3500/auth/login" , {
30+ method : 'POST' ,
31+ headers : {
32+ 'Content-Type' : 'application/json' ,
33+ } ,
34+ body : JSON . stringify ( formData ) ,
35+ } ) ;
36+ if ( ! response . ok ) {
37+ const errData = await response . json ( ) ;
38+ throw new Error ( errData . message || "Failed to login" ) ;
39+ }
40+ const { token, user } = await response . json ( ) ;
41+ localStorage . setItem ( 'token' , token ) ;
42+ navigate ( "/" ) ;
43+ } catch ( err ) {
44+ setError ( err . message ) ;
45+ } finally {
46+ setIsLoading ( false ) ;
47+ }
48+ } ;
49+
50+ const ColorButton = styled ( Button ) ( ( ) => ( {
51+ color : '#FFFFFF' ,
52+ backgroundColor : '#8D538D' ,
53+ '&:hover' : {
54+ backgroundColor : '#514ACD' ,
55+ } ,
56+ borderRadius : '8px' ,
57+ } ) ) ;
58+
59+ return (
60+ < div className = 'flex flex-col justify-center items-center min-h-screen bg-gray-100' >
61+ < div className = 'mb-8 text-center' >
62+ < h1 className = 'text-4xl font-bold text-transparent bg-clip-text bg-gradient-to-r from-[#8D538D] to-[#514ACD]' >
63+ Welcome to JobNode!
64+ </ h1 >
65+ < p className = 'text-xl text-gray-700 mt-2' > Your gateway to career opportunities</ p >
66+ </ div >
67+
68+ < div className = 'flex items-center bg-white shadow-lg rounded-lg overflow-hidden w-[40em]' >
69+ < form
70+ className = 'flex flex-col gap-4 w-1/2 p-8'
71+ onSubmit = { handleSubmit }
72+ >
73+ < h1 className = 'text-2xl font-bold text-center text-gray-800 mb-4' > Login</ h1 >
74+ < TextField
75+ id = 'login-email'
76+ label = 'Email'
77+ variant = 'outlined'
78+ onChange = { handleChange }
79+ type = 'email'
80+ name = 'email'
81+ value = { formData . email }
82+ />
83+ < TextField
84+ id = 'login-password'
85+ label = 'Password'
86+ variant = 'outlined'
87+ onChange = { handleChange }
88+ type = 'password'
89+ name = 'password'
90+ value = { formData . password }
91+ />
92+ < Link to = '/forgot-password' className = 'text-sm text-blue-500 hover:underline self-center' >
93+ Forgot Password?
94+ </ Link >
95+ { error && < p className = 'text-red-500 text-center' > { error } </ p > }
96+ < ColorButton
97+ variant = 'contained'
98+ size = 'large'
99+ type = 'submit'
100+ disabled = { isLoading }
101+ >
102+ { isLoading ? 'Logging in...' : 'Login' }
103+ </ ColorButton >
104+ < div className = 'flex items-center gap-2 text-sm mt-4' >
105+ < div className = 'w-full h-[1px] bg-gray-300' > </ div >
106+ </ div >
107+ < p className = 'text-sm text-center mt-4' >
108+ Don't have an account?{ ' ' }
109+ < Link to = '/signup' className = 'text-blue-500 hover:underline' >
110+ Register
111+ </ Link >
112+ </ p >
113+ </ form >
114+ < div className = 'w-1/2 bg-gray-200 flex items-center justify-center' >
115+ < img src = '/loginImg.jpeg' alt = 'Illustration' className = 'w-full h-auto' />
116+ </ div >
117+ </ div >
118+ </ div >
119+ ) ;
120+ } ;
121+
122+ export default Login ;
0 commit comments