33import Link from 'next/link' ;
44import { useRouter , useSearchParams } from 'next/navigation' ;
55import { FormEvent , useState } from 'react' ;
6- import { ArrowRight } from 'lucide-react' ;
6+ import { motion , AnimatePresence } from 'framer-motion' ;
7+ import {
8+ Mail ,
9+ Lock ,
10+ ShieldCheck ,
11+ Loader2 ,
12+ AlertCircle ,
13+ Eye ,
14+ EyeOff ,
15+ ArrowRight
16+ } from 'lucide-react' ;
717import { useAuth } from '../../src/components/auth/AuthProvider' ;
18+ import { GridBackground } from '../../components/home' ;
19+ import { fadeUp , staggerContainer } from '../../components/home/motion-variants' ;
20+ import { GlassCard } from '../../components/ui/GlassCard' ;
21+ import { AccentButton } from '../../components/ui/AccentButton' ;
822
923export default function LoginPage ( ) {
1024 const [ email , setEmail ] = useState ( '' ) ;
1125 const [ password , setPassword ] = useState ( '' ) ;
26+ const [ showPassword , setShowPassword ] = useState ( false ) ;
1227 const [ error , setError ] = useState ( '' ) ;
1328 const [ loading , setLoading ] = useState ( false ) ;
29+
1430 const router = useRouter ( ) ;
1531 const searchParams = useSearchParams ( ) ;
1632 const { login } = useAuth ( ) ;
@@ -25,87 +41,170 @@ export default function LoginPage() {
2541 const next = searchParams . get ( 'next' ) || '/dashboard' ;
2642 router . push ( next ) ;
2743 } catch ( err ) {
28- setError ( ( err as Error ) . message || 'Login failed' ) ;
44+ setError ( ( err as Error ) . message || 'Authentication failed. Please check your credentials. ' ) ;
2945 } finally {
3046 setLoading ( false ) ;
3147 }
3248 } ;
3349
3450 return (
35- < main className = "relative min-h-screen overflow-hidden bg-[#030303] text-white flex flex-col justify-center px-6" >
36- { /* Background Ambience */ }
37- < div className = "pointer-events-none absolute inset-0 grid-bg opacity-10" />
38- < div className = "pointer-events-none absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 h-[600px] w-full max-w-4xl bg-purple-600/5 blur-[120px]" />
39-
40- < div className = "relative z-10 mx-auto w-full max-w-lg" >
41- < div className = "text-center mb-10" >
42- < Link href = "/" className = "inline-flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-purple-500 to-purple-700 shadow-xl shadow-purple-500/20 mb-6 group transition-transform hover:scale-105 active:scale-95" >
43- < span className = "text-white font-black text-3xl" > FS</ span >
44- </ Link >
45- < h1 className = "text-4xl font-extrabold tracking-tight text-white mb-3" >
46- Welcome Back
47- </ h1 >
48- < p className = "text-zinc-400 font-medium tracking-wide uppercase text-[10px] tracking-[0.2em]" >
49- Sign in to your FairShare account
50- </ p >
51- </ div >
51+ < main className = "relative min-h-screen overflow-hidden bg-[#030303] text-white selection:bg-purple-500/30 font-sans" >
52+ < GridBackground />
53+
54+ { /* Subtle Background Glows */ }
55+ < div className = "absolute top-0 left-0 h-full w-full pointer-events-none overflow-hidden" >
56+ < div className = "absolute top-[-10%] left-[-10%] h-[500px] w-[500px] bg-purple-600/10 blur-[120px] rounded-full" />
57+ < div className = "absolute bottom-[-10%] right-[-10%] h-[600px] w-[600px] bg-indigo-600/5 blur-[150px] rounded-full" />
58+ </ div >
59+
60+ < div className = "relative z-10 flex min-h-screen pt-10 md:pt-5 flex-col lg:flex-row max-w-[1600px] mx-auto" >
61+ { /* Left Side: Brand & Value Prop */ }
62+ < div className = "hidden md:flex flex-1 flex-col justify-center px-8 py-0 -mt-32 lg:px-20 xl:px-32" >
63+ < motion . div
64+ variants = { staggerContainer }
65+ initial = "hidden"
66+ animate = "show"
67+ className = "max-w-xl"
68+ >
5269
53- < div className = "relative overflow-hidden rounded-[2.5rem] border border-white/5 bg-white/[0.03] backdrop-blur-2xl p-8 sm:p-12 shadow-2xl" >
54- { /* Internal Glow */ }
55- < div className = "absolute inset-0 bg-gradient-to-br from-purple-500/5 via-transparent to-transparent pointer-events-none" />
56-
57- < form className = "relative z-10 space-y-6" onSubmit = { onSubmit } >
58- < div className = "space-y-2" >
59- < label className = "text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-500 ml-1" > Email Address</ label >
60- < input
61- className = "w-full bg-white/5 border border-white/10 rounded-2xl p-4 font-medium text-white outline-none focus:border-purple-500/50 focus:bg-white/[0.08] transition-all"
62- placeholder = "name@company.com"
63- type = "email"
64- value = { email }
65- onChange = { ( event ) => setEmail ( event . target . value ) }
66- required
67- />
68- </ div >
69-
70- < div className = "space-y-2" >
71- < label className = "text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-500 ml-1" > Password</ label >
72- < input
73- className = "w-full bg-white/5 border border-white/10 rounded-2xl p-4 font-medium text-white outline-none focus:border-purple-500/50 focus:bg-white/[0.08] transition-all"
74- placeholder = "••••••••"
75- type = "password"
76- value = { password }
77- onChange = { ( event ) => setPassword ( event . target . value ) }
78- required
79- />
80- </ div >
81-
82- { error ? (
83- < div className = "bg-red-500/10 border border-red-500/20 p-4 rounded-xl text-red-400 font-bold text-sm text-center" >
84- { error }
85- </ div >
86- ) : null }
8770
88- < button
89- className = "btn-royal w-full group py-4 h-14"
90- disabled = { loading }
91- type = "submit"
71+ < motion . h1
72+ variants = { fadeUp }
73+ className = "text-5xl font-bold tracking-tight md:text-6xl lg:text-7xl leading-[1.1] text-white mb-8"
9274 >
93- < span className = "flex items-center justify-center gap-2" >
94- { loading ? 'Authenticating...' : 'Sign In' }
95- { ! loading && < ArrowRight size = { 18 } className = "transition-transform group-hover:translate-x-1" /> }
96- </ span >
97- </ button >
98-
99- < p className = "text-center text-sm font-medium text-zinc-500" >
100- New to FairShare?{ ' ' }
101- < Link className = "text-purple-400 hover:text-purple-300 transition-colors font-bold underline decoration-purple-500/30 underline-offset-8 decoration-2" href = "/register" >
102- Create account
103- </ Link >
104- </ p >
105- </ form >
106-
107- { /* Top light leak */ }
108- < div className = "absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-white/15 to-transparent" />
75+ Access the < br />
76+ < span className = "text-zinc-600" > financial engine.</ span >
77+ </ motion . h1 >
78+
79+ < motion . p
80+ variants = { fadeUp }
81+ className = "mb-12 text-lg text-zinc-400 leading-relaxed max-w-lg"
82+ >
83+ The unified protocol for expense management and collaborative finance. Sign in to resume your operations.
84+ </ motion . p >
85+
86+ < motion . div variants = { fadeUp } className = "space-y-6" >
87+ { [
88+ { title : 'Secure Vault' , sub : 'End-to-end encrypted session keys.' , icon : Lock } ,
89+ { title : 'Verified Nodes' , sub : 'Institutional-grade access control.' , icon : ShieldCheck }
90+ ] . map ( ( item , idx ) => (
91+ < div key = { idx } className = "flex items-center gap-5 group" >
92+ < div className = "h-10 w-10 flex items-center justify-center rounded-xl border border-white/5 bg-white/[0.03] group-hover:border-purple-500/30 group-hover:bg-purple-500/5 transition-all" >
93+ < item . icon size = { 18 } className = "text-zinc-500 group-hover:text-purple-400" />
94+ </ div >
95+ < div >
96+ < h4 className = "text-sm font-bold text-white uppercase tracking-wider" > { item . title } </ h4 >
97+ < p className = "text-xs text-zinc-500 font-medium" > { item . sub } </ p >
98+ </ div >
99+ </ div >
100+ ) ) }
101+ </ motion . div >
102+ </ motion . div >
103+ </ div >
104+
105+ { /* Right Side: Identity Form */ }
106+ < div className = "relative flex flex-1 items-center justify-center px-6 py-20 lg:px-12 xl:px-24" >
107+ < motion . div
108+ initial = { { opacity : 0 , y : 20 } }
109+ animate = { { opacity : 1 , y : 0 } }
110+ transition = { { duration : 0.8 , ease : "easeOut" } }
111+ className = "w-full max-w-[480px]"
112+ >
113+ < GlassCard className = "relative p-8 md:p-12 border-white/5 bg-white/[0.01] overflow-hidden" >
114+ < div className = "relative z-10" >
115+ < div className = "mb-10" >
116+ < h2 className = "text-3xl font-bold tracking-tight text-white mb-2" > Welcome Back</ h2 >
117+ < p className = "text-sm text-zinc-500" > Resume your collaborative financial operations.</ p >
118+ </ div >
119+
120+ < form onSubmit = { onSubmit } className = "space-y-5" >
121+ < AnimatePresence mode = "wait" >
122+ { error && (
123+ < motion . div
124+ initial = { { opacity : 0 , y : - 10 } }
125+ animate = { { opacity : 1 , y : 0 } }
126+ exit = { { opacity : 0 , scale : 0.95 } }
127+ className = "flex items-center gap-3 rounded-xl border border-red-500/10 bg-red-500/5 p-4 text-xs font-medium text-red-500"
128+ >
129+ < AlertCircle size = { 14 } />
130+ < span > { error } </ span >
131+ </ motion . div >
132+ ) }
133+ </ AnimatePresence >
134+
135+ < div className = "space-y-1.5" >
136+ < label className = "text-xs font-bold text-zinc-500 ml-1" > Email Address</ label >
137+ < div className = "relative group" >
138+ < Mail size = { 16 } className = "absolute left-4 top-1/2 -translate-y-1/2 text-zinc-600 group-focus-within:text-purple-500 transition-colors" />
139+ < input
140+ required
141+ type = "email"
142+ value = { email }
143+ onChange = { ( e ) => setEmail ( e . target . value ) }
144+ placeholder = "name@fairshare.com"
145+ disabled = { loading }
146+ className = "w-full bg-white/[0.03] border border-white/5 rounded-xl py-4 pl-12 pr-4 text-sm font-medium text-white placeholder-zinc-700 outline-none focus:border-purple-500/30 focus:bg-white/[0.05] transition-all"
147+ />
148+ </ div >
149+ </ div >
150+
151+ < div className = "space-y-1.5" >
152+ < div className = "flex items-center justify-between px-1" >
153+ < label className = "text-xs font-bold text-zinc-500" > Password</ label >
154+ < Link href = "/forgot-password" className = "text-[10px] font-bold text-zinc-500 hover:text-white transition-colors uppercase tracking-widest" >
155+ Forgot?
156+ </ Link >
157+ </ div >
158+ < div className = "relative group" >
159+ < Lock size = { 16 } className = "absolute left-4 top-1/2 -translate-y-1/2 text-zinc-600 group-focus-within:text-purple-500 transition-colors" />
160+ < input
161+ required
162+ type = { showPassword ? 'text' : 'password' }
163+ value = { password }
164+ onChange = { ( e ) => setPassword ( e . target . value ) }
165+ placeholder = "••••••••"
166+ disabled = { loading }
167+ className = "w-full bg-white/[0.03] border border-white/5 rounded-xl py-4 pl-12 pr-12 text-sm font-medium text-white placeholder-zinc-700 outline-none focus:border-purple-500/30 focus:bg-white/[0.05] transition-all"
168+ />
169+ < button
170+ type = "button"
171+ onClick = { ( ) => setShowPassword ( ! showPassword ) }
172+ className = "absolute right-4 top-1/2 -translate-y-1/2 text-zinc-600 hover:text-white transition-colors"
173+ >
174+ { showPassword ? < EyeOff size = { 16 } /> : < Eye size = { 16 } /> }
175+ </ button >
176+ </ div >
177+ </ div >
178+
179+ < div className = "pt-4" >
180+ < AccentButton
181+ type = "submit"
182+ disabled = { loading }
183+ className = "w-full h-14 text-base font-bold"
184+ variant = "primary"
185+ >
186+ { loading ? (
187+ < span className = "flex items-center gap-2" >
188+ < Loader2 size = { 18 } className = "animate-spin" /> Verifying...
189+ </ span >
190+ ) : (
191+ < span className = "flex items-center gap-2" >
192+ Sign In < ArrowRight size = { 18 } />
193+ </ span >
194+ ) }
195+ </ AccentButton >
196+ </ div >
197+
198+ < p className = "pt-8 text-center text-xs font-medium text-zinc-500" >
199+ New to the ecosystem?{ ' ' }
200+ < Link className = "text-white hover:text-purple-400 font-bold transition-all" href = "/register" >
201+ Create an account
202+ </ Link >
203+ </ p >
204+ </ form >
205+ </ div >
206+ </ GlassCard >
207+ </ motion . div >
109208 </ div >
110209 </ div >
111210 </ main >
0 commit comments