33import { useState } from 'react' ;
44import { useRouter } from 'next/navigation' ;
55import { Button } from '@/components/ui/button' ;
6- import {
7- Card ,
8- CardContent ,
9- CardDescription ,
10- CardHeader ,
11- CardTitle ,
12- } from '@/components/ui/card' ;
136import { Input } from '@/components/ui/input' ;
147import { login } from '@/lib/auth' ;
158
@@ -26,7 +19,7 @@ export default function LoginPage() {
2619 setLoading ( true ) ;
2720 try {
2821 await login ( { email, password } ) ;
29- router . push ( '/analyses ' ) ;
22+ router . push ( '/projects ' ) ;
3023 } catch ( err : unknown ) {
3124 setError ( err instanceof Error ? err . message : 'Login failed' ) ;
3225 } finally {
@@ -35,55 +28,126 @@ export default function LoginPage() {
3528 }
3629
3730 return (
38- < div className = "flex min-h-[calc(100vh-8rem)] items-center justify-center px-4" >
39- < Card className = "w-full max-w-sm" >
40- < CardHeader >
41- < CardTitle > Sign in</ CardTitle >
42- < CardDescription > Enter your email and password to continue.</ CardDescription >
43- </ CardHeader >
44- < CardContent >
45- < form onSubmit = { handleSubmit } className = "space-y-4" >
46- < div className = "space-y-1" >
47- < label htmlFor = "email" className = "text-sm font-medium" >
48- Email
49- </ label >
50- < Input
51- id = "email"
52- type = "email"
53- autoComplete = "email"
54- required
55- value = { email }
56- onChange = { ( e ) => setEmail ( e . target . value ) }
57- />
31+ < div className = "flex min-h-screen" >
32+ { /* Left brand panel */ }
33+ < div className = "hidden lg:flex lg:w-1/2 bg-gradient-to-br from-[#3C5488] via-[#4DBBD5] to-[#00A087] items-center justify-center p-12" >
34+ < div className = "max-w-md text-white" >
35+ < div className = "flex items-center gap-3 mb-8" >
36+ < div className = "w-12 h-12 rounded-xl bg-white/20 backdrop-blur flex items-center justify-center text-2xl font-bold" >
37+ M
5838 </ div >
59- < div className = "space-y-1" >
60- < label htmlFor = "password" className = "text-sm font-medium" >
61- Password
62- </ label >
63- < Input
64- id = "password"
65- type = "password"
66- autoComplete = "current-password"
67- required
68- value = { password }
69- onChange = { ( e ) => setPassword ( e . target . value ) }
70- />
39+ < span className = "text-3xl font-bold tracking-tight" > MetaboFlow</ span >
40+ </ div >
41+ < h2 className = "text-2xl font-semibold mb-4" >
42+ Multi-Engine Metabolomics Analysis Platform
43+ </ h2 >
44+ < p className = "text-white/80 text-lg leading-relaxed mb-8" >
45+ From raw mzML to publication-ready figures in one workflow.
46+ 50 chart templates, automated reports, and multi-engine comparison.
47+ </ p >
48+ < div className = "space-y-3 text-white/70" >
49+ < div className = "flex items-center gap-3" >
50+ < svg className = "w-5 h-5 text-white/90" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
51+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
52+ </ svg >
53+ < span > XCMS + MZmine + MS-DIAL engine support</ span >
54+ </ div >
55+ < div className = "flex items-center gap-3" >
56+ < svg className = "w-5 h-5 text-white/90" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
57+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
58+ </ svg >
59+ < span > Nature-grade figures with one click</ span >
60+ </ div >
61+ < div className = "flex items-center gap-3" >
62+ < svg className = "w-5 h-5 text-white/90" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
63+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
64+ </ svg >
65+ < span > MFSL spectral library: 960K compounds</ span >
66+ </ div >
67+ < div className = "flex items-center gap-3" >
68+ < svg className = "w-5 h-5 text-white/90" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
69+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
70+ </ svg >
71+ < span > PDF & Word reports with auto Methods</ span >
72+ </ div >
73+ </ div >
74+ </ div >
75+ </ div >
76+
77+ { /* Right form panel */ }
78+ < div className = "flex w-full lg:w-1/2 items-center justify-center p-8 bg-gray-50" >
79+ < div className = "w-full max-w-md" >
80+ { /* Mobile logo */ }
81+ < div className = "lg:hidden flex items-center gap-2 mb-8 justify-center" >
82+ < div className = "w-10 h-10 rounded-lg bg-[#3C5488] flex items-center justify-center text-white text-xl font-bold" >
83+ M
7184 </ div >
72- { error && (
73- < p className = "text-sm text-destructive" > { error } </ p >
74- ) }
75- < Button type = "submit" className = "w-full" disabled = { loading } >
76- { loading ? 'Signing in…' : 'Sign in' }
77- </ Button >
78- </ form >
79- < p className = "mt-4 text-center text-sm text-muted-foreground" >
80- Don't have an account?{ ' ' }
81- < a href = "/register" className = "underline underline-offset-4 hover:text-foreground" >
82- Register
83- </ a >
85+ < span className = "text-2xl font-bold text-gray-900" > MetaboFlow</ span >
86+ </ div >
87+
88+ < div className = "bg-white rounded-2xl shadow-sm border border-gray-100 p-8" >
89+ < h1 className = "text-2xl font-bold text-gray-900 mb-1" > Welcome back</ h1 >
90+ < p className = "text-gray-500 mb-6" > Sign in to your account to continue.</ p >
91+
92+ < form onSubmit = { handleSubmit } className = "space-y-5" >
93+ < div className = "space-y-1.5" >
94+ < label htmlFor = "email" className = "text-sm font-medium text-gray-700" >
95+ Email
96+ </ label >
97+ < Input
98+ id = "email"
99+ type = "email"
100+ autoComplete = "email"
101+ required
102+ placeholder = "you@lab.edu"
103+ className = "h-11 bg-gray-50 border-gray-200 focus:bg-white"
104+ value = { email }
105+ onChange = { ( e ) => setEmail ( e . target . value ) }
106+ />
107+ </ div >
108+ < div className = "space-y-1.5" >
109+ < label htmlFor = "password" className = "text-sm font-medium text-gray-700" >
110+ Password
111+ </ label >
112+ < Input
113+ id = "password"
114+ type = "password"
115+ autoComplete = "current-password"
116+ required
117+ className = "h-11 bg-gray-50 border-gray-200 focus:bg-white"
118+ value = { password }
119+ onChange = { ( e ) => setPassword ( e . target . value ) }
120+ />
121+ </ div >
122+ { error && (
123+ < div className = "bg-red-50 text-red-700 text-sm px-4 py-2.5 rounded-lg border border-red-100" >
124+ { error }
125+ </ div >
126+ ) }
127+ < Button
128+ type = "submit"
129+ className = "w-full h-11 bg-[#3C5488] hover:bg-[#2d3f66] text-white font-medium"
130+ disabled = { loading }
131+ >
132+ { loading ? 'Signing in...' : 'Sign in' }
133+ </ Button >
134+ </ form >
135+
136+ < div className = "mt-6 text-center" >
137+ < p className = "text-sm text-gray-500" >
138+ Don't have an account?{ ' ' }
139+ < a href = "/register" className = "text-[#3C5488] font-medium hover:underline" >
140+ Request access
141+ </ a >
142+ </ p >
143+ </ div >
144+ </ div >
145+
146+ < p className = "mt-6 text-center text-xs text-gray-400" >
147+ MetaboFlow v0.1.0 Beta — Invite-only access
84148 </ p >
85- </ CardContent >
86- </ Card >
149+ </ div >
150+ </ div >
87151 </ div >
88152 ) ;
89153}
0 commit comments