From 3fad093f7d8669bc19d8299b939a55d9bd682a8f Mon Sep 17 00:00:00 2001 From: Angryman18 Date: Thu, 5 May 2022 17:29:12 +0530 Subject: [PATCH 1/2] React Play Password Generator --- src/meta/play-meta.js | 15 +- src/plays/index.js | 1 + .../password-generator/PasswordGenerator.jsx | 199 ++++++++++++++++++ src/plays/password-generator/Readme.md | 1 + src/plays/password-generator/data.json | 5 + .../password-generator-style.css | 142 +++++++++++++ 6 files changed, 362 insertions(+), 1 deletion(-) create mode 100644 src/plays/password-generator/PasswordGenerator.jsx create mode 100644 src/plays/password-generator/Readme.md create mode 100644 src/plays/password-generator/data.json create mode 100644 src/plays/password-generator/password-generator-style.css diff --git a/src/meta/play-meta.js b/src/meta/play-meta.js index 22057fdc9a..7d6afa6e65 100644 --- a/src/meta/play-meta.js +++ b/src/meta/play-meta.js @@ -12,7 +12,8 @@ import { ReactTodoApp, ExpandingCards, AnalogClock, - //import play here + PasswordGenerator, +//import play here } from "plays"; export const plays = [ @@ -185,5 +186,17 @@ export const plays = [ cover: "", blog: "", video: "", + }, { + id: 'pl-password-generator', + name: 'Password Generator', + description: 'Its a simple password generator built in react using what user can generate password and customize their requirements in choosing characters and number while generating a medium or strong level password.', + component: () => {return }, + path: '/plays/password-generator', + level: 'Beginner', + tags: 'PasswordGenerator', + github: 'Angryman18', + cover: 'https://securityintelligence.com/wp-content/uploads/2018/10/si-eight-character-password-feature.jpg', + blog: '', + video: '' }, //replace new play item here ]; diff --git a/src/plays/index.js b/src/plays/index.js index 1353b6d97b..95867efe46 100644 --- a/src/plays/index.js +++ b/src/plays/index.js @@ -14,4 +14,5 @@ export { default as ReactTodoApp } from 'plays/react-todo-app/ReactTodoApp'; export { default as ExpandingCards } from 'plays/expanding-cards/ExpandingCards'; export { default as AnalogClock } from 'plays/analog-clock/AnalogClock'; +export { default as PasswordGenerator } from 'plays/password-generator/PasswordGenerator'; //add export here diff --git a/src/plays/password-generator/PasswordGenerator.jsx b/src/plays/password-generator/PasswordGenerator.jsx new file mode 100644 index 0000000000..4039d47e44 --- /dev/null +++ b/src/plays/password-generator/PasswordGenerator.jsx @@ -0,0 +1,199 @@ +import { getPlayById } from "meta/play-meta-util"; + +import PlayHeader from "common/playlists/PlayHeader"; +import { useEffect, useState } from "react"; + +import "./password-generator-style.css"; +import data from "./data.json"; + +const config = { + length: 12, + numbers: true, + special: true, + uppercase: true, + lowercase: true, + // excludeSimilarCharacters: true, +}; + +function PasswordGenerator(props) { + // Do not remove the below lines. + // The following code is to fetch the current play from the URL + const { id } = props; + const play = getPlayById(id); + + // Your Code Start below. + const [password, setPassword] = useState({ status: false, password: "" }); + const [passwordConfig, setPasswordConfig] = useState({ ...config }); + const [error, setError] = useState(false); + + // generating lowercase characters + data.lowercase = data?.uppercase?.map((i) => i.toLowerCase()); + + // generate a random number within limit which is provided + const randomNumberGenerator = (limit) => { + let result = 0; + while (limit) { + result = Math.floor(Math.random() * Math.floor(Math.random() * 100)); + if (result < limit) return result; + continue; + } + }; + + // arrange data to feed the generatePassword function + const arrangeData = () => { + const { numbers, special, uppercase, lowercase } = passwordConfig; + + const parseData = (val, key) => { + if (val) return data[key]; + return []; + }; + + const concated = [ + ...parseData(numbers, "numbers"), + ...parseData(special, "special"), + ...parseData(uppercase, "uppercase"), + ...parseData(lowercase, "lowercase"), + ]; + return concated; + }; + + // Generate a random password + const generatePassword = () => { + setError(false) + const concated = arrangeData(); + let finalPassword = ""; + for (let i = 0; i < passwordConfig.length; i++) { + finalPassword += concated[randomNumberGenerator(concated.length)]; + } + return finalPassword; + }; + + // generate password button click handler + const generateHander = () => { + const finalPassword = generatePassword(); + setPassword({ status: false, password: finalPassword }); + }; + + // handling checkbox and updating the config + const handleCheckedItem = (name, checked) => { + const modifiedConfig = { ...passwordConfig }; + delete modifiedConfig.length + delete modifiedConfig.excludeSimilarCharacters + modifiedConfig[name] = checked; + const values = Object.values(modifiedConfig).filter(i => i === true); + if (values.length === 0) { + return setError(true) + } + setPasswordConfig({ ...passwordConfig, [name]: checked }); + setError(false) + }; + + // Copy the password to the clipboard + const onCopyClick = (e) => { + e.preventDefault(); + navigator.clipboard.writeText(password.password); + setPassword({ ...password, status: true }); + }; + + useEffect(() => { + generateHander(); + }, []); + + const ErrorBox = () => { + return

You cannot Uncheck All At Once.

; + }; + + return ( +
+ +
+ {/* Your Code Starts Here */} +
+

Password Generator

+
+ {error && } +
+ + + + +
+ + +
+
+
+ + +
+
+ +
+
+
+ {/* Your Code Ends Here */} +
+
+ ); +} + +const CheckBox = ({ name, checked, getCheckedItem, id }) => { + const checkboxChangeHandler = (id) => (e) => { + getCheckedItem(id, e.target.checked); + }; + + return ( +
+ + +
+ ); +}; + +export default PasswordGenerator; diff --git a/src/plays/password-generator/Readme.md b/src/plays/password-generator/Readme.md new file mode 100644 index 0000000000..e6f53070f0 --- /dev/null +++ b/src/plays/password-generator/Readme.md @@ -0,0 +1 @@ +# Password Generator \ No newline at end of file diff --git a/src/plays/password-generator/data.json b/src/plays/password-generator/data.json new file mode 100644 index 0000000000..d450eeb5d3 --- /dev/null +++ b/src/plays/password-generator/data.json @@ -0,0 +1,5 @@ +{ + "uppercase": ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"], + "numbers": ["0","1","2","3","4","5","6","7","8","9"], + "special": ["!","@","#","$","%","^","&","*","(",")","-","_","=","+","[","{","]","}","|",";",":","'","\"",",",".","<",">","/","?"] +} \ No newline at end of file diff --git a/src/plays/password-generator/password-generator-style.css b/src/plays/password-generator/password-generator-style.css new file mode 100644 index 0000000000..22f251d482 --- /dev/null +++ b/src/plays/password-generator/password-generator-style.css @@ -0,0 +1,142 @@ + + +.main { + padding: 0; + margin: 0; + box-sizing: border-box; +} + +.title { + text-align: center; +} + +section { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +section > div:nth-of-type(2) { + position: relative; + /* background-color: black; */ +} + +.copy-button { + position: absolute; + right: 0; + top: 0; + bottom: 0; + border: 2px solid #187B86; + border-left: none; + border-bottom-right-radius: 5px; + border-top-right-radius: 5px; + padding: 0 10px; + font-size: 20px; + background-color: #187B86; + outline: none; + color: white; + transition: 100ms; +} + +.copy-button:hover { + background-color: #135088; + border: 2px solid #135088; + border-left: none; +} + +.copid { + background-color: #135088; + border: 2px solid #135088; + border-left: none; +} + +section > div:nth-of-type(1) { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 1fr 1fr; + width: 400px; + column-gap: 25px; + row-gap: 20px; + margin: 25px 0; +} + +input { + padding: 10px; + outline: none; + border: 2px solid #ccc; + border-radius: 5px; + font-size: 1.3rem; + font-weight: bold; + width: 400px; + /* max-width: 400px; */ + color: gray; +} + + +.generate { + padding: 10px 1rem; + outline: none; + font-size: 1.5rem; + outline: none; + background: rgb(0,128,0, 0.8); + border: none; + color: white; + cursor: pointer; + border-radius: 5px; + transition: 100ms; +} + +.generate:hover { + background: rgb(0,128,0, 1); +} + +.checkbox-comp { + padding: 0; + margin: 0; + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; +} + + + +.checkbox-comp > label { + display: inline; +} + +.checkbox-comp > input[type=checkbox] { + width: 20px; + height: 20px; + float: right; +} + +.checkbox-comp > select { + width: 40px; + height: 20px; + float: right; +} + +.error { + color: red; + font-size: 1rem; + text-align: center; +} + +@media screen and (max-width: 600px) { + section > div:nth-of-type(1) { + grid-template-columns: 1fr; + grid-template-rows: 1fr; + width: 100%; + } + + input { + font-size: 1rem; + width: 100%; + } + .copy-button { + padding: 0 5px; + font-size: 16px; + } +} \ No newline at end of file From 63c67b44c72232ffd9caa65803456d4eefc7b012 Mon Sep 17 00:00:00 2001 From: Angryman18 Date: Thu, 5 May 2022 20:22:11 +0530 Subject: [PATCH 2/2] issue fixes --- .../password-generator/PasswordGenerator.jsx | 30 +++++++++++-------- src/plays/password-generator/Readme.md | 17 ++++++++++- .../password-generator-style.css | 28 ++++++++--------- 3 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/plays/password-generator/PasswordGenerator.jsx b/src/plays/password-generator/PasswordGenerator.jsx index 4039d47e44..d378ebd0de 100644 --- a/src/plays/password-generator/PasswordGenerator.jsx +++ b/src/plays/password-generator/PasswordGenerator.jsx @@ -12,7 +12,6 @@ const config = { special: true, uppercase: true, lowercase: true, - // excludeSimilarCharacters: true, }; function PasswordGenerator(props) { @@ -59,7 +58,7 @@ function PasswordGenerator(props) { // Generate a random password const generatePassword = () => { - setError(false) + setError(false); const concated = arrangeData(); let finalPassword = ""; for (let i = 0; i < passwordConfig.length; i++) { @@ -77,15 +76,15 @@ function PasswordGenerator(props) { // handling checkbox and updating the config const handleCheckedItem = (name, checked) => { const modifiedConfig = { ...passwordConfig }; - delete modifiedConfig.length - delete modifiedConfig.excludeSimilarCharacters + delete modifiedConfig.length; + delete modifiedConfig.excludeSimilarCharacters; modifiedConfig[name] = checked; - const values = Object.values(modifiedConfig).filter(i => i === true); + const values = Object.values(modifiedConfig).filter((i) => i === true); if (values.length === 0) { - return setError(true) + return setError(true); } setPasswordConfig({ ...passwordConfig, [name]: checked }); - setError(false) + setError(false); }; // Copy the password to the clipboard @@ -110,7 +109,7 @@ function PasswordGenerator(props) { {/* Your Code Starts Here */}

