1+ import React , { useState , ChangeEvent , FormEvent , useContext } from "react" ;
2+ import axios from "axios" ;
3+ import { useNavigate } from "react-router-dom" ;
4+ import { ThemeContext } from "../../ThemeContext" ;
5+ import type { ThemeContextType } from "../../ThemeContext" ;
6+
7+ const backendUrl = import . meta. env . VITE_BACKEND_URL ;
8+
9+ interface LoginFormData {
10+ email : string ;
11+ password : string ;
12+ }
13+
14+ const Login : React . FC = ( ) => {
15+ const [ formData , setFormData ] = useState < LoginFormData > ( { email : "" , password : "" } ) ;
16+ const [ message , setMessage ] = useState < string > ( "" ) ;
17+ const [ isLoading , setIsLoading ] = useState < boolean > ( false ) ;
18+
19+ const navigate = useNavigate ( ) ;
20+ const themeContext = useContext ( ThemeContext ) as ThemeContextType ;
21+ const { mode } = themeContext ;
22+
23+ const handleChange = ( e : ChangeEvent < HTMLInputElement > ) => {
24+ const { name, value } = e . target ;
25+ setFormData ( { ...formData , [ name ] : value } ) ;
26+ } ;
27+
28+ const handleSubmit = async ( e : FormEvent ) => {
29+ e . preventDefault ( ) ;
30+ setIsLoading ( true ) ;
31+
32+ try {
33+ const response = await axios . post ( `${ backendUrl } /api/auth/login` , formData ) ;
34+ setMessage ( response . data . message ) ;
35+
36+ if ( response . data . message === "Login successful" ) {
37+ navigate ( "/home" ) ;
38+ }
39+ } catch ( error : any ) {
40+ setMessage ( error . response ?. data ?. message || "Something went wrong" ) ;
41+ } finally {
42+ setIsLoading ( false ) ;
43+ }
44+ } ;
45+
46+ return (
47+ < div
48+ className = { `min-h-screen w-full flex items-center justify-center relative overflow-hidden ${
49+ mode === "dark"
50+ ? "bg-gradient-to-br from-slate-900 via-purple-900 to-slate-900"
51+ : "bg-gradient-to-br from-slate-100 via-purple-100 to-slate-100"
52+ } `}
53+ >
54+ { /* Background blobs */ }
55+ < div className = "absolute inset-0 pointer-events-none" >
56+ < div className = { `absolute -top-40 -right-40 w-96 h-96 ${ mode === "dark" ? "bg-purple-500" : "bg-purple-300" } rounded-full blur-3xl opacity-30 animate-pulse` } />
57+ < div className = { `absolute -bottom-40 -left-40 w-96 h-96 ${ mode === "dark" ? "bg-blue-500" : "bg-blue-300" } rounded-full blur-3xl opacity-30 animate-pulse` } />
58+ < div className = { `absolute top-40 left-40 w-96 h-96 ${ mode === "dark" ? "bg-pink-500" : "bg-pink-300" } rounded-full blur-3xl opacity-30 animate-pulse` } />
59+ </ div >
60+
61+ { /* Login Card */ }
62+ < div className = "relative w-full max-w-md px-6" >
63+ < div className = "text-center mb-10" >
64+ < div className = { `inline-flex items-center justify-center w-20 h-20 bg-white rounded-3xl mb-6 shadow-2xl overflow-hidden` } >
65+ < img src = "/crl-icon.png" alt = "Logo" className = "w-14 h-14 object-contain" />
66+ </ div >
67+ < h1 className = { `text-4xl font-bold bg-clip-text text-transparent mb-2 ${
68+ mode === "dark" ? "bg-gradient-to-r from-purple-300 via-pink-300 to-indigo-300" : "bg-gradient-to-r from-purple-600 via-pink-600 to-indigo-600"
69+ } `} >
70+ GitHubTracker
71+ </ h1 >
72+ < p className = { `${ mode === "dark" ? "text-slate-300" : "text-gray-700" } text-lg font-medium` } > Track your GitHub journey</ p >
73+ </ div >
74+
75+ { /* Form */ }
76+ < div className = { `rounded-3xl p-10 shadow-2xl border ${
77+ mode === "dark" ? "bg-white/10 backdrop-blur-xl border-white/20 text-white" : "bg-white border-gray-200 text-black"
78+ } `} >
79+ < h2 className = { `text-2xl font-bold text-center mb-8 ${ mode === "dark" ? "text-white" : "text-gray-800" } ` } > Welcome Back</ h2 >
80+
81+ < form onSubmit = { handleSubmit } className = "space-y-6" >
82+ < input
83+ type = "email"
84+ name = "email"
85+ placeholder = "Enter your email"
86+ value = { formData . email }
87+ onChange = { handleChange }
88+ autoComplete = "username"
89+ required
90+ className = { `w-full px-4 py-4 rounded-2xl focus:outline-none transition-all ${
91+ mode === "dark"
92+ ? "bg-white/5 border border-white/10 text-white placeholder-slate-400 focus:ring-2 focus:ring-purple-500"
93+ : "bg-gray-100 border border-gray-300 text-gray-900 placeholder-gray-500 focus:ring-2 focus:ring-purple-400"
94+ } `}
95+ />
96+
97+ < input
98+ type = "password"
99+ name = "password"
100+ autoComplete = "current-password"
101+ placeholder = "Enter your password"
102+ value = { formData . password }
103+ onChange = { handleChange }
104+ required
105+ className = { `w-full px-4 py-4 rounded-2xl focus:outline-none transition-all ${
106+ mode === "dark"
107+ ? "bg-white/5 border border-white/10 text-white placeholder-slate-400 focus:ring-2 focus:ring-purple-500"
108+ : "bg-gray-100 border border-gray-300 text-gray-900 placeholder-gray-500 focus:ring-2 focus:ring-purple-400"
109+ } `}
110+ />
111+
112+ < button
113+ type = "submit"
114+ disabled = { isLoading }
115+ className = "w-full bg-gradient-to-r from-purple-600 via-pink-600 to-indigo-600 text-white py-4 px-6 rounded-2xl font-semibold focus:ring-4 focus:ring-purple-500/50 transition-all duration-300 disabled:opacity-50 disabled:cursor-not-allowed"
116+ >
117+ { isLoading ? "Signing in..." : "Sign In" }
118+ </ button >
119+ </ form >
120+
121+ { message && (
122+ < div className = { `mt-6 p-4 rounded-2xl text-center text-sm font-medium ${
123+ message === "Login successful"
124+ ? "bg-green-500/20 text-green-300 border border-green-500/30"
125+ : "bg-red-500/20 text-red-300 border border-red-500/30"
126+ } `} >
127+ { message }
128+ </ div >
129+ ) }
130+ </ div >
131+
132+ { /* Footer Text */ }
133+ < div className = "text-center mt-8 pb-8" >
134+ < p className = { `${ mode === "dark" ? "text-slate-500" : "text-gray-600" } text-sm` } >
135+ Don't have an account?
136+ < a href = "#" className = "ml-1 text-purple-400 hover:text-purple-300 transition-colors duration-300" >
137+ Sign up here
138+ </ a >
139+ </ p >
140+ </ div >
141+ </ div >
142+
143+ { /* Lower gradient */ }
144+ < div className = { `${ mode === "dark" ? "from-slate-900" : "from-slate-100" } absolute bottom-0 left-0 w-full h-20 bg-gradient-to-t to-transparent` } />
145+ </ div >
146+ ) ;
147+ } ;
148+
149+ export default Login ;
0 commit comments