Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 56s
94 lines
2.7 KiB
TypeScript
94 lines
2.7 KiB
TypeScript
// src/pages/admin/components/PasswordStrengthIndicator.tsx
|
|
// src/components/PasswordStrengthIndicator.tsx
|
|
import React from 'react';
|
|
import zxcvbn from 'zxcvbn';
|
|
|
|
interface PasswordStrengthIndicatorProps {
|
|
password?: string;
|
|
}
|
|
|
|
/**
|
|
* A component that visually indicates the strength of a password using zxcvbn.
|
|
* It displays a colored bar and provides feedback to the user.
|
|
*/
|
|
export const PasswordStrengthIndicator: React.FC<PasswordStrengthIndicatorProps> = ({
|
|
password = '',
|
|
}) => {
|
|
const result = zxcvbn(password);
|
|
const score = result.score; // Score from 0 (worst) to 4 (best)
|
|
|
|
// Function to determine the color of each segment of the strength bar
|
|
const getBarColor = (index: number) => {
|
|
if (password.length === 0) return 'bg-gray-200 dark:bg-gray-600';
|
|
if (index > score) return 'bg-gray-200 dark:bg-gray-600';
|
|
switch (score) {
|
|
case 0:
|
|
return 'bg-red-500';
|
|
case 1:
|
|
return 'bg-red-500';
|
|
case 2:
|
|
return 'bg-orange-500';
|
|
case 3:
|
|
return 'bg-yellow-500';
|
|
case 4:
|
|
return 'bg-green-500';
|
|
default:
|
|
return 'bg-gray-200 dark:bg-gray-600';
|
|
}
|
|
};
|
|
|
|
// Function to get a human-readable strength label
|
|
const getStrengthLabel = () => {
|
|
switch (score) {
|
|
case 0:
|
|
return 'Very Weak';
|
|
case 1:
|
|
return 'Weak';
|
|
case 2:
|
|
return 'Fair';
|
|
case 3:
|
|
return 'Good';
|
|
case 4:
|
|
return 'Strong';
|
|
default:
|
|
return '';
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="mt-2 space-y-1">
|
|
<div className="flex space-x-1">
|
|
{/* Create 5 segments for the strength bar */}
|
|
{Array.from(Array(5).keys()).map((index) => (
|
|
<div
|
|
key={index}
|
|
className={`h-1.5 flex-1 rounded-full ${getBarColor(index)} transition-colors`}
|
|
></div>
|
|
))}
|
|
</div>
|
|
{password.length > 0 && (
|
|
<div className="flex justify-between items-center text-xs">
|
|
<span
|
|
className={`font-bold ${
|
|
score < 2 ? 'text-red-500' : score < 3 ? 'text-orange-500' : 'text-green-500'
|
|
}`}
|
|
>
|
|
{getStrengthLabel()}
|
|
</span>
|
|
{/* Display feedback from zxcvbn if available */}
|
|
{(result.feedback.warning || result.feedback.suggestions.length > 0) && (
|
|
<span className="text-gray-500 dark:text-gray-400 text-right">
|
|
{/* Prioritize the warning over suggestions. */}
|
|
{result.feedback.warning ? (
|
|
<span>{result.feedback.warning}</span>
|
|
) : (
|
|
<span>{result.feedback.suggestions[0]}</span>
|
|
)}
|
|
</span>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|