Password Generator

-
+
{error && }
-
+
@@ -152,6 +156,7 @@ function PasswordGenerator(props) {
{ div:nth-of-type(2) { +.section > div:nth-of-type(2) { position: relative; /* background-color: black; */ } @@ -51,7 +51,7 @@ section > div:nth-of-type(2) { border-left: none; } -section > div:nth-of-type(1) { +.section > div:nth-of-type(1) { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; @@ -61,7 +61,7 @@ section > div:nth-of-type(1) { margin: 25px 0; } -input { +.password-input { padding: 10px; outline: none; border: 2px solid #ccc; @@ -100,22 +100,18 @@ input { justify-content: space-between; } - - -.checkbox-comp > label { - display: inline; -} - -.checkbox-comp > input[type=checkbox] { +.checkbox { width: 20px; height: 20px; float: right; } -.checkbox-comp > select { - width: 40px; - height: 20px; +.select { + width: 45px; + height: 25px; + font-size: 1rem; float: right; + margin: 0; } .error { @@ -125,13 +121,13 @@ input { } @media screen and (max-width: 600px) { - section > div:nth-of-type(1) { + .section > div:nth-of-type(1) { grid-template-columns: 1fr; grid-template-rows: 1fr; width: 100%; } - input { + .password-input { font-size: 1rem; width: 100%; }