Build a One-Time Password Generator - Build a One-Time Password Generator

Tell us what’s happening:

When I execute the lab by clicking the “Generate OTP” button, it works as expected. However, when I submit my work it says it failed step 13 and 16 in Tests section. I don’t understand why because for step 13 it does count down from 5 to 0, and when the timer reaches 0 it does display the required statement for step 16. Can anyone help? Any hep is appreciated. Thank you.

Your code so far

<!-- file: index.html -->
<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>OTP Generator</title>
    <link rel="stylesheet" href="styles.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.5/babel.min.js"></script>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      src="index.jsx"
    ></script>
</head>

<body>
    <div id="root"></div>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
    >
      import { OTPGenerator } from './index.jsx';
      ReactDOM.createRoot(document.getElementById('root')).render(<OTPGenerator />);
    </script>
</body>

</html>
/* file: styles.css */
#generate-otp-button:disabled{
  cursor: not-allowed;
}
/* file: index.jsx */
const { useState, useEffect, useRef } = React;

export const OTPGenerator = () => {
  const [initialCount, setCount] = useState(5);
  const [initialPass, setPassword] = useState(null);
  const [initialDisplay, setDisplay] = useState(false);
  const [isRunning, setIsRunning] = useState(false);
  
  const generatePassword = () => {
    const newPass = Math.floor(Math.random() * (900000 - 100000 + 1) + 100000);
    setPassword(newPass);
    setDisplay(true);
    setCount(5);
    setIsRunning(true);
  };

  const getMessage = () => {
    if(!initialDisplay){
      return "";
    }

    if(initialCount > 0){
      return `Expires in: ${initialCount} seconds`;
    }
    else{
      return "OTP expired. Click the button to generate a new OTP.";
    }
  };

  useEffect(() => {
    if(!isRunning){
      return;
    }

    const intervalId = setInterval(() => {
      setCount((previousTime) => {
        if(previousTime <= 1){
          setIsRunning(false);
          return 0;
        }

        return previousTime - 1;
      });
      
    }, 1000);

    return () => clearInterval(intervalId);

  }, [isRunning]);

  return (
    <div className="container">
      <h1 id="otp-title">OTP Generator</h1>
      <h2 id="otp-display">{initialPass || "Click 'Generate OTP' to get a code"}</h2>

      <p id="otp-timer" aria-live="polite">{getMessage()}</p>

      <button id="generate-otp-button" onClick={generatePassword} disabled={isRunning}>Generate OTP</button>
    </div>
  );
};

Your browser information:

User Agent is: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Safari/605.1.15

Challenge Information:

Build a One-Time Password Generator - Build a One-Time Password Generator

GitHub Link: freeCodeCamp/curriculum/challenges/english/blocks/lab-one-time-password-generator/67c562286b29447da020d407.md at main · freeCodeCamp/freeCodeCamp · GitHub

Updated JavaScript and React code below. I got step 16 in Test section to pass, but step 13 still does not pass. For step 13, the element with id “otp-timer” does update every second to show the remaining time as described by the instruction, but again it does not pass step 13. Can anyone take a look at my solution and tell me what I am doing wrong? Thank you for your help.

HTML Below:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>OTP Generator</title>
    <link rel="stylesheet" href="styles.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.5/babel.min.js"></script>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      src="index.jsx"
    ></script>
</head>

<body>
    <div id="root"></div>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
    >
      import { OTPGenerator } from './index.jsx';
      ReactDOM.createRoot(document.getElementById('root')).render(<OTPGenerator />);
    </script>
</body>

</html>

CSS Below:

#generate-otp-button:disabled{
  cursor: not-allowed;
}

JavaScript and React Code Below:

const { useState, useEffect, useRef } = React;

export const OTPGenerator = () => {
  const [initialCount, setCount] = useState(5);
  const [initialPass, setPassword] = useState(null);
  const [initialDisplay, setDisplay] = useState(false);
  const [isRunning, setIsRunning] = useState(false);
  
  const generatePassword = () => {
    const newPass = Math.floor(Math.random() * (900000 - 100000 + 1) + 100000);
    setPassword(newPass);
    setDisplay(true);
    setCount(5);
    setIsRunning(true);
  };

  const getMessage = () => {
    if(!initialDisplay){
      return "";
    }

    if(initialCount > 0){
      return `Expires in: ${initialCount} seconds`;
    }
    else{
      return "OTP expired. Click the button to generate a new OTP.";
    }
  };

  useEffect(() => {
    if(!isRunning){
      return;
    }

    const intervalId = setInterval(() => {
      setCount((previousTime) => {
        if(previousTime <= 1){
          return 0;
        }

        return previousTime - 1;
      });
      
    }, 1000);

    return () => clearInterval(intervalId);

  }, [isRunning]);

  useEffect(() => {
    if(isRunning && !initialCount){
      setIsRunning(false);
    }

  }, [initialCount, isRunning]);

  return (
    <div className="container">
      <h1 id="otp-title">OTP Generator</h1>
      <h2 id="otp-display">{initialPass || "Click 'Generate OTP' to get a code"}</h2>
      <p id="otp-timer" aria-live="polite">{getMessage()}</p>
      <button id="generate-otp-button" onClick={generatePassword} disabled={isRunning}>Generate OTP</button>
    </div>
  );
};