2025-12-03 21:56:50 +00:00
|
|
|
interface PasswordStrengthIndicatorProps {
|
|
|
|
|
password: string;
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-13 02:34:34 +00:00
|
|
|
export function PasswordStrengthIndicator({
|
|
|
|
|
password,
|
|
|
|
|
}: PasswordStrengthIndicatorProps) {
|
|
|
|
|
const getStrength = (
|
|
|
|
|
pwd: string,
|
|
|
|
|
): {
|
|
|
|
|
level: number;
|
|
|
|
|
label: string;
|
|
|
|
|
color: string;
|
|
|
|
|
requirements: string[];
|
|
|
|
|
} => {
|
2025-12-03 21:56:50 +00:00
|
|
|
const requirements: string[] = [];
|
|
|
|
|
let strength = 0;
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
// Minimum 12 caractères (requis)
|
|
|
|
|
if (pwd.length >= 12) {
|
|
|
|
|
strength++;
|
|
|
|
|
} else {
|
|
|
|
|
requirements.push(`Au moins 12 caractères (${pwd.length}/12)`);
|
|
|
|
|
}
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
// Majuscule et minuscule
|
|
|
|
|
if (/[a-z]/.test(pwd) && /[A-Z]/.test(pwd)) {
|
|
|
|
|
strength++;
|
|
|
|
|
} else {
|
|
|
|
|
if (!/[a-z]/.test(pwd)) requirements.push('Une minuscule');
|
|
|
|
|
if (!/[A-Z]/.test(pwd)) requirements.push('Une majuscule');
|
|
|
|
|
}
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
// Chiffre
|
|
|
|
|
if (/\d/.test(pwd)) {
|
|
|
|
|
strength++;
|
|
|
|
|
} else {
|
|
|
|
|
requirements.push('Un chiffre');
|
|
|
|
|
}
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
// Caractère spécial
|
|
|
|
|
if (/[^a-zA-Z\d]/.test(pwd)) {
|
|
|
|
|
strength++;
|
|
|
|
|
} else {
|
|
|
|
|
requirements.push('Un caractère spécial (!@#$%^&*...)');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let label: string;
|
|
|
|
|
let color: string;
|
|
|
|
|
if (strength <= 1) {
|
|
|
|
|
label = 'Très faible';
|
2026-01-16 00:56:47 +00:00
|
|
|
color = 'bg-kodo-red';
|
2025-12-03 21:56:50 +00:00
|
|
|
} else if (strength === 2) {
|
|
|
|
|
label = 'Faible';
|
2026-01-16 00:59:31 +00:00
|
|
|
color = 'bg-kodo-gold';
|
2025-12-03 21:56:50 +00:00
|
|
|
} else if (strength === 3) {
|
|
|
|
|
label = 'Moyen';
|
2026-01-16 00:59:31 +00:00
|
|
|
color = 'bg-kodo-gold';
|
2025-12-03 21:56:50 +00:00
|
|
|
} else if (strength === 4) {
|
|
|
|
|
label = 'Fort';
|
2026-01-16 00:56:47 +00:00
|
|
|
color = 'bg-kodo-lime/100';
|
2025-12-03 21:56:50 +00:00
|
|
|
} else {
|
|
|
|
|
label = 'Très fort';
|
2026-01-16 00:59:31 +00:00
|
|
|
color = 'bg-kodo-lime';
|
2025-12-03 21:56:50 +00:00
|
|
|
}
|
2025-12-13 02:34:34 +00:00
|
|
|
|
2025-12-03 21:56:50 +00:00
|
|
|
return { level: strength, label, color, requirements };
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (!password) return null;
|
|
|
|
|
|
|
|
|
|
const { level, label, color, requirements } = getStrength(password);
|
|
|
|
|
const width = (level / 4) * 100;
|
|
|
|
|
|
|
|
|
|
return (
|
2025-12-13 02:34:34 +00:00
|
|
|
<div
|
|
|
|
|
className="mt-2 space-y-2"
|
|
|
|
|
role="status"
|
|
|
|
|
aria-live="polite"
|
|
|
|
|
aria-atomic="true"
|
|
|
|
|
>
|
2025-12-03 21:56:50 +00:00
|
|
|
<div>
|
2025-12-13 02:34:34 +00:00
|
|
|
<div
|
2026-01-16 00:56:47 +00:00
|
|
|
className="w-full bg-kodo-slate rounded-full h-2"
|
2025-12-03 21:56:50 +00:00
|
|
|
role="progressbar"
|
|
|
|
|
aria-valuenow={level}
|
|
|
|
|
aria-valuemin={0}
|
|
|
|
|
aria-valuemax={4}
|
|
|
|
|
aria-label={`Force du mot de passe: ${label}`}
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
className={`${color} h-2 rounded-full transition-all`}
|
|
|
|
|
style={{ width: `${width}%` }}
|
|
|
|
|
aria-hidden="true"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2026-01-16 00:56:47 +00:00
|
|
|
<p className="text-xs text-kodo-content-dim mt-1" id="password-strength-label">
|
2025-12-03 21:56:50 +00:00
|
|
|
Force: <span aria-live="polite">{label}</span>
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
{requirements.length > 0 && (
|
2026-01-16 00:56:47 +00:00
|
|
|
<div className="text-xs text-kodo-content-dim">
|
2025-12-03 21:56:50 +00:00
|
|
|
<p className="font-medium mb-1">Requis :</p>
|
|
|
|
|
<ul className="list-disc list-inside space-y-0.5">
|
|
|
|
|
{requirements.map((req, index) => (
|
2026-01-16 00:56:47 +00:00
|
|
|
<li key={index} className="text-kodo-red">
|
2025-12-13 02:34:34 +00:00
|
|
|
{req}
|
|
|
|
|
</li>
|
2025-12-03 21:56:50 +00:00
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|