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..d378ebd0de --- /dev/null +++ b/src/plays/password-generator/PasswordGenerator.jsx @@ -0,0 +1,205 @@ +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, +}; + +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..e7de99062c --- /dev/null +++ b/src/plays/password-generator/Readme.md @@ -0,0 +1,16 @@ +# Password Generator +The `Password Generator` project is a fun project which shows the usecase of some concept in ReactJS. + +- Multiple Checkbox Handling. +- Managing Complex logic to generate random password +- Use and manage multiple nested `useState` hooks +- Use of `useEffect` hook in ReactJS. +- Also how to copy text and handle error are shown. + +# File Contents + +For now all the necessary components, functions and logics are managed inside `PasswordGenerator.jsx` file.and the css are contained inside `password-generator-style.css` + +also there is a `data.json` which is the main source and feeding requied data into the `PasswordGenerator.jsx` component. + +Happy Learning! \ 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..308b676d37 --- /dev/null +++ b/src/plays/password-generator/password-generator-style.css @@ -0,0 +1,138 @@ + + +.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; +} + +.password-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 { + width: 20px; + height: 20px; + float: right; +} + +.select { + width: 45px; + height: 25px; + font-size: 1rem; + float: right; + margin: 0; +} + +.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%; + } + + .password-input { + font-size: 1rem; + width: 100%; + } + .copy-button { + padding: 0 5px; + font-size: 16px; + } +} \ No newline at end of file