Skip to content

Commit ed8d1e7

Browse files
committed
feat: add password strength indicator and enhance registration form UI
1 parent 1872ba9 commit ed8d1e7

2 files changed

Lines changed: 276 additions & 126 deletions

File tree

frontend/src/pages/Login.tsx

Lines changed: 112 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { GoogleLogin } from '@react-oauth/google';
44
import { useAuth } from '../context/AuthContext';
55
import { Button } from '../components/ui/button';
66
import { Input } from '../components/ui/input';
7-
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '../components/ui/card';
8-
import { Lock, ArrowRight, Mail, Loader2 } from 'lucide-react';
7+
import { Lock, Mail, Loader2, Eye, EyeOff, ArrowRight } from 'lucide-react';
98
import { toast } from 'sonner';
109

1110
export function Login() {
1211
const [email, setEmail] = useState('');
1312
const [password, setPassword] = useState('');
13+
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
1414
const [isLoading, setIsLoading] = useState(false);
1515
const [error, setError] = useState('');
1616
const { login, loginAsGuest, googleLogin } = useAuth();
@@ -50,110 +50,163 @@ export function Login() {
5050
};
5151

5252
return (
53-
<div className="min-h-[100dvh] flex items-center justify-center bg-background px-4 relative overflow-hidden">
54-
<Card className="w-full max-w-md border-primary/10 shadow-xl bg-card/50 backdrop-blur-sm relative z-10">
55-
<CardHeader className="space-y-1 text-center">
56-
<div className="mx-auto w-12 h-12 bg-primary/10 rounded-full flex items-center justify-center mb-2">
57-
<Lock className="w-6 h-6 text-primary" />
53+
<div className="flex h-[100dvh] w-full bg-white">
54+
{/* Left side - Image (hidden on mobile) */}
55+
<div className="w-full hidden md:flex items-center justify-center bg-gray-50">
56+
<img
57+
className="w-full h-full object-cover"
58+
src="https://images.unsplash.com/photo-1484480974693-6ca0a78fb36b?w=600&h=800&fit=crop"
59+
alt="Focus and productivity"
60+
/>
61+
</div>
62+
63+
{/* Right side - Form */}
64+
<div className="w-full flex flex-col items-center justify-center px-6 md:px-0">
65+
<div className="w-full md:w-96 max-w-md">
66+
{/* Header */}
67+
<div className="mb-8">
68+
<h1 className="text-3xl font-bold text-gray-900">Welcome back</h1>
69+
<p className="text-sm text-gray-600 mt-2">Sign in to your account to continue</p>
5870
</div>
59-
<CardTitle className="text-2xl font-bold">Welcome back</CardTitle>
60-
<CardDescription>Enter your email to sign in to your account</CardDescription>
61-
</CardHeader>
62-
<CardContent>
71+
72+
{/* Error Message */}
6373
{error && (
64-
<div className="mb-4 p-3 rounded-lg bg-destructive/10 border border-destructive/20 text-destructive text-sm font-medium text-center">
74+
<div className="mb-4 p-4 rounded-lg bg-red-50 border border-red-200 text-red-700 text-sm">
6575
{error}
6676
</div>
6777
)}
78+
79+
{/* Google Login Button */}
80+
<div className="flex justify-center mb-6">
81+
<GoogleLogin
82+
onSuccess={(credentialResponse) => {
83+
if (credentialResponse.credential) {
84+
googleLogin(credentialResponse.credential);
85+
navigate('/dashboard');
86+
}
87+
}}
88+
onError={() => {
89+
setError('Google Login Failed');
90+
}}
91+
useOneTap
92+
/>
93+
</div>
94+
95+
{/* Divider */}
96+
<div className="flex items-center gap-3 mb-6">
97+
<div className="flex-1 h-px bg-gray-200"></div>
98+
<span className="text-xs text-gray-500">or sign in with email</span>
99+
<div className="flex-1 h-px bg-gray-200"></div>
100+
</div>
101+
102+
{/* Form */}
68103
<form onSubmit={handleSubmit} className="space-y-4">
69-
<div className="space-y-2">
104+
{/* Email Field */}
105+
<div>
106+
<label htmlFor="email" className="block text-sm font-medium text-gray-700 mb-2">
107+
Email
108+
</label>
70109
<div className="relative">
71-
<Mail className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
110+
<Mail className="absolute left-3 top-3 h-4 w-4 text-gray-400" />
72111
<Input
112+
id="email"
73113
type="email"
74-
placeholder="name@gmail.com"
75-
className="pl-9 text-base md:text-sm h-12 md:h-10 transition-all font-medium border-primary/20 bg-background/50 hover:bg-background/80 focus:bg-background"
114+
placeholder="name@example.com"
115+
className="pl-10 h-11 border border-gray-300 bg-white text-gray-900 placeholder:text-gray-500 focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
76116
value={email}
77117
onChange={(e) => setEmail(e.target.value)}
78118
disabled={isLoading}
79119
/>
80120
</div>
81121
</div>
82-
<div className="space-y-2">
122+
123+
{/* Password Field */}
124+
<div>
125+
<label htmlFor="password" className="block text-sm font-medium text-gray-700 mb-2">
126+
Password
127+
</label>
83128
<div className="relative">
84-
<Lock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
129+
<Lock className="absolute left-3 top-3 h-4 w-4 text-gray-400" />
85130
<Input
86-
type="password"
87-
placeholder="Password"
88-
className="pl-9 text-base md:text-sm h-12 md:h-10 transition-all font-medium border-primary/20 bg-background/50 hover:bg-background/80 focus:bg-background"
131+
id="password"
132+
type={isPasswordVisible ? 'text' : 'password'}
133+
placeholder="••••••••"
134+
className="pl-10 pr-10 h-11 border border-gray-300 bg-white text-gray-900 placeholder:text-gray-500 focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
89135
value={password}
90136
onChange={(e) => setPassword(e.target.value)}
91137
disabled={isLoading}
92138
/>
139+
<button
140+
type="button"
141+
onClick={() => setIsPasswordVisible(!isPasswordVisible)}
142+
className="absolute right-3 top-3 text-gray-400 hover:text-gray-600"
143+
tabIndex={-1}
144+
>
145+
{isPasswordVisible ? (
146+
<EyeOff className="h-4 w-4" />
147+
) : (
148+
<Eye className="h-4 w-4" />
149+
)}
150+
</button>
93151
</div>
94152
</div>
95153

96-
<Button
154+
{/* Remember & Forgot */}
155+
<div className="flex items-center justify-between pt-2">
156+
<label className="flex items-center gap-2 cursor-pointer">
157+
<input
158+
type="checkbox"
159+
className="w-4 h-4 border border-gray-300 rounded focus:ring-blue-500"
160+
/>
161+
<span className="text-sm text-gray-600">Remember me</span>
162+
</label>
163+
<a href="#" className="text-sm text-blue-600 hover:text-blue-700">
164+
Forgot password?
165+
</a>
166+
</div>
167+
168+
{/* Sign In Button */}
169+
<button
97170
type="submit"
98-
className="w-full h-12 md:h-10 text-base md:text-sm font-semibold shadow-lg border-dashed border-2 hover:border-solid hover:border-purple-500/50 shadow-primary/20 hover:shadow-primary/40 transition-all duration-300"
171+
className="w-full h-11 mt-6 bg-blue-600 text-white font-medium rounded-lg hover:bg-blue-700 transition-colors flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
99172
disabled={isLoading}
100173
>
101174
{isLoading ? (
102175
<>
103-
<Loader2 className="mr-2 h-4 w-4 animate-spin" /> Signing in...
176+
<Loader2 className="h-4 w-4 animate-spin" />
177+
Signing in...
104178
</>
105179
) : (
106180
<>
107-
Sign In <ArrowRight className="ml-2 h-4 w-4" />
181+
Sign In
182+
<ArrowRight className="h-4 w-4" />
108183
</>
109184
)}
110-
</Button>
111-
112-
<div className="relative my-4">
113-
<div className="absolute inset-0 flex items-center">
114-
<span className="w-full border-t" />
115-
</div>
116-
<div className="relative flex justify-center text-xs uppercase">
117-
<span className="bg-background px-2 text-muted-foreground">Or continue with</span>
118-
</div>
119-
</div>
120-
121-
<div className="flex justify-center mb-4">
122-
<GoogleLogin
123-
onSuccess={(credentialResponse) => {
124-
if (credentialResponse.credential) {
125-
googleLogin(credentialResponse.credential);
126-
navigate('/dashboard');
127-
}
128-
}}
129-
onError={() => {
130-
setError('Google Login Failed');
131-
}}
132-
useOneTap
133-
/>
134-
</div>
185+
</button>
135186

136-
<Button
187+
{/* Guest Login */}
188+
<button
137189
type="button"
138-
variant="outline"
139-
className="w-full h-12 md:h-10 border-dashed border-2 hover:border-solid hover:border-purple-500/50 hover:bg-secondary/50 text-base md:text-sm"
190+
className="w-full h-11 border border-gray-300 text-gray-700 font-medium rounded-lg hover:bg-gray-50 transition-colors"
140191
onClick={() => {
141192
loginAsGuest();
142193
navigate('/dashboard');
143194
}}
195+
disabled={isLoading}
144196
>
145197
Continue as Guest
146-
</Button>
198+
</button>
147199
</form>
148200

149-
<div className="mt-6 text-center text-sm text-muted-foreground">
201+
{/* Sign Up Link */}
202+
<p className="text-center text-sm text-gray-600 mt-6">
150203
Don't have an account?{' '}
151-
<Link to="/register" className="text-primary hover:underline font-medium">
204+
<Link to="/register" className="text-blue-600 hover:text-blue-700 font-medium">
152205
Sign up
153206
</Link>
154-
</div>
155-
</CardContent>
156-
</Card>
207+
</p>
208+
</div>
209+
</div>
157210
</div>
158211
);
159212
}

0 commit comments

Comments
 (0)