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 = () => {
-
+
Password
-
setPassword(e.target.value)}
- required
- />
+ onChange={handlePasswordChange}
+ required/>
+ setShowPassword(!showPassword)}
+ className="absolute right-3 top-[38px] cursor-pointer ">
+ {showPassword ? (
+
+ ) : (
+
+ )}
+
+
+ {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}