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

Tell us what’s happening:

The OTP Generator is working as expected but the test frame has not pass requirements 12 & 13. Please see below for assist.

  1. When the button is clicked, the p element with id of otp-timer should show a 5-second countdown.
  2. The message in the p element with id otp-timer should update every second to show the remaining time.

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;

export const OTPGenerator = () => {
  const [otp, setOtp] = useState("Click 'Generate OTP' to get a code");
  const [timer, setTimer] = useState(0);
  const [isDisabled, setIsDisabled] = useState(false);
  const intervalRef = useRef(null);

  const generateOtp = () => {
    const newOtp = Math.floor(100000 + Math.random() * 900000).toString();
    setOtp(newOtp);
    setTimer(5); // Start at 5 seconds
    setIsDisabled(true);

    if (intervalRef.current) clearInterval(intervalRef.current);

    intervalRef.current = setInterval(() => {
      setTimer((prev) => {
        if (prev <= 1) {
          clearInterval(intervalRef.current);
          setIsDisabled(false);
          return 0;
        }
        return prev - 1;
      });
    }, 1000);
  };

  useEffect(() => {
    return () => clearInterval(intervalRef.current);
  }, []);

  return (
    <div className="container">
      <h1 id="otp-title">OTP Generator</h1>
      <h2 id="otp-display">{otp}</h2>
      
      {/* 
          Criterion 13: This p element updates every second 
          while timer > 0 to show the remaining time.
      */}
      <p id="otp-timer" aria-live="assertive"> 
        {timer > 0 
          ? `Time remaining: ${timer}` 
          : otp.length === 6 
            ? "OTP expired. Click the button to generate a new OTP." 
            : ""
        }
      </p>

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

export default OTPGenerator;


Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36

Challenge Information:

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

hello!

Kindly recheck what the #otp-timer is supposed to display when the countdown is active from the User Stories.

The code is well executed as expected but the test frame does not pass the requirements 12 and 13. If you could test my code from your end you might as well see same result. Very importantly, how do I pass the test now I need a fix.

Here’s my complete code, please do inspect it. Thanks

const { useState, useEffect, useRef } = React;

export const OTPGenerator = () => {
  const [otp, setOtp] = useState("Click 'Generate OTP' to get a code");
  const [timer, setTimer] = useState(0);
  const [isDisabled, setIsDisabled] = useState(false);
  const intervalRef = useRef(null);

  const generateOtp = () => { 
    const newOtp = Math.floor(100000 + Math.random() * 900000).toString();
    setOtp(newOtp);
    setTimer(5); // Start at 5 seconds
    setIsDisabled(true);

    if (intervalRef.current) clearInterval(intervalRef.current);

    intervalRef.current = setInterval(() => {
      setTimer((prev) => {
        if (prev <= 1) {
          clearInterval(intervalRef.current);
          setIsDisabled(false);
          return 0;
        }
        return prev - 1;
      });
    }, 1000);
  };

  useEffect(() => {
    return () => clearInterval(intervalRef.current);
  }, []);

  return (
    <div className="container">
      <h1 id="otp-title">OTP Generator</h1>
      <h2 id="otp-display">{otp}</h2>
      
      {/* 
          Criterion 13: This p element updates every second 
          while timer > 0 to show the remaining time.
      */}
      <p id="otp-timer" aria-live="assertive"> 
        {timer > 0 
          ? `Time remaining: ${timer}` 
          : otp.length === 6 
            ? "OTP expired. Click the button to generate a new OTP." 
            : ""
        }
      </p>

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

export default OTPGenerator;


I did check your code. Currently it does not fulfill the requirements of the third point of User Story#3, which says -

there should be a p element with the ID otp-timer that displays "Expires in: X seconds" after the button is clicked, where X represents the remaining time before the OTP expires.

Your’s currently displays `Time remaining: ${timer}`.