11"use client" ;
22
3- import { useState } from "react" ;
4- import { useRouter } from "next/navigation" ;
5- import { signInWithPopup , GoogleAuthProvider , signInWithEmailAndPassword , createUserWithEmailAndPassword } from "firebase/auth" ;
3+ import { useState , useEffect } from "react" ;
4+ import { useRouter , useSearchParams } from "next/navigation" ;
5+ import {
6+ signInWithPopup ,
7+ GoogleAuthProvider ,
8+ signInWithEmailAndPassword ,
9+ createUserWithEmailAndPassword ,
10+ } from "firebase/auth" ;
611import { auth } from "@/lib/firebase" ;
712import { useAuth } from "@/contexts/AuthContext" ;
8- import { useEffect } from "react" ;
13+ import { motion } from "framer-motion" ;
14+ import { Button } from "@/components/ui/Button" ;
915
1016export default function LoginPage ( ) {
11- const { user, loading } = useAuth ( ) ;
17+ const { user, loading, setPlan } = useAuth ( ) ;
1218 const router = useRouter ( ) ;
19+ const searchParams = useSearchParams ( ) ;
1320 const [ email , setEmail ] = useState ( "" ) ;
1421 const [ password , setPassword ] = useState ( "" ) ;
1522 const [ isSignUp , setIsSignUp ] = useState ( false ) ;
1623 const [ error , setError ] = useState ( "" ) ;
1724 const [ submitting , setSubmitting ] = useState ( false ) ;
1825
26+ // Read plan from URL param
27+ useEffect ( ( ) => {
28+ const planParam = searchParams . get ( "plan" ) ;
29+ if ( planParam === "premium" || planParam === "free" ) {
30+ setPlan ( planParam ) ;
31+ }
32+ } , [ searchParams , setPlan ] ) ;
33+
1934 useEffect ( ( ) => {
2035 if ( ! loading && user ) {
2136 router . replace ( "/dashboard" ) ;
@@ -27,8 +42,8 @@ export default function LoginPage() {
2742 setError ( "" ) ;
2843 await signInWithPopup ( auth , new GoogleAuthProvider ( ) ) ;
2944 router . replace ( "/dashboard" ) ;
30- } catch ( err : any ) {
31- setError ( err . message || "Google sign-in failed" ) ;
45+ } catch ( err : unknown ) {
46+ setError ( err instanceof Error ? err . message : "Google sign-in failed" ) ;
3247 }
3348 } ;
3449
@@ -43,102 +58,138 @@ export default function LoginPage() {
4358 await signInWithEmailAndPassword ( auth , email , password ) ;
4459 }
4560 router . replace ( "/dashboard" ) ;
46- } catch ( err : any ) {
47- setError ( err . message || "Authentication failed" ) ;
61+ } catch ( err : unknown ) {
62+ setError ( err instanceof Error ? err . message : "Authentication failed" ) ;
4863 } finally {
4964 setSubmitting ( false ) ;
5065 }
5166 } ;
5267
5368 if ( loading ) {
5469 return (
55- < div className = "flex min-h-screen items-center justify-center bg-gray-50 " >
56- < div className = "h-8 w-8 animate-spin rounded-full border-4 border-indigo-600 border-t-transparent" />
70+ < div className = "flex min-h-screen items-center justify-center bg-[var(--bg-secondary)] " >
71+ < div className = "h-8 w-8 animate-spin rounded-full border-4 border-[var(--accent)] border-t-transparent" />
5772 </ div >
5873 ) ;
5974 }
6075
6176 return (
62- < div className = "flex min-h-screen items-center justify-center bg-gradient-to-br from-indigo-50 via-white to-purple-50 px-4" >
63- < div className = "w-full max-w-md space-y-8" >
77+ < div className = "flex min-h-screen items-center justify-center bg-[var(--bg-secondary)] px-4" >
78+ < motion . div
79+ initial = { { opacity : 0 , y : 20 } }
80+ animate = { { opacity : 1 , y : 0 } }
81+ transition = { { duration : 0.4 , ease : "easeOut" } }
82+ className = "w-full max-w-md space-y-8"
83+ >
6484 < div className = "text-center" >
65- < h1 className = "text-3xl font-bold text-indigo-600" > Seniora</ h1 >
66- < p className = "mt-2 text-sm text-gray-600" >
67- { isSignUp ? "Create your account" : "Sign in to your account" }
85+ < div className = "inline-flex items-center justify-center w-12 h-12 rounded-2xl bg-[var(--accent)] text-white font-bold text-xl mb-4" >
86+ S
87+ </ div >
88+ < h1 className = "text-2xl font-bold text-[var(--text-primary)]" >
89+ { isSignUp ? "Create your account" : "Welcome back" }
90+ </ h1 >
91+ < p className = "mt-1 text-sm text-[var(--text-secondary)]" >
92+ { isSignUp
93+ ? "Get started with Seniora"
94+ : "Sign in to continue to Seniora" }
6895 </ p >
6996 </ div >
7097
71- < div className = "rounded-xl border border-gray-200 bg-white p-8 shadow-sm space-y-6" >
98+ < div className = "rounded-2xl border border-[var(--card-border)] bg-[var(--card-bg)] p-8 shadow-[var(--card-shadow)] space-y-6" >
7299 { error && (
73- < p className = "rounded-lg bg-red-50 p-3 text-sm text-red-600" > { error } </ p >
100+ < p className = "rounded-xl bg-[var(--danger-light)] p-3 text-sm text-red-700" >
101+ { error }
102+ </ p >
74103 ) }
75104
76105 < button
77106 onClick = { handleGoogle }
78- className = "flex w-full items-center justify-center gap-3 rounded-lg border border-gray-300 px-4 py-2.5 text-sm font-medium text-gray-700 hover:bg-gray-50 transition-colors"
107+ className = "flex w-full items-center justify-center gap-3 rounded-xl border border-[var(--border-default)] px-4 py-2.5 text-sm font-medium text-[var(--text-primary)] hover:bg-[var(--bg-tertiary)] transition-colors"
79108 >
80109 < svg className = "h-5 w-5" viewBox = "0 0 24 24" >
81- < path d = "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill = "#4285F4" />
82- < path d = "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill = "#34A853" />
83- < path d = "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill = "#FBBC05" />
84- < path d = "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill = "#EA4335" />
110+ < path
111+ d = "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z"
112+ fill = "#4285F4"
113+ />
114+ < path
115+ d = "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
116+ fill = "#34A853"
117+ />
118+ < path
119+ d = "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
120+ fill = "#FBBC05"
121+ />
122+ < path
123+ d = "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
124+ fill = "#EA4335"
125+ />
85126 </ svg >
86127 Continue with Google
87128 </ button >
88129
89130 < div className = "relative" >
90131 < div className = "absolute inset-0 flex items-center" >
91- < div className = "w-full border-t border-gray-200 " />
132+ < div className = "w-full border-t border-[var(--border-default)] " />
92133 </ div >
93134 < div className = "relative flex justify-center text-sm" >
94- < span className = "bg-white px-4 text-gray-500" > or</ span >
135+ < span className = "bg-[var(--card-bg)] px-4 text-[var(--text-muted)]" >
136+ or
137+ </ span >
95138 </ div >
96139 </ div >
97140
98141 < form onSubmit = { handleEmailAuth } className = "space-y-4" >
99142 < div >
100- < label className = "block text-sm font-medium text-gray-700 mb-1" > Email</ label >
143+ < label className = "block text-sm font-medium text-[var(--text-secondary)] mb-1" >
144+ Email
145+ </ label >
101146 < input
102147 type = "email"
103148 value = { email }
104149 onChange = { ( e ) => setEmail ( e . target . value ) }
105150 required
106- className = "w-full rounded-lg border border-gray-300 px-3 py-2 text-sm text-gray-900 placeholder-gray-400 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 "
151+ className = "w-full rounded-xl border border-[var(--border-default)] bg-[var(--bg-primary)] px-3 py-2.5 text-sm text-[var(--text-primary)] placeholder-[var(--text-muted)] focus:border-[var(--accent)] focus:outline-none focus:ring-1 focus:ring-[var(--accent)] "
107152 placeholder = "you@example.com"
108153 />
109154 </ div >
110155 < div >
111- < label className = "block text-sm font-medium text-gray-700 mb-1" > Password</ label >
156+ < label className = "block text-sm font-medium text-[var(--text-secondary)] mb-1" >
157+ Password
158+ </ label >
112159 < input
113160 type = "password"
114161 value = { password }
115162 onChange = { ( e ) => setPassword ( e . target . value ) }
116163 required
117164 minLength = { 6 }
118- className = "w-full rounded-lg border border-gray-300 px-3 py-2 text-sm text-gray-900 placeholder-gray-400 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 "
165+ className = "w-full rounded-xl border border-[var(--border-default)] bg-[var(--bg-primary)] px-3 py-2.5 text-sm text-[var(--text-primary)] placeholder-[var(--text-muted)] focus:border-[var(--accent)] focus:outline-none focus:ring-1 focus:ring-[var(--accent)] "
119166 placeholder = "••••••••"
120167 />
121168 </ div >
122- < button
169+ < Button
123170 type = "submit"
124- disabled = { submitting }
125- className = "w-full rounded-lg bg-indigo-600 px-4 py-2.5 text-sm font-medium text-white hover:bg-indigo-700 transition-colors disabled:opacity-50"
171+ loading = { submitting }
172+ className = "w-full"
173+ size = "lg"
126174 >
127- { submitting ? "Please wait..." : isSignUp ? "Create Account" : "Sign In" }
128- </ button >
175+ { isSignUp ? "Create Account" : "Sign In" }
176+ </ Button >
129177 </ form >
130178
131- < p className = "text-center text-sm text-gray-500 " >
179+ < p className = "text-center text-sm text-[var(--text-secondary)] " >
132180 { isSignUp ? "Already have an account?" : "Don't have an account?" } { " " }
133181 < button
134- onClick = { ( ) => { setIsSignUp ( ! isSignUp ) ; setError ( "" ) ; } }
135- className = "font-medium text-indigo-600 hover:text-indigo-500"
182+ onClick = { ( ) => {
183+ setIsSignUp ( ! isSignUp ) ;
184+ setError ( "" ) ;
185+ } }
186+ className = "font-medium text-[var(--accent)] hover:underline"
136187 >
137188 { isSignUp ? "Sign In" : "Sign Up" }
138189 </ button >
139190 </ p >
140191 </ div >
141- </ div >
192+ </ motion . div >
142193 </ div >
143194 ) ;
144195}
0 commit comments