The reservation calendar (or BookingCalendar
) component is a React-based calendar that allows users to select dates for booking. It includes the ability to retrieve existing reservations and block off those dates on the calendar, as well as select and highlight date ranges for new reservations.
Getting Started
The first step in building this component is to import the necessary modules. In this case, we need React
for building the component, useState
and useEffect
hooks for handling state and lifecycle methods, react-calendar
for displaying the calendar UI, and axios
for making HTTP requests to retrieve data.
import React, { useState, useEffect } from 'react';
import Calendar from 'react-calendar';
import axios from 'axios';
import "../Styling/BookingCalendar.css"
State and HTTP Requests
The component has several pieces of state:
reservations
: An array of objects representing existing reservations retrieved via an HTTP requestblockedDates
: An array of objects representing the start and end dates of existing reservations, formatted asfrom
andto
start
: ADate
object representing the start date of a new reservationend
: ADate
object representing the end date of a new reservation
const [reservations, setReservations] = useState([]);
const [blockedDates, setBlockedDates] = useState([]);
const [start, setStart] = useState(null);
const [end, setEnd] = useState(null);
The reservations are retrieved using the useEffect
hook, which runs once when the component is mounted. We make an HTTP GET request to retrieve the reservations, then set the state using the setReservations
function:
useEffect(() => {
axios.get('/reservations')
.then(response => {
setReservations(response.data);
});
}, []);
We also have another useEffect
hook that runs whenever the reservations
state changes. This hook converts the reservations data into an array of objects representing the start and end dates of each reservation, then sets the blockedDates
state:
useEffect(() => {
const dates = reservations.map(reservation => {
return {
from: new Date(reservation.start_date),
to: new Date(reservation.end_date),
};
});
setBlockedDates(dates);
}, [reservations]);
Selecting and Highlighting Dates
The BookingCalendar
component uses the Calendar
component from react-calendar
to display the UI for selecting and highlighting dates.
The tileClassName
function is used to determine the class name for each date tile, based on whether the date is blocked by an existing reservation or part of a selected date range:
const tileClassName = ({ date, view }) => {
if (view === 'month') {
if (isBlocked(date)) {
return 'blocked';
} else if (
start &&
!end &&
start.toDateString() === date.toDateString()
) {
return 'selected start';
} else if (
start &&
end &&
date >= start &&
date <= end
) {
return 'selected range';
} else {
return 'available';
}
}
};
The isBlocked
function is used to check if a date is blocked by an existing reservation. It returns true
if the given date is within the start and end dates of any existing reservation:
const isBlocked = date =>
blockedDates.some(d => date >= d.from && date <= d.to);
The handleSelect
function is called every time the user clicks on a date on the calendar. This function will be responsible for selecting dates and updating the state of start
and end
accordingly. If the selected date is blocked, the function will return and nothing will happen.
Here is what the handleSelect
function does:
- If
start
is not set, it means we are selecting the first date of the range. So, we setstart
to the selected date andend
tonull
. - If
start
is set butend
is not, it means we are selecting the second date of the range. If the selected date is after thestart
date, we setend
to the selected date. Otherwise, we do nothing. - If both
start
andend
are set, it means the range has been selected and we need to clear the selection. So, we setstart
andend
tonull
.
After updating the start
and end
state, the onSelectDate
function is called to pass the selected range to the parent component.
Finally, the tileClassName
function is passed to the Calendar
component. This function is used to set the class name of each tile on the calendar based on its date and the current selection state. It returns different class names depending on whether the date is available, blocked, or selected. This allows us to style the tiles accordingly using CSS.
The CSS styles for the calendar are defined in the style
tag at the bottom of the component. The styles define the size and appearance of the calendar, as well as the colors for each tile class.
Implementation
To use this component in your project, you can simply import it and include it in your JSX code, passing in the required props. Here is an example of how to use the component:
import BookingCalendar from './BookingCalendar';
function Form() {
const handleSelectDate = ({ start, end }) => {
console.log(`Selected range: ${start} to ${end}`);
}; return (
<div className="Form">
<BookingCalendar
selectedStart={new Date()}
selectedEnd={null}
onSelectDate={handleSelectDate}
/>
</div>
);
}
In this example, we pass in a function called handleSelectDate
as the onSelectDate
prop. This function will be called every time a date range is selected on the calendar. It receives an object with start
and end
properties that represent the selected range.
That’s it! You now have a fully functional booking calendar component that you can use in your React projects. I hope you found this article helpful in understanding how the component works and how it can be customized to suit your needs.