(create-react-app) Auto-reset countdown timer once reaches target date

Viewed 42

I am trying to make a countdown timer for Christmas and found this video useful. It uses React with Day.js package. It works well if I set Christmas date timestamp manually. However, there are two target functions that I can't figure out.

  1. Make timer disappear and display "Christmas today" on screen for 24 hours once it reaches the day of Christmas.

  2. Automatically set new timeStampDayJs to next Christmas once current date reaches Dec. 26?

Currently, I have to set the next Christmas timestamp manually once Christmas arrives, and I can't automatically show "Christmas today" on the day of Christmas. Is there any way I can achieve the two goals automatically?

My code here (mostly the same as the YouTube video, but I set Christmas timestamp manually):

import { useState, useEffect } from "react";
import dayJs from "dayjs";
var utc = require("dayjs/plugin/utc");
var timezone = require("dayjs/plugin/timezone");
dayJs.extend(utc);
dayJs.extend(timezone);

const defaultRemainingTime = {
  seconds: "00",
  minutes: "00",
  hours: "00",
  days: "00",
};

const Countdown = () => {
  const [remainingTime, setRemainingTime] = useState(defaultRemainingTime);

  const countdownTimeStamp = 1671919200000;

  const getRemainingTime = (countdownTimeStamp) => {
    const timeStampDayJs = dayJs(countdownTimeStamp).tz("Europe/Helsinki");
    const nowDayJs = dayJs().tz("Europe/Helsinki");
    if (timeStampDayJs.isBefore(nowDayJs)) {
      return defaultRemainingTime;
    }

    return {
      seconds: getRemainingSeconds(nowDayJs, timeStampDayJs),
      minutes: getRemainingMinutes(nowDayJs, timeStampDayJs),
      hours: getRemainingHours(nowDayJs, timeStampDayJs),
      days: getRemainingDays(nowDayJs, timeStampDayJs),
    };
  };

  const getRemainingSeconds = (nowDayJs, timeStampDayJs) => {
    const seconds = timeStampDayJs.diff(nowDayJs, "seconds") % 60;
    return padWithZeros(seconds, 2);
  };

  const getRemainingMinutes = (nowDayJs, timeStampDayJs) => {
    const minutes = timeStampDayJs.diff(nowDayJs, "minutes") % 60;
    return padWithZeros(minutes, 2);
  };

  const getRemainingHours = (nowDayJs, timeStampDayJs) => {
    const hours = timeStampDayJs.diff(nowDayJs, "hours") % 24;
    return padWithZeros(hours, 2);
  };

  const getRemainingDays = (nowDayJs, timeStampDayJs) => {
    const days = timeStampDayJs.diff(nowDayJs, "days");
    return days;
  };

  const padWithZeros = (number, minLength) => {
    const numberString = number.toString();
    if (numberString.length >= minLength) {
      return numberString;
    } else {
      return "0".repeat(minLength - numberString.length) + numberString;
    }
  };

  useEffect(() => {
    const intervalId = setInterval(() => {
      updateRemaninigTime(countdownTimeStamp);
    }, 1000);
    return () => clearInterval(intervalId);
  }, [countdownTimeStamp]);

  const updateRemaninigTime = (countdownTimeStamp) => {
    setRemainingTime(getRemainingTime(countdownTimeStamp));
  };

  return (
    <div>
      <span>{remainingTime.days} </span>
      <span>days </span>
      <span>{remainingTime.hours} </span>
      <span>hours </span>
      <span>{remainingTime.minutes} </span>
      <span>minutes </span>
      <span>{remainingTime.seconds} </span>
      <span>seconds </span>
    </div>
  );
};

export default Countdown;
1 Answers

you can use two function to make your goals!

import { useState, useEffect } from "react";
import dayJs from "dayjs";
var utc = require("dayjs/plugin/utc");
var timezone = require("dayjs/plugin/timezone");
dayJs.extend(utc);
dayJs.extend(timezone);

const defaultRemainingTime = {
  seconds: "00",
  minutes: "00",
  hours: "00",
  days: "00",
  initialValue: true,
};

