0

I have written a code to generate password within the specified length. I am taking length of password from the slider, but getting password with random length it didn't generate the password from the given length from slider.

React js file:

import Slider from 'rc-slider'
import 'rc-slider/assets/index.css'
import { useState } from 'react'

import passwordGif from '../../assets/gif/password.gif'
import { ReactComponent as Copy } from '../../assets/icons/copy.svg'
import { ReactComponent as Refresh } from '../../assets/icons/refresh.svg'

import './index.css'



const PasswordGenerator = () => {
  const [passwordLength, setPasswordLength] = useState(8)
  const [upperCase, setUpperCase] = useState(false)
  const [lowerCase, setLowerCase] = useState(false)
  const [number, setNumber] = useState(false)
  const [specialChar, setSpecialChar] = useState(false)
  const [password, setPassword] = useState('');

  const [strength, setStrength] = useState('')
  const [copy, setCopy] = useState('Copy');
  const [colors, setColor] = useState("#FF0000")
  //const color = colors[strength]

  const onChangePasswordLength = (value) => {
    setPasswordLength(value);
    calculateStrength()
  }

  const handleCheckBox = (event) => {
    const value = event.target.checked
    console.log('value in checkBox', value)
    switch (event.target.id) {
      case 'uppercase':
        setUpperCase(value)
        break

      case 'lowercase':
        setLowerCase(value)
        break

      case 'numbers':
        setNumber(value)
        break

      case 'special chars':
        setSpecialChar(value)
        break

      default:
        console.log('in default case')
    }
  }

  const calculateStrength = () => {
    if(password.length === 0) return;
    if (password.length >= 12) {
      setStrength('Strong');
      setColor("#12b40e");
      console.log("color", colors)
    } else if (password.length >= 8 && password.length <= 11) {
      setStrength('Medium');
      setColor("#ffa200");
    } else if (password.length >= 2 && password.length <= 7) {
      setStrength('Weak');
      setColor('#ff0000');
    }
    console.log('strength:', strength)
  }

  async function copyContent() {
    try {
      if (password.length === 0) {
        setCopy('Copy')
        setStrength('Password is empty choose the correct filter and generate')
        setTimeout(() => {
          setStrength('')
        }, 2000)
        return
      }
      await navigator.clipboard.writeText(password)
      setCopy('Copied')
      setTimeout(() => {
        setCopy('Copy')
      }, 2000)
      console.log('copy text:', copy)
    } catch (e) {
      setCopy('Failed')
    }
  }

  const generatePassword = () => {
    const password = []
    const length = passwordLength
    console.log('lenght:', length)
    const characters =
      'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_-+={[}]|<?/'

    for (let i = 0; i < length; i++) {
      const index = Math.floor(Math.random() * characters.length)
      if (upperCase && characters[index] >= 'A' && characters[index] <= 'Z') {
        password.push(characters[index])
      } else if (lowerCase && characters[index] >= 'a' && characters[index] <= 'z') {
        password.push(characters[index])
      } else if (number && characters[index] >= '0' && characters[index] <= '9') {
        password.push(characters[index])
      } else if (specialChar && characters[index] >= '!' && characters[index] <= '/') {
        password.push(characters[index])
      }
    }
    setPassword(password.join(''))
    calculateStrength()
  }

  return (
    <div className="password-wrapper">
      <div className="gif">
        <img src={passwordGif} alt="Password Gif" />
      </div>
      <div className="tac">
        <h2 className="title">PASSWORD GENERATOR</h2>
        <p className="subtitle">
          Create strong and secure passwords to keep your account safe online.
        </p>
      </div>
      <div className="password-input-wrapper">
        <div className="password-field">
          <input type="text" placeholder="Password" value={password} onChange={generatePassword} />
        </div>
        <button className="copy-btn" onClick={copyContent} value={copy}>
          <Copy /> {copy}
        </button>
      </div>
      
      <p style={{color : `${colors}`, fontWeight:'bold', marginLeft:"10px", marginTop:"15px"}} >{strength}</p>
      <div className="slider">
        <div>
          <label id="slider-label">Password Length: </label>
          <span>{passwordLength}</span>
        </div>
        <Slider
          max={30}
          min={5}
          value={passwordLength}
          onChange={onChangePasswordLength}
          className="slider-style"
        />
      </div>

      <div className="checkbox-wrapper">
        <input
          className="inputcheck"
          type="checkbox"
          name="upperCase"
          id="uppercase"
          onChange={handleCheckBox}
          checked={upperCase}
          value={upperCase}
        />
        <label> UpperCase </label>
        <input
          type="checkbox"
          name="lowerCase"
          id="lowercase"
          onChange={handleCheckBox}
          checked={lowerCase}
          value={lowerCase}
        />
        <label> Lowercase </label>
        <input
          type="checkbox"
          name="numbers"
          id="numbers"
          onChange={handleCheckBox}
          checked={number}
        />
        <label> Numbers </label>
        <input
          type="checkbox"
          name="specialChars"
          id="special chars"
          onChange={handleCheckBox}
          checked={specialChar}
        />
        <label> Special Charcters </label>
      </div>

      <button className="generate-btn" onClick={() => generatePassword()}>
        Generate Password
      </button>
    </div>
  )
}

