diff --git a/frontend/src/components/common/PasswordStrengthIndicator.jsx b/frontend/src/components/common/PasswordStrengthIndicator.jsx index 6907efc..23848bd 100644 --- a/frontend/src/components/common/PasswordStrengthIndicator.jsx +++ b/frontend/src/components/common/PasswordStrengthIndicator.jsx @@ -1,24 +1,37 @@ import { useMemo } from 'react'; +import { CheckCircle, XCircle } from 'lucide-react'; /** * Password Strength Indicator Component * Calculates and displays password strength with visual feedback + * Shows requirements based on production environment standards */ const PasswordStrengthIndicator = ({ password }) => { + const requirements = useMemo(() => { + const checks = { + minLength: password.length >= 8, + hasUppercase: /[A-Z]/.test(password), + hasLowercase: /[a-z]/.test(password), + hasNumber: /[0-9]/.test(password), + }; + + return checks; + }, [password]); + const strength = useMemo(() => { if (!password) return { score: 0, label: '', color: '' }; let score = 0; - // Length check - if (password.length >= 8) score++; - if (password.length >= 12) score++; + // Count met requirements (production standards) + if (requirements.minLength) score++; + if (requirements.hasUppercase) score++; + if (requirements.hasLowercase) score++; + if (requirements.hasNumber) score++; - // Character variety checks - if (/[a-z]/.test(password)) score++; // lowercase - if (/[A-Z]/.test(password)) score++; // uppercase - if (/[0-9]/.test(password)) score++; // numbers - if (/[^a-zA-Z0-9]/.test(password)) score++; // special chars + // Bonus points for extra length and special chars + if (password.length >= 12) score++; + if (/[^a-zA-Z0-9]/.test(password)) score++; // Determine label and color if (score <= 2) { @@ -28,7 +41,13 @@ const PasswordStrengthIndicator = ({ password }) => { } else { return { score, label: 'Strong', color: 'bg-green-500' }; } - }, [password]); + }, [password, requirements]); + + // Check if all required criteria are met + const allRequirementsMet = requirements.minLength && + requirements.hasUppercase && + requirements.hasLowercase && + requirements.hasNumber; if (!password) return null; @@ -52,17 +71,56 @@ const PasswordStrengthIndicator = ({ password }) => { style={{ width: `${widthPercentage}%` }} /> -
Password requirements:
++ Please meet all requirements above +
+ )} ); }; diff --git a/frontend/src/pages/RegisterPage.jsx b/frontend/src/pages/RegisterPage.jsx index bda9f4d..19657cc 100644 --- a/frontend/src/pages/RegisterPage.jsx +++ b/frontend/src/pages/RegisterPage.jsx @@ -174,14 +174,29 @@ const RegisterPage = () => { e.preventDefault(); setError(''); - // Validation + // Validation - passwords match if (formData.password !== formData.confirmPassword) { setError('Passwords do not match'); return; } + // Validation - password requirements (production standards) + const passwordErrors = []; if (formData.password.length < 8) { - setError('Password must be at least 8 characters long'); + passwordErrors.push('at least 8 characters'); + } + if (!/[A-Z]/.test(formData.password)) { + passwordErrors.push('one uppercase letter'); + } + if (!/[a-z]/.test(formData.password)) { + passwordErrors.push('one lowercase letter'); + } + if (!/[0-9]/.test(formData.password)) { + passwordErrors.push('one number'); + } + + if (passwordErrors.length > 0) { + setError(`Password must contain ${passwordErrors.join(', ')}`); return; }