password complexity indicator
This commit is contained in:
@@ -67,6 +67,7 @@ export default function LoginView({ onSignup }: { onSignup: () => void }) {
|
||||
</div>
|
||||
<div className="flex py-2 px-1 justify-between">
|
||||
<Checkbox
|
||||
isDisabled
|
||||
classNames={{
|
||||
label: "text-small",
|
||||
}}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Card } from "@heroui/react";
|
||||
import React from "react";
|
||||
|
||||
interface PasswordComplexityIndicatorProps {
|
||||
password: string;
|
||||
}
|
||||
|
||||
const checkCriteria = (password: string) => ({
|
||||
isLongEnough: password.length >= 12,
|
||||
hasLowercase: /[a-z]/.test(password),
|
||||
hasUppercase: /[A-Z]/.test(password),
|
||||
hasNumber: /\d/.test(password),
|
||||
hasSpecialChar: /[^A-Za-z\d]/.test(password),
|
||||
});
|
||||
|
||||
// Dot indicator component
|
||||
const DotIndicator = ({ met }: { met: boolean }) => (
|
||||
<span
|
||||
className={`w-3 h-3 rounded-full ${met ? "bg-green-500" : "bg-red-500"}`}
|
||||
></span>
|
||||
);
|
||||
|
||||
// List item component
|
||||
const CriteriaItem = ({ label, met }: { label: string; met: boolean }) => (
|
||||
<div className="flex items-center gap-2">
|
||||
<DotIndicator met={met} />
|
||||
<span className="text-sm opacity-50">{label}</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
// Main password complexity component
|
||||
const PasswordComplexityIndicator: React.FC<
|
||||
PasswordComplexityIndicatorProps
|
||||
> = ({ password }) => {
|
||||
const criteria = checkCriteria(password);
|
||||
|
||||
const criteriaList = [
|
||||
{ label: "12 characters", met: criteria.isLongEnough },
|
||||
{ label: "Lowercase", met: criteria.hasLowercase },
|
||||
{ label: "Uppercase", met: criteria.hasUppercase },
|
||||
{ label: "Number", met: criteria.hasNumber },
|
||||
{ label: "Special character", met: criteria.hasSpecialChar },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card radius="sm" className="p-4 bg-neutral-500/10">
|
||||
<div className="grid grid-cols-2">
|
||||
{criteriaList.map((criterion, index) => (
|
||||
<CriteriaItem
|
||||
key={index}
|
||||
label={criterion.label}
|
||||
met={criterion.met}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default PasswordComplexityIndicator;
|
||||
@@ -3,6 +3,7 @@ import { IconMail, IconLock } from "@tabler/icons-react";
|
||||
import { useState } from "react";
|
||||
import { toast } from "react-toastify";
|
||||
import http, { login } from "../http";
|
||||
import PasswordComplexityIndicator from "./PasswordComplexityIndicator";
|
||||
|
||||
export const validatePassword = (password: string): boolean => {
|
||||
const passwordComplexityRegex =
|
||||
@@ -108,26 +109,30 @@ export default function SignupView({
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-row gap-2">
|
||||
<Input
|
||||
size="sm"
|
||||
label="First name"
|
||||
value={firstName}
|
||||
onValueChange={setFirstName}
|
||||
/>
|
||||
<Input
|
||||
size="sm"
|
||||
label="Last name"
|
||||
value={lastName}
|
||||
onValueChange={setLastName}
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
size="sm"
|
||||
endContent={<IconMail />}
|
||||
label="Email"
|
||||
type="email"
|
||||
value={emailValue}
|
||||
onValueChange={setEmailValue}
|
||||
/>
|
||||
<Input label="NRIC" value={nric} onValueChange={setNric} />
|
||||
<Input size="sm" label="NRIC" value={nric} onValueChange={setNric} />
|
||||
<div className="flex flex-row gap-2">
|
||||
<Select
|
||||
size="sm"
|
||||
label="Gender"
|
||||
selectedKeys={[gender]}
|
||||
onChange={(e) => {
|
||||
@@ -139,12 +144,13 @@ export default function SignupView({
|
||||
</Select>
|
||||
<input
|
||||
type="date"
|
||||
className="rounded-xl px-4 transition-colors dark:bg-neutral-800 dark:hover:bg-neutral-700"
|
||||
className="rounded-lg px-4 transition-colors dark:bg-neutral-800 dark:hover:bg-neutral-700"
|
||||
value={dateOfBirth}
|
||||
onChange={(e) => setDateOfBirth(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
size="sm"
|
||||
endContent={<IconLock />}
|
||||
label="Password"
|
||||
type="password"
|
||||
@@ -152,12 +158,14 @@ export default function SignupView({
|
||||
onValueChange={setPassword}
|
||||
/>
|
||||
<Input
|
||||
size="sm"
|
||||
endContent={<IconLock />}
|
||||
label="Confirm password"
|
||||
type="password"
|
||||
value={confirmPassword}
|
||||
onValueChange={setConfirmPassword}
|
||||
/>
|
||||
<PasswordComplexityIndicator password={password} />
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 w-full">
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user