From cdccac1c87b941117dc99b402380bc5c8b308244 Mon Sep 17 00:00:00 2001 From: Li Ying Kwa Date: Tue, 17 Oct 2023 17:59:08 +0800 Subject: [PATCH] Implement password validator new design --- .../components/registration-form.tsx | 96 +++++++++++++++++-- src/utilities/validators.ts | 19 +++- 2 files changed, 106 insertions(+), 9 deletions(-) diff --git a/src/features/registration/components/registration-form.tsx b/src/features/registration/components/registration-form.tsx index 405e795..1585f88 100644 --- a/src/features/registration/components/registration-form.tsx +++ b/src/features/registration/components/registration-form.tsx @@ -6,6 +6,9 @@ import { Text, VStack, Input, + Center, + Icon, + HStack, } from "@chakra-ui/react"; import { ViewIcon, ViewOffIcon } from "@chakra-ui/icons"; import { useState } from "react"; @@ -15,8 +18,13 @@ import { // DoPasswordsMatch, IsValidEmail, IsValidName, + PasswordContainsLowercase, + PasswordContainsNumber, + PasswordContainsSymbol, + PasswordContainsUppercase, } from "../../../utilities/validators"; import SignIn from "./sign-in"; +import { ImCheckboxChecked, ImCross } from 'react-icons/im' export default function RegistrationForm() { const [input, setInput] = useState({ @@ -31,7 +39,7 @@ export default function RegistrationForm() { givenName: "", famName: "", email: "", - password: "", + password: { text: "", numChecked: 0, color: "", checks: { "Minimum length": false, "Number": false, "Symbol": false, "Uppercase": false, "Lowercase": false } }, confirmPassword: "", valid: false, }); @@ -63,7 +71,12 @@ export default function RegistrationForm() { const validateInput = (event: any) => { let { name, value } = event.target; setError((prev) => { - const errorState = { ...prev, [name]: "" }; + let errorState; + if (name == "password") { + errorState = { ...prev } + } else { + errorState = { ...prev, [name]: "" }; + } errorState.valid = canEnableSignUpButton(); switch (name) { @@ -90,12 +103,65 @@ export default function RegistrationForm() { // case "confirmPassword": setNoText(typeof value != "undefined" && value.length < 1); - if (input.password && !IsPasswordMinLength(value)) { - errorState.password = - "Password must have a minimum of 8 characters, contain numbers, symbols, uppercase and lowercase characters."; + errorState.password.text = "Strong, your password is secure 💪"; + errorState.password.checks = { "Minimum length": true, "Number": true, "Symbol": true, "Uppercase": true, "Lowercase": true }; + + let numChecked = 5; + + if (!PasswordContainsSymbol(value)) { + errorState.password.text = "Almost there, add a special symbol 😉" + errorState.password.checks["Symbol"] = false errorState.valid = false; - } else { - errorState.password = ""; + numChecked -= 1; + } + + if (!PasswordContainsNumber(value)) { + errorState.password.text = "So-so, should be alphanumeric 😕" + errorState.password.checks["Number"] = false + errorState.valid = false; + numChecked -= 1; + } + + if (!PasswordContainsUppercase(value)) { + errorState.password.text = + "Weak, must have at one uppercase and lowercase letter 😖"; + errorState.password.checks["Uppercase"] = false + errorState.valid = false; + numChecked -= 1; + } + + if (!PasswordContainsLowercase(value)) { + errorState.password.text = + "Weak, must have at one uppercase and lowercase letter 😖"; + errorState.password.checks["Lowercase"] = false + errorState.valid = false; + numChecked -= 1; + } + + if (!IsPasswordMinLength(value)) { + errorState.password.text = + "Must have at least 8 characters."; + errorState.password.checks["Minimum length"] = false + errorState.valid = false; + numChecked -= 1; + } + + errorState.password.numChecked = numChecked; + switch (numChecked) { + case 1: + errorState.password.color = "red"; + break; + case 2: + case 3: + errorState.password.color = "yellow.300"; + break; + case 4: + errorState.password.color = "blue"; + break; + case 5: + default: + errorState.password.color = "green.400"; + break; } // if (!DoPasswordsMatch(input.password, value)) { @@ -167,7 +233,21 @@ export default function RegistrationForm() { - {error.password && {error.password}} + + +
+ + {error.password.text} + + {[...Array(error.password.numChecked)].map(() => )} + {[...Array(5 - error.password.numChecked)].map(() => )} + + + {Object.entries(error.password.checks).map(([item, checked]) => ( + {item} + ))} + +
{/* Confirm Password diff --git a/src/utilities/validators.ts b/src/utilities/validators.ts index 085d4c4..013e80a 100644 --- a/src/utilities/validators.ts +++ b/src/utilities/validators.ts @@ -11,7 +11,24 @@ export function IsPasswordMinLength(password: string) { // var letter = /[a-zA-Z]/; // var number = /[0-9]/; // var valid = number.test(password) && letter.test(password); //match a letter _and_ a number - return /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/.test(password) && password.length >= 8; + // return /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$/.test(password) && password.length >= 8; + return password.length >= 8; +} + +export function PasswordContainsNumber(password: string) { + return /^(?=.*?[0-9]).+$/.test(password); +} + +export function PasswordContainsSymbol(password: string) { + return /^(?=.*?[#?!@$%^&*-]).+$/.test(password); +} + +export function PasswordContainsUppercase(password: string) { + return /^(?=.*?[A-Z]).+$/.test(password); +} + +export function PasswordContainsLowercase(password: string) { + return /^(?=.*?[a-z]).+$/.test(password); }