Skip to content

Commit 848023e

Browse files
committed
Add interactive password requirements popup for Signup and Reset Password pages
- Create floating password requirements component that appears to the right of password fields - Auto-hide requirements box after 1 second when all required criteria are met - Display real-time validation with checkmarks and X marks for each requirement - Apply to both Signup and Reset Password pages for consistent UX - Remove static password requirements boxes in favor of dynamic popup
1 parent ce31587 commit 848023e

3 files changed

Lines changed: 30 additions & 17 deletions

File tree

packages/web/src/components/PasswordRequirements.tsx

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { Check, X } from 'lucide-react';
2+
import { useState, useEffect } from 'react';
23

34
interface PasswordRequirementsProps {
45
password: string;
56
showAll?: boolean;
67
}
78

89
export function PasswordRequirements({ password, showAll = false }: PasswordRequirementsProps) {
10+
const [showBox, setShowBox] = useState(true);
11+
912
const requirements = [
1013
{
1114
label: '8+ characters',
@@ -35,11 +38,27 @@ export function PasswordRequirements({ password, showAll = false }: PasswordRequ
3538
}
3639
];
3740

38-
if (!password && !showAll) return null;
41+
const allRequiredMet = requirements
42+
.filter(req => !req.optional)
43+
.every(req => req.met);
44+
45+
useEffect(() => {
46+
if (allRequiredMet && password) {
47+
const timer = setTimeout(() => {
48+
setShowBox(false);
49+
}, 1000);
50+
return () => clearTimeout(timer);
51+
} else if (password) {
52+
setShowBox(true);
53+
}
54+
}, [allRequiredMet, password]);
55+
56+
if (!password) return null;
57+
if (!showBox) return null;
3958

4059
return (
41-
<div className="mt-2 p-3 bg-gray-900/50 border border-gray-600/50 rounded-lg">
42-
<p className="text-xs font-medium text-gray-300 mb-2">Password Requirements:</p>
60+
<div className="absolute left-full ml-4 top-0 w-56 p-3 bg-gray-800/95 backdrop-blur-xl border border-gray-700/50 rounded-xl shadow-2xl z-50">
61+
<p className="text-xs font-semibold text-gray-300 mb-2">Password Requirements</p>
4362
<ul className="space-y-1.5">
4463
{requirements.map((req, index) => (
4564
<li key={index} className="flex items-center space-x-2 text-xs">
@@ -53,9 +72,9 @@ export function PasswordRequirements({ password, showAll = false }: PasswordRequ
5372
<div className="h-3.5 w-3.5 rounded-full border border-gray-500 flex-shrink-0" />
5473
)}
5574
<span className={`${
56-
password
57-
? req.met
58-
? 'text-teal-400'
75+
password
76+
? req.met
77+
? 'text-teal-400'
5978
: 'text-gray-400'
6079
: 'text-gray-400'
6180
}`}>

packages/web/src/pages/ResetPassword.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useState, useEffect } from 'react';
22
import { useSearchParams, useNavigate, Link } from 'react-router-dom';
33
import { Lock, Eye, EyeOff, CheckCircle, XCircle } from 'lucide-react';
44
import { TlsStatusIndicator } from '../components/TlsStatusIndicator';
5+
import { PasswordRequirements } from '../components/PasswordRequirements';
56
import { validatePassword, getPasswordStrength } from '../utils/validation';
67

78
export function ResetPassword() {
@@ -99,7 +100,7 @@ export function ResetPassword() {
99100
</div>
100101
) : (
101102
<form onSubmit={handleSubmit} className="space-y-5">
102-
<div>
103+
<div className="relative">
103104
<label htmlFor="password" className="block text-sm font-medium text-gray-300 mb-1">
104105
New Password
105106
</label>
@@ -149,6 +150,8 @@ export function ResetPassword() {
149150
</div>
150151
</div>
151152
)}
153+
154+
<PasswordRequirements password={password} />
152155
</div>
153156

154157
<div>
@@ -212,15 +215,6 @@ export function ResetPassword() {
212215
)}
213216
</div>
214217

215-
<div className="p-3 bg-blue-900/20 border border-blue-500/30 rounded-lg">
216-
<p className="text-xs text-blue-300 font-semibold mb-2">Password Requirements:</p>
217-
<ul className="text-xs text-blue-300/80 space-y-1">
218-
<li>• At least 8 characters long</li>
219-
<li>• Contains uppercase and lowercase letters</li>
220-
<li>• Contains at least one number</li>
221-
</ul>
222-
</div>
223-
224218
<button
225219
type="submit"
226220
disabled={loading}

packages/web/src/pages/Signup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ export function Signup() {
492492
</div>
493493

494494
{/* Password Field */}
495-
<div>
495+
<div className="relative">
496496
<label htmlFor="password" className="block text-sm font-medium text-gray-300 mb-1">
497497
Password
498498
</label>

0 commit comments

Comments
 (0)