1. Overview

Challenge & starter files: Advent of JS

Full codes: nilstarbb/advent-of-js/14-calendar-picker

Live Demo: 14 - Calendar Picker || Advent of JavaScript

Preview:

calendar-picker.gif

2. Details

Users should be able to:

  • view calendar with correct days with the current day highlighted
  • navigate through different months

3. Coding

Setup React template

Please be aware: this approach is fine for learning and creating simple demos but is not suitable for production.

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    ...
    <link rel="stylesheet" href="./styles.css" />

    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
  </head>

  <body>
    <div class="wrapper menu" id="wrapper"></div>
    <script type="text/babel" src="./script.js"></script>
  </body>
</html>

script.js:

const { useState, useEffect } = React;

const App = () => {
  return (
    <>
			...
    </>
  );
};

ReactDOM.render(<App />, document.getElementById("wrapper"));

Build the app

The key point of this app is the date calculations based on current date and user’s click action.

All we need are:

  • Today.
  • Current month shown on the page.
  • Number of total days of current month.
  • Day of the first day of current month.

We can get those variables by:

const today = new Date();

const [currentMonth, setCurrentMonth] = useState(today.getMonth());

const firstDayOfMonth = new Date(today.getFullYear(), currentMonth, 1);
const lastDayOfMonth = new Date(today.getFullYear(), currentMonth + 1, 0);

const handleChangeMonth = (i) =>
  setCurrentMonth(
    currentMonth + i >= 0 && currentMonth + i <= 11
      ? currentMonth + i
      : currentMonth
  );

Full codes:

const { useState, useEffect } = React;

const months = {
  0: "January",
  1: "February",
  2: "March",
  3: "April",
  4: "May",
  5: "June",
  6: "July",
  7: "August",
  8: "September",
  9: "October",
  10: "November",
  11: "December",
};

const App = () => {
  const today = new Date();

  const [currentMonth, setCurrentMonth] = useState(today.getMonth());

  const firstDayOfMonth = new Date(today.getFullYear(), currentMonth, 1);
  const lastDayOfMonth = new Date(today.getFullYear(), currentMonth + 1, 0);

  const handleChangeMonth = (i) =>
    setCurrentMonth(
      currentMonth + i >= 0 && currentMonth + i <= 11
        ? currentMonth + i
        : currentMonth
    );

  return (
    <>
      <div className="previous">
        <img
          src="images/previous.svg"
          alt="Previous"
          onClick={() => handleChangeMonth(-1)}
        />
      </div>

      <div className="month">{months[currentMonth]}</div>

      <div className="next">
        <img
          src="images/next.svg"
          alt="Next"
          onClick={() => handleChangeMonth(1)}
        />
      </div>

      <div className="day-of-week">S</div>
      <div className="day-of-week">M</div>
      <div className="day-of-week">T</div>
      <div className="day-of-week">W</div>
      <div className="day-of-week">T</div>
      <div className="day-of-week">F</div>
      <div className="day-of-week">S</div>

      {[...Array(firstDayOfMonth.getDay())].map((a, i) => (
        <div key={i}></div>
      ))}
      {[...Array(lastDayOfMonth.getDate())].map((a, i) => (
        <div
          key={i}
          className={
            currentMonth == today.getMonth() && i + 1 == today.getDate()
              ? "today"
              : ""
          }
        >
          {i + 1}
        </div>
      ))}
    </>
  );
};

ReactDOM.render(<App />, document.getElementById("wrapper"));