export default PasswordGenerator

Expectation is that code should generate password with the length given by slider.

jcubic
  • 61,973
  • 54
  • 229
  • 402
Gauri
  • 43
  • 3
  • You're confused as to how react `setState` works. This exact question is asked many times a day on Stackoverflow. [React setState not updating state](https://stackoverflow.com/questions/41446560/react-setstate-not-updating-state) – Andy Ray Jun 22 '23 at 21:18

1 Answers1

0

You are getting variable length passwords because your for loop is running n-times but you are not adding a character to the password on every iteration. For example: if for i=1 loop gave you a number but you do not want a number then you will not add it to the password, hence 1 iteration wasted. Use a do-while loop for this and break the loop whenever newpassword.length=== n

  const generatePassword = () => {
    const newpassword = [];
    const length = passwordLength;
    console.log("length:", length);
    const characters =
      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_-+={[}]|<?/";

    do {
      const index = Math.floor(Math.random() * characters.length);
      if (upperCase && characters[index] >= "A" && characters[index] <= "Z") {
        newpassword.push(characters[index]);
      } else if (
        lowerCase &&
        characters[index] >= "a" &&
        characters[index] <= "z"
      ) {
        newpassword.push(characters[index]);
      } else if (
        number &&
        characters[index] >= "0" &&
        characters[index] <= "9"
      ) {
        newpassword.push(characters[index]);
      } else if (
        specialChar &&
        characters[index] >= "!" &&
        characters[index] <= "/"
      ) {
        newpassword.push(characters[index]);
      }
    }while(newpassword.length !== length)

    setPassword(newpassword.join(""));
    console.log(newpassword.join(""));
  };

using For loop:

  const generatePassword = () => {
    const newpassword = [];
    const length = passwordLength;
    console.log("length:", length);
    const characters =
      "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_-+={[}]|<?/";

    for(let i=0; i<200; i++){
      const index = Math.floor(Math.random() * characters.length);
      if (upperCase && characters[index] >= "A" && characters[index] <= "Z") {
        newpassword.push(characters[index]);
      } else if (
        lowerCase &&
        characters[index] >= "a" &&
        characters[index] <= "z"
      ) {
        newpassword.push(characters[index]);
      } else if (
        number &&
        characters[index] >= "0" &&
        characters[index] <= "9"
      ) {
        newpassword.push(characters[index]);
      } else if (
        specialChar &&
        characters[index] >= "!" &&
        characters[index] <= "/"
      ) {
        newpassword.push(characters[index]);
      }
    if(newpassword.length === length) break;
    }

    setPassword(newpassword.join(""));
    console.log(newpassword.join(""));
  };

Put calculateStrength() inside useEffect so that it runs whenever the password is updated:

useEffect(()=>{
calculateStrength();
},[password]);
Aniket Pandey
  • 464
  • 1
  • 9
  • Thank you so much for quick response, with do-while loop code is working as expected. But I still have a doubt how come the iteration of for loop causes issue to the length of password which gets generate. Because I am checking iteration till it reaches to the length, so how does that affects. – Gauri Jun 23 '23 at 06:37
  • You are doing `const index = Math.floor(Math.random() * characters.length);` now suppose `characters[index]` returns a number and you have chosen the option to not include numbers, then that characters will be ignored and you will not push any character to password for that iteration. this reduces the number of characters in final output as loop runs **n-times** but you only push charcters **(n-1) - times** – Aniket Pandey Jun 23 '23 at 07:27
  • @Gauri I have updated the answer to include for loop as well, please check. – Aniket Pandey Jun 23 '23 at 07:39
  • You are running the loop n-times but you are not checking the length of password anywhere in your function. there is a difference between the two. try console-logging every character you get in for loop and also value of "i", you will understand what's happening. – Aniket Pandey Jun 23 '23 at 07:46
  • Many Thanks Aniket for explanation now understood properly. – Gauri Jun 23 '23 at 10:57
  • The issue with your code is that you're calling `calculateStrength()` before your password state is set, as explained in the duplicate question in the comment on your post. The password is not updated when you call `calculateStrength()` – Andy Ray Jun 24 '23 at 17:26