const Countdown = () => {
  const [remainingTime, setRemainingTime] = useState(defaultRemainingTime);  

  function getNextChristimaDay(){
    let today = dayJs().tz("Europe/Helsinki");
    let christmasYear = today.year();

    if (today.month() == 11 && today.day() > 25) {
      christmasYear = christmasYear + 1;
    }

    let christmasDate = new Date(christmasYear, 11, 25);
    const christmasDateTimeStamp = 
     Math.round(christmasDate.getTime());
    return christmasDateTimeStamp;    
  }

  useEffect(() => {
    const getRemainingSeconds = (nowDayJs, timeStampDayJs) => {
        const seconds = timeStampDayJs.diff(nowDayJs, "seconds") % 60;
        return padWithZeros(seconds, 2);
    };

    const getRemainingMinutes = (nowDayJs, timeStampDayJs) => {
    const minutes = timeStampDayJs.diff(nowDayJs, "minutes") % 60;
    return padWithZeros(minutes, 2);
    };

    const getRemainingHours = (nowDayJs, timeStampDayJs) => {
    const hours = timeStampDayJs.diff(nowDayJs, "hours") % 24;
    return padWithZeros(hours, 2);
    };

    const getRemainingDays = (nowDayJs, timeStampDayJs) => {
    const days = timeStampDayJs.diff(nowDayJs, "days");
    return days;
    };

    const padWithZeros = (number, minLength) => {
    const numberString = number.toString();
    if (numberString.length >= minLength) {
        return numberString;
    } else {
        return "0".repeat(minLength - numberString.length) + numberString;
    }
    };

    const getRemainingTime = () => {
        const timeStampDayJs = dayJs(getNextChristimaDay()).tz("Europe/Helsinki");
        const nowDayJs = dayJs().tz("Europe/Helsinki");
                
        return {
          seconds: getRemainingSeconds(nowDayJs, timeStampDayJs),
          minutes: getRemainingMinutes(nowDayJs, timeStampDayJs),
          hours: getRemainingHours(nowDayJs, timeStampDayJs),
          days: getRemainingDays(nowDayJs, timeStampDayJs),
        };
    };
    
    setInterval(() => {        
        setRemainingTime(getRemainingTime());
    }, 1000);
  }, [setRemainingTime]);

  function showMessage(d, h, m, s){
    if(d <= 0 && h <= 0 && m <= 0 && s <= 0){
        return <span>Happy Christmas!</span>
    } else {
        return (
            <>
                <span>{d}</span>
                <span>days </span>
                <span>{h}</span>
                <span>hours </span>
                <span>{m}</span>
                <span>minutes </span>
                <span>{s}</span>
                <span>seconds </span>
            </>
        )
    }
  }

  const { days, hours, minutes, seconds, initialValue } = remainingTime;
  
  return (
    <div>                   
        {!initialValue && showMessage(days, hours, minutes, seconds)}      
    </div>
  );
};

export default Countdown;

I remade your code and put two principals functions look above:

// this code you will use to discover the next Christmas day in timestamp, then you can not worry about the fixed timestamp value.

function getNextChristimaDay(){
  let today = dayJs().tz("Europe/Helsinki");
  let christmasYear = today.year();

   if (today.month() == 11 && today.day() > 25) {
    christmasYear = christmasYear + 1;
   }

   let christmasDate = new Date(christmasYear, 11, 25);
   const christmasDateTimeStamp = 
     Math.round(christmasDate.getTime());
    return christmasDateTimeStamp;    
 }


// In this step we resolved a problem with fixed text about remaning days or happy Christmas.
function showMessage(d, h, m, s){
    if(d <= 0 && h <= 0 && m <= 0 && s <= 0){
        return <span>Happy Christmas!</span>
    } else {
        return (
            <>
                <span>{d}</span>
                <span>days </span>
                <span>{h}</span>
                <span>hours </span>
                <span>{m}</span>
                <span>minutes </span>
                <span>{s}</span>
                <span>seconds </span>
            </>
        )
    }
  }
Related