Files
flyer-crawler.projectium.com/src/components/PasswordStrengthIndicator.tsx

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>
);
};