From 76a4766a4e3536cad77625f7dcb7e428c7fe7b2c Mon Sep 17 00:00:00 2001 From: kushalkumar1362 Date: Thu, 30 May 2024 22:33:34 +0530 Subject: [PATCH] Add Password Strength and Toogle Password --- frontend/package-lock.json | 88 ++++++++++++++++++++++++- frontend/package.json | 7 +- frontend/src/pages/Signin.tsx | 25 ++++++-- frontend/src/pages/Signup.tsx | 117 ++++++++++++++++++++++++++++++++-- 4 files changed, 223 insertions(+), 14 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4276142e..d8857fe7 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,15 +8,20 @@ "name": "frontend", "version": "0.0.0", "dependencies": { + "@fortawesome/free-solid-svg-icons": "^6.5.2", + "@fortawesome/react-fontawesome": "^0.2.2", "axios": "^1.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-icons": "^5.2.1", "react-router-dom": "^6.23.1", - "recoil": "^0.7.7" + "recoil": "^0.7.7", + "zxcvbn": "^4.4.2" }, "devDependencies": { "@types/react": "^18.2.66", "@types/react-dom": "^18.2.22", + "@types/zxcvbn": "^4.4.4", "@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/parser": "^7.2.0", "@vitejs/plugin-react": "^4.2.1", @@ -862,6 +867,52 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz", + "integrity": "sha512-gBxPg3aVO6J0kpfHNILc+NMhXnqHumFxOmjYCFfOiLZfwhnnfhtsdA2hfJlDnj+8PjAs6kKQPenOTKj3Rf7zHw==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.2.tgz", + "integrity": "sha512-5CdaCBGl8Rh9ohNdxeeTMxIj8oc3KNBgIeLMvJosBMdslK/UnEB8rzyDRrbKdL1kDweqBPo4GT9wvnakHWucZw==", + "hasInstallScript": true, + "peer": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.2.tgz", + "integrity": "sha512-QWFZYXFE7O1Gr1dTIp+D6UcFUF0qElOnZptpi7PBUMylJh+vFmIedVe1Ir6RM1t2tEQLLSV1k7bR4o92M+uqlw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz", + "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==", + "dependencies": { + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "react": ">=16.3" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -1342,6 +1393,12 @@ "@types/react": "*" } }, + "node_modules/@types/zxcvbn": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@types/zxcvbn/-/zxcvbn-4.4.4.tgz", + "integrity": "sha512-Tuk4q7q0DnpzyJDI4aMeghGuFu2iS1QAdKpabn8JfbtfGmVDUgvZv1I7mEjP61Bvnp3ljKCC8BE6YYSTNxmvRQ==", + "dev": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.10.0.tgz", @@ -3130,7 +3187,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3473,6 +3529,16 @@ "node": ">= 0.8.0" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -3530,6 +3596,19 @@ "react": "^18.3.1" } }, + "node_modules/react-icons": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.2.1.tgz", + "integrity": "sha512-zdbW5GstTzXaVKvGSyTaBalt7HSfuK5ovrzlpyiWHAFXndXTdd/1hdDHI4xBM1Mn7YriT6aqESucFl9kEXzrdw==", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", @@ -4397,6 +4476,11 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zxcvbn": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz", + "integrity": "sha512-Bq0B+ixT/DMyG8kgX2xWcI5jUvCwqrMxSFam7m0lAf78nf04hv6lNCsyLYdyYTrCVMqNDY/206K7eExYCeSyUQ==" } } } diff --git a/frontend/package.json b/frontend/package.json index 312db805..0ffded8d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,15 +10,20 @@ "preview": "vite preview" }, "dependencies": { + "@fortawesome/free-solid-svg-icons": "^6.5.2", + "@fortawesome/react-fontawesome": "^0.2.2", "axios": "^1.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-icons": "^5.2.1", "react-router-dom": "^6.23.1", - "recoil": "^0.7.7" + "recoil": "^0.7.7", + "zxcvbn": "^4.4.2" }, "devDependencies": { "@types/react": "^18.2.66", "@types/react-dom": "^18.2.22", + "@types/zxcvbn": "^4.4.4", "@typescript-eslint/eslint-plugin": "^7.2.0", "@typescript-eslint/parser": "^7.2.0", "@vitejs/plugin-react": "^4.2.1", diff --git a/frontend/src/pages/Signin.tsx b/frontend/src/pages/Signin.tsx index 53a3e20b..f7eddee9 100644 --- a/frontend/src/pages/Signin.tsx +++ b/frontend/src/pages/Signin.tsx @@ -3,10 +3,13 @@ import { useState } from "react"; import { Link, useNavigate } from "react-router-dom"; import { useSetRecoilState } from "recoil"; import { tokenState } from "../store/atoms/auth"; +import { AiOutlineEyeInvisible, AiOutlineEye } from "react-icons/ai"; const Signin = () => { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); + const [showPassword, setShowPassword] = useState(false); + const [error, setError] = useState({ email: "", password: "", @@ -75,18 +78,30 @@ const Signin = () => {

- +

{error.password}

diff --git a/frontend/src/pages/Signup.tsx b/frontend/src/pages/Signup.tsx index aaf10745..2a6b768f 100644 --- a/frontend/src/pages/Signup.tsx +++ b/frontend/src/pages/Signup.tsx @@ -3,11 +3,17 @@ import { useState } from "react"; import { Link, useNavigate } from "react-router-dom"; import { useSetRecoilState } from "recoil"; import { tokenState } from "../store/atoms/auth"; +import { AiOutlineEyeInvisible, AiOutlineEye } from "react-icons/ai"; +import zxcvbn, { ZXCVBNResult } from 'zxcvbn'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCheck, faCircle } from '@fortawesome/free-solid-svg-icons'; const Signup = () => { const [username, setUsername] = useState(""); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); + const [showPassword, setShowPassword] = useState(false); + const [passwordStrength, setPasswordStrength] = useState(null); const [error, setError] = useState({ username: "", email: "", @@ -48,6 +54,28 @@ const Signup = () => { } }; + const handlePasswordChange = (e:React.ChangeEvent) => { + const newPassword = e.target.value; + setPassword(newPassword); + setPasswordStrength(zxcvbn(newPassword)); + }; + + const strengthMeterColor = (score:number) => { + switch (score) { + case 0: + return 'bg-red-500'; + case 1: + return 'bg-yellow-500'; + case 2: + return 'bg-yellow-300'; + case 3: + return 'bg-green-300'; + case 4: + return 'bg-green-500'; + default: + return 'bg-gray-500'; + } + }; return (
@@ -96,19 +124,96 @@ const Signup = () => {

- + {passwordStrength && ( +
+
+
+
+

+ {['Weak', 'Fair', 'Good', 'Strong', 'Very Strong'][passwordStrength.score]} +

+ )} + +
    +
  • + + +  Lowercase & Uppercase + +
  • +
  • + + +  Number (0-9) + +
  • +
  • + + +  Special Character (!@#$%^&*) + +
  • +
  • + + 7 ? faCheck : faCircle} + className={ + password.length > 7 ? 'text-green-600' : 'text-gray-400' + } + /> +  At least 8 Characters + +
  • +
+

{error.password}