skip to Main Content

I’m currently trying to make an API call when my timer hits zero OR is in the past.

This is my Timer componenet

import { useState, useEffect } from "react";
import Box from "@mui/material/Box";
import { useDispatch } from "react-redux";
import { AppDispatch } from "../store";

const Timer = ({ deadline }: { deadline: Date }) => {
  const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(deadline));
  const [timerExpired, setTimerExpired] = useState(false);

  useEffect(() => {
    const intervalId = setInterval(() => {
      const remaining = getTimeRemaining(deadline);
      setTimeRemaining(remaining);

      if(remaining.days <= 0 && remaining.hours <= 0 && remaining.minutes <= 0 && remaining.seconds <= 0) {
        setTimerExpired(true);
        clearInterval(intervalId);

        const dispatch = useDispatch<AppDispatch>();
        try{
          console.log("TIMER EXPIRED");
        } catch (e){
          /* redux handles error */
        }
      }
    }, 1000);

    return () => clearInterval(intervalId);
  }, [deadline]);

  const { days, hours, minutes, seconds } = timeRemaining;

  return (
    <Box
    sx={{
      display: "flex",
      flexDirection: "column",
      alignItems: "center",
      justifyContent: "center",
      padding: "20px",
      fontSize: "35px",
      fontWeight: "bold"
    }}
  >
    {timerExpired ? (
      <p>Timer has expired.</p>
    ) : (
      <>
        {days === 1 ? (
          <p>
            {days} day {hours} hours {minutes} minutes {seconds} seconds
          </p>
        ) : (
          <p>
            {days} days {hours} hours {minutes} minutes {seconds} seconds
          </p>
        )}
      </>
    )}
  </Box>
      );
}

const getTimeRemaining = (deadline: Date) => {
  const total = deadline.getTime() - new Date().getTime();
  const days = Math.floor(total / (1000 * 60 * 60 * 24));
  const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
  const minutes = Math.floor((total / 1000 / 60) % 60);
  const seconds = Math.floor((total / 1000) % 60);

  return {
    days,
    hours,
    minutes,
    seconds
  };
};

export default Timer;

In this component i initialize the timer with the time it should expire:

const creationDate = new Date("2023-07-12");
    creationDate.setHours(9);
    creationDate.setMinutes(0);
    creationDate.setSeconds(0);

<Timer deadline={creationDate}/>

the console.log("TIMER EXPIRED") is never called, even when i set the createionDate to 2023-01-01 or any day in the past.

If you need any more information, please do not hesitate to comment.

Thanks in advance.

2

Answers


  1. The timer is only checking if the remaining time is zero or not, and it doesn’t check if the deadline is in the past. If the remaining time becomes negative the condition to set timerExpired to true is never met.

    const Timer = ({ deadline }: { deadline: Date }) => {
      const [timeRemaining, setTimeRemaining] = useState(getTimeRemaining(deadline));
      const [timerExpired, setTimerExpired] = useState(false);
    
      useEffect(() => {
        if (deadline < new Date()) {
          setTimerExpired(true);
          const dispatch = useDispatch<AppDispatch>();
          try {
            console.log("TIMER EXPIRED");
          } catch (e) {
            /* redux handles error */
          }
        } else {
          const intervalId = setInterval(() => {
            const remaining = getTimeRemaining(deadline);
            setTimeRemaining(remaining);
    
            if (
              remaining.days <= 0 &&
              remaining.hours <= 0 &&
              remaining.minutes <= 0 &&
              remaining.seconds <= 0
            ) {
              setTimerExpired(true);
              clearInterval(intervalId);
    
              const dispatch = useDispatch<AppDispatch>();
              try {
                console.log("TIMER EXPIRED");
              } catch (e) {
                /* redux handles error */
              }
            }
          }, 1000);
    
          return () => clearInterval(intervalId);
        }
      }, [deadline]);
    
      const { days, hours, minutes, seconds } = timeRemaining;
    };
    
    const getTimeRemaining = (deadline: Date) => {
      const total = deadline.getTime() - new Date().getTime();
      const days = Math.floor(total / (1000 * 60 * 60 * 24));
      const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
      const minutes = Math.floor((total / 1000 / 60) % 60);
      const seconds = Math.floor((total / 1000) % 60);
    
      return {
        days,
        hours,
        minutes,
        seconds,
      };
    };
    
    export default Timer;
    
    Login or Signup to reply.
  2. You could add total to the return in getTimeRemaining, and then check that.

    if ( remaining.total <= 0 ) {
    

    Then your code should work I have made an example stackblitz.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search