11"use client" ;
22
3- import { useEffect , useState } from "react" ;
3+ import { useEffect , useMemo , useState } from "react" ;
44import { useAuth } from "@/contexts/AuthContext" ;
55import { useRouter } from "next/navigation" ;
6+ import { Loader2 } from "lucide-react" ;
67
78export default function AuthPage ( ) {
89 const [ isLogin , setIsLogin ] = useState ( true ) ;
@@ -15,6 +16,8 @@ export default function AuthPage() {
1516
1617 const { user, signIn, signUp, signInWithGoogle } = useAuth ( ) ;
1718 const router = useRouter ( ) ;
19+ const inputClassName =
20+ "w-full rounded-2xl border border-white/10 bg-white/5 px-4 py-3 text-base text-white placeholder:text-white/50 focus:border-emerald-400 focus:ring-2 focus:ring-emerald-400/30 focus:outline-none" ;
1821
1922 // if logged in, redirect to dashboard
2023 useEffect ( ( ) => {
@@ -56,135 +59,226 @@ export default function AuthPage() {
5659 }
5760 } ;
5861
62+ const pageStats = useMemo (
63+ ( ) => [
64+ {
65+ value : "~2 min" ,
66+ label : "Average approval time" ,
67+ } ,
68+ {
69+ value : "15+" ,
70+ label : "Signals per assessment" ,
71+ } ,
72+ {
73+ value : "0–100" ,
74+ label : "Transparent trust score" ,
75+ } ,
76+ ] ,
77+ [ ] ,
78+ ) ;
79+
5980 return (
60- < div className = "min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8" >
61- < div className = "max-w-md w-full space-y-8" >
62- < div >
63- < h2 className = "mt-6 text-center text-3xl font-extrabold text-gray-900" >
64- { isLogin ? "Sign in to your account" : "Create new account" }
65- </ h2 >
66- </ div >
81+ < div className = "relative min-h-screen overflow-hidden bg-zinc-950 text-white" >
82+ < div className = "absolute inset-0 opacity-30" >
83+ < div
84+ className = "absolute inset-0"
85+ style = { {
86+ backgroundImage :
87+ "linear-gradient(rgba(255,255,255,0.04) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.04) 1px, transparent 1px)" ,
88+ backgroundSize : "64px 64px" ,
89+ } }
90+ />
91+ </ div >
92+ < div className = "absolute -right-32 top-0 h-[600px] w-[600px] rounded-full bg-emerald-500/20 blur-[160px]" />
93+ < div className = "absolute -left-32 bottom-0 h-[500px] w-[500px] rounded-full bg-blue-500/20 blur-[160px]" />
6794
68- < form className = "mt-8 space-y-6" onSubmit = { handleSubmit } >
69- { error && (
70- < div className = "rounded-md bg-red-50 p-4" >
71- < p className = "text-sm text-red-800" > { error } </ p >
95+ < div className = "relative mx-auto flex min-h-screen w-full items-center justify-center px-4 py-16 sm:px-6 lg:px-8" >
96+ < div className = "grid w-full max-w-6xl gap-12 lg:grid-cols-2" >
97+ < div className = "space-y-8" >
98+ < div className = "inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-4 py-2 text-sm text-white/70 backdrop-blur" >
99+ Junction One • Zero-trust intake
72100 </ div >
73- ) }
74-
75- < div className = "rounded-md shadow-sm -space-y-px" >
76- { ! isLogin && (
77- < >
78- < div >
79- < label htmlFor = "first-name" className = "sr-only" >
80- First Name
81- </ label >
82- < input
83- id = "first-name"
84- name = "firstName"
85- type = "text"
86- required = { ! isLogin }
87- value = { firstName }
88- onChange = { ( e ) => setFirstName ( e . target . value ) }
89- className = "appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm"
90- placeholder = "First Name"
91- />
92- </ div >
93- < div >
94- < label htmlFor = "last-name" className = "sr-only" >
95- Last Name
96- </ label >
97- < input
98- id = "last-name"
99- name = "lastName"
100- type = "text"
101- required = { ! isLogin }
102- value = { lastName }
103- onChange = { ( e ) => setLastName ( e . target . value ) }
104- className = "appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm"
105- placeholder = "Last Name"
106- />
107- </ div >
108- </ >
109- ) }
110-
111101 < div >
112- < label htmlFor = "email-address" className = "sr-only" >
113- Email address
114- </ label >
115- < input
116- id = "email-address"
117- name = "email"
118- type = "email"
119- autoComplete = "email"
120- required
121- value = { email }
122- onChange = { ( e ) => setEmail ( e . target . value ) }
123- className = { `appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 ${ isLogin ? "rounded-t-md" : "" } focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm` }
124- placeholder = "Email address"
125- />
102+ < h1 className = "text-4xl font-semibold leading-tight tracking-tight sm:text-5xl" >
103+ Join the trust layer for{ " " }
104+ < span className = "bg-gradient-to-r from-emerald-400 to-blue-400 bg-clip-text text-transparent" >
105+ security decisions
106+ </ span >
107+ </ h1 >
108+ < p className = "mt-6 text-lg text-white/70" >
109+ One login gives you SOC 2 ready assessments, audit trails, and
110+ explainable AI recommendations so your team never ships blind.
111+ </ p >
126112 </ div >
127113
128- < div >
129- < label htmlFor = "password" className = "sr-only" >
130- Password
131- </ label >
132- < input
133- id = "password"
134- name = "password"
135- type = "password"
136- autoComplete = "current-password"
137- required
138- value = { password }
139- onChange = { ( e ) => setPassword ( e . target . value ) }
140- className = "appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-blue-500 focus:border-blue-500 focus:z-10 sm:text-sm"
141- placeholder = "Password"
142- />
114+ < div className = "grid gap-4 sm:grid-cols-3" >
115+ { pageStats . map ( ( stat ) => (
116+ < div
117+ key = { stat . label }
118+ className = "rounded-2xl border border-white/10 bg-white/5 p-5"
119+ >
120+ < div className = "text-2xl font-semibold" > { stat . value } </ div >
121+ < p className = "mt-2 text-sm text-white/60" > { stat . label } </ p >
122+ </ div >
123+ ) ) }
143124 </ div >
144- </ div >
145125
146- < div >
147- < button
148- type = "submit"
149- disabled = { loading }
150- className = "group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
151- >
152- { loading ? "Loading..." : isLogin ? "Sign in" : "Sign up" }
153- </ button >
126+ < p className = "text-sm uppercase tracking-[0.3em] text-white/40" >
127+ Trusted by security teams in EMEA & the Nordics
128+ </ p >
154129 </ div >
155130
156- < div className = "relative" >
157- < div className = "absolute inset-0 flex items-center" >
158- < div className = "w-full border-t border-gray-300" />
131+ < div className = "rounded-3xl border border-white/10 bg-zinc-900/70 p-8 shadow-2xl backdrop-blur" >
132+ < div className = "flex items-center justify-between" >
133+ < div >
134+ < p className = "text-sm uppercase tracking-widest text-emerald-400" >
135+ Access portal
136+ </ p >
137+ < h2 className = "mt-2 text-2xl font-semibold" >
138+ { isLogin ? "Welcome back" : "Create your account" }
139+ </ h2 >
140+ </ div >
141+ < button
142+ type = "button"
143+ onClick = { ( ) => setIsLogin ( ! isLogin ) }
144+ className = "text-sm text-white/60 transition hover:text-white"
145+ >
146+ { isLogin ? "Need access?" : "Have an account?" }
147+ </ button >
159148 </ div >
160- < div className = "relative flex justify-center text-sm" >
161- < span className = "px-2 bg-gray-50 text-gray-500" > Or</ span >
149+
150+ < div className = "mt-6 flex rounded-full bg-white/5 p-1 text-sm text-white/70" >
151+ < button
152+ type = "button"
153+ onClick = { ( ) => setIsLogin ( true ) }
154+ className = { `flex-1 rounded-full px-4 py-2 transition ${
155+ isLogin ? "bg-white text-zinc-900" : "text-white/60"
156+ } `}
157+ >
158+ Sign in
159+ </ button >
160+ < button
161+ type = "button"
162+ onClick = { ( ) => setIsLogin ( false ) }
163+ className = { `flex-1 rounded-full px-4 py-2 transition ${
164+ ! isLogin ? "bg-white text-zinc-900" : "text-white/60"
165+ } `}
166+ >
167+ Create account
168+ </ button >
162169 </ div >
163- </ div >
164170
165- < div >
166- < button
167- type = "button"
168- onClick = { handleGoogleSignIn }
169- disabled = { loading }
170- className = "group relative w-full flex justify-center py-2 px-4 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 disabled:opacity-50"
171- >
172- Sign in with Google
173- </ button >
174- </ div >
171+ < form className = "mt-8 space-y-5" onSubmit = { handleSubmit } >
172+ { error && (
173+ < div className = "rounded-2xl border border-red-500/40 bg-red-500/10 px-4 py-3 text-sm text-red-200" >
174+ { error }
175+ </ div >
176+ ) }
177+
178+ { ! isLogin && (
179+ < div className = "grid gap-4 sm:grid-cols-2" >
180+ < div >
181+ < label
182+ htmlFor = "first-name"
183+ className = "mb-2 block text-sm text-white/70"
184+ >
185+ First name
186+ </ label >
187+ < input
188+ id = "first-name"
189+ name = "firstName"
190+ type = "text"
191+ required
192+ value = { firstName }
193+ onChange = { ( e ) => setFirstName ( e . target . value ) }
194+ className = { inputClassName }
195+ placeholder = "Alex"
196+ />
197+ </ div >
198+ < div >
199+ < label
200+ htmlFor = "last-name"
201+ className = "mb-2 block text-sm text-white/70"
202+ >
203+ Last name
204+ </ label >
205+ < input
206+ id = "last-name"
207+ name = "lastName"
208+ type = "text"
209+ required
210+ value = { lastName }
211+ onChange = { ( e ) => setLastName ( e . target . value ) }
212+ className = { inputClassName }
213+ placeholder = "Choi"
214+ />
215+ </ div >
216+ </ div >
217+ ) }
175218
176- < div className = "text-center" >
177- < button
178- type = "button"
179- onClick = { ( ) => setIsLogin ( ! isLogin ) }
180- className = "text-blue-600 hover:text-blue-500 text-sm"
181- >
182- { isLogin
183- ? "Need an account? Sign up"
184- : "Already have an account? Sign in" }
185- </ button >
219+ < div className = "space-y-2" >
220+ < label
221+ htmlFor = "email-address"
222+ className = "text-sm text-white/70"
223+ >
224+ Work email
225+ </ label >
226+ < input
227+ id = "email-address"
228+ name = "email"
229+ type = "email"
230+ autoComplete = "email"
231+ required
232+ value = { email }
233+ onChange = { ( e ) => setEmail ( e . target . value ) }
234+ className = { inputClassName }
235+ 236+ />
237+ </ div >
238+
239+ < div className = "space-y-2" >
240+ < label htmlFor = "password" className = "text-sm text-white/70" >
241+ Password
242+ </ label >
243+ < input
244+ id = "password"
245+ name = "password"
246+ type = "password"
247+ autoComplete = { isLogin ? "current-password" : "new-password" }
248+ required
249+ value = { password }
250+ onChange = { ( e ) => setPassword ( e . target . value ) }
251+ className = { inputClassName }
252+ placeholder = "••••••••"
253+ />
254+ </ div >
255+
256+ < button
257+ type = "submit"
258+ disabled = { loading }
259+ className = "group flex w-full items-center justify-center gap-2 rounded-2xl bg-white px-4 py-3 text-base font-semibold text-zinc-950 transition hover:bg-zinc-100 disabled:cursor-not-allowed disabled:opacity-60"
260+ >
261+ { loading && < Loader2 className = "size-5 animate-spin" /> }
262+ { isLogin ? "Secure sign in" : "Create secure access" }
263+ </ button >
264+
265+ < div className = "flex items-center gap-3 text-sm text-white/50" >
266+ < div className = "h-px flex-1 bg-white/10" />
267+ Or continue with
268+ < div className = "h-px flex-1 bg-white/10" />
269+ </ div >
270+
271+ < button
272+ type = "button"
273+ onClick = { handleGoogleSignIn }
274+ disabled = { loading }
275+ className = "flex w-full items-center justify-center gap-2 rounded-2xl border border-white/10 bg-black/50 px-4 py-3 text-sm font-medium text-white/90 transition hover:border-white/30 hover:bg-black/60 disabled:cursor-not-allowed disabled:opacity-60"
276+ >
277+ Google Workspace
278+ </ button >
279+ </ form >
186280 </ div >
187- </ form >
281+ </ div >
188282 </ div >
189283 </ div >
190284 ) ;
0 commit comments