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

Tell us what’s happening:

My code runs as should, but I’m failing step 12 and 13:
12. When the button is clicked, the p element with id of otp-timer should show a 5-second countdown.
13. The message in the p element with id otp-timer should update every second to show the remaining time.

Perhaps my timer isn’t exactly 5 seconds, but maybe slightly longer due to extra code needing to run between each 1 second timer. Maybe that’s the problem?

I have tried swapping from setTimer to setInterval instead to make the timer exactly 5 seconds, but then the states of my timer wouldn’t update properly dynamically (the timer just stayed on 5 seconds). Let me know if this code, with setTimer, might be salvageable or if you would like me to send the code with setInterval instead.

Many thanks!!

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 */

/* file: index.jsx */
const { useState, useEffect, useRef } = React;


let disabled = false;


export const OTPGenerator = () => {


  const [otp, setOtp] = useState("");
  const [message, setMessage] = useState("");
  const [seconds, setSeconds] = useState(5);
  const buttonRef = useRef(null);


  function generateOtp() {
    const newOtp = [Math.floor(Math.random() * 10), Math.floor(Math.random() * 10), Math.floor(Math.random() * 10), Math.floor(Math.random() * 10), Math.floor(Math.random() * 10), Math.floor(Math.random() * 10)];
    setOtp(newOtp);


    toggleDisabled();
    setSeconds(5);
  }


  function toggleDisabled() {
    if (buttonRef.current) {
      if (disabled === false) {
        buttonRef.current.setAttribute("disabled", true);
        disabled = true;
      } else {
        buttonRef.current.removeAttribute("disabled");
        disabled = false;
      }
    }
  }


  useEffect(() => {
    if (otp === "") {
      return;
    }


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


    const timeoutId = setTimeout(() => {
      setSeconds(prev => prev - 1);
    }, 1000);
    return () => clearTimeout(timeoutId);
  }, [otp, seconds]);


  return (
    <div className="container">
      <h1 id="otp-title">OTP Generator</h1>
      <h2 id="otp-display">
        {otp ? otp : "Click 'Generate OTP' to get a code"}
      </h2>
      <p id="otp-timer" aria-live="polite">{message}</p>
      <button id="generate-otp-button" ref={buttonRef} onClick={generateOtp}>Generate OTP</button>
    </div>
  );
};

Your browser information:

User Agent is: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:151.0) Gecko/20100101 Firefox/151.0

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