Countdown is not updating even with SetInterval

96 Views Asked by At

I am trying to create a countdown forge application that takes an input of type date and starts counting based on the actual date. As an example, I am giving as input "After 3 days from now", But I only get as a result, 2d:23h:59m:59s , ans this result is not updating every second.

Here is the main function:

const useCountdown = (targetDate) => {
const countDownDate = new Date(targetDate).getTime();

const [countDown, setCountDown] = useState(
countDownDate - new Date().getTime()
);

useEffect(() => {
const interval = setInterval(() => {
  setCountDown(countDownDate - new Date().getTime());
}, 1000);

return () => clearInterval(interval);
}, [countDownDate]);

return getReturnValues(countDown);
};

This is where I display the countdown:

const Edit = () => {

const THREE_DAYS_IN_MS = 3 * 24 * 60 * 60 * 1000;
const NOW_IN_MS = new Date().getTime();

const dateTimeAfterThreeDays = NOW_IN_MS + THREE_DAYS_IN_MS;
 return(
  <Fragment>
  <Text>Time left 123:</Text>
  <CountdownTimer targetDate={dateTimeAfterThreeDays} />
  </Fragment>
   )
       };
    export const renderFieldView = render(<View />);

I am using Atlassian forge and deploying the app in Jira.

2

There are 2 best solutions below

3
On BEST ANSWER

I hope the original poster has found the solution by now, but for anyone coming across this post, I believe part of the reason this isn't working is because it's using UI Kit (original) which uses an Atlassian implementation of useEffect that doesn't work quite the same way as React.

I've written a bit more about how Forge uses hooks in each of the different kinds of apps in this blog https://blog.developer.atlassian.com/a-deeper-look-at-hooks-in-forge/

I can confirm, if you build this using UI Kit 2 (which uses React hooks) then it will work.

2
On

Are you sure you do not have an error in your console?

The only thing I can think of is using milliseconds (Number) as a Date or vice versa.

const { Fragment, useEffect, useState } = React;

const shiftDate = (date) =>
  new Date(date.getTime() - date.getTimezoneOffset() * 6e4);

const startOfYearLocal = (date) =>
  shiftDate(new Date(date.getFullYear(), 0, 1));

const dayOfYear = (date) =>
  Math.floor((date - startOfYearLocal(date)) / 864e5);

const getReturnValues = (dateInMillis) => {
  const date = new Date(dateInMillis);
  return {
    days: dayOfYear(date),
    hours: date.getHours(),
    minutes: date.getMinutes(),
    seconds: date.getSeconds(),
  };
};

const useCountdown = (targetDate) => {
  const countDownDate = new Date(targetDate).getTime();
  const [countDown, setCountDown] = useState(countDownDate - Date.now());
  useEffect(() => {
    const interval = setInterval(() =>
      setCountDown(countDownDate - Date.now()), 1000);
    return () => clearInterval(interval);
  }, [countDownDate]);
  return getReturnValues(countDown);
};

const Text = ({ children }) => <span>{children}</span>;

const CountdownTimer = ({ targetDate }) => {
  const { days, hours, minutes, seconds } = useCountdown(new Date(targetDate));
  return (
    <div className="CountdownTimer">
      <span>Days:</span><span>{days}</span>
      <span>Hours:</span><span>{hours}</span>
      <span>Minutes:</span><span>{minutes}</span>
      <span>Seconds:</span><span>{seconds}</span>
    </div>
  );
};

const Edit = () => {
  const THREE_DAYS_IN_MS = 2592e5;
  const NOW_IN_MS = Date.now();
  const dateTimeAfterThreeDays = NOW_IN_MS + THREE_DAYS_IN_MS;
  return (
    <Fragment>
      <Text>Time Left</Text>
      <CountdownTimer targetDate={dateTimeAfterThreeDays} />
    </Fragment>
  );
};

ReactDOM
  .createRoot(document.getElementById('root'))
  .render(<Edit />);
html, body, #root {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

#root {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.CountdownTimer {
  display: grid;
  grid-template-columns: repeat(4, auto);
  grid-column-gap: 0.5rem;
  grid-row-gap: 0.25rem;
  padding: 1rem;
}

.CountdownTimer span {
  text-align: right;
}

.CountdownTimer span:nth-child(odd) {
  font-weight: bold;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>