This post is part of a new series where we build a clone of Airbnb with Next.js. See the first post here.

Now we can select a start and end date to book a place (something we’ll implement later!) but we have one thing to do: start and end dates are not synced!

To start with, the end date can’t be today: it must default to “tomorrow” if the start date is set to “today” by default

Then, we must make and ensure a relationship between the start and end date: the end date can’t be before the start date. When we change the start date, the end date will point to the day after it, unless the end date is still a valid one (e.g. it’s still after the start date)

Let’s start.

First, I’m going to set that “today” is not a valid selectable date for the end day:

components/DateRangePicker.js

dayPickerProps={{
modifiers: {
disabled: [
new Date(),
{
before: new Date()
}
]
}
}}

Then, I am going to set the end date to “tomorrow” by default. I do so by passing the value prop to the DayPickerInput component. To the first I pass startDate, to the second endDate, which correspond, at page load time, at today and tomorrow’s dates:

import { useState } from 'react'

const today = new Date()
const tomorrow = new Date(today)
tomorrow.setDate(tomorrow.getDate() + 1)

//...

export default function DateRangePicker() {
const [startDate, setStartDate] = useState(today)
const [endDate, setEndDate] = useState(tomorrow)

return (
<div className='date-range-picker-container'>
<div>
<label>From:</label>
<DayPickerInput
formatDate={formatDate}
format={format}
value={startDate}
parseDate={parseDate}
placeholder={${dateFnsFormat(new Date(), format)}} dayPickerProps={{ modifiers: { disabled: { before: new Date() } } }} onDayChange={day => { setStartDate(day) }} /> </div> <div> <label>To:</label> <DayPickerInput formatDate={formatDate} format={format} value={endDate} parseDate={parseDate} placeholder={${dateFnsFormat(new Date(), format)}}
dayPickerProps={{
modifiers: {
disabled: [
new Date(),
{
before: new Date()
}
]
}
}}
onDayChange={day => {
setEndDate(day)
}}
/>
</div>

....

Cool!

Now let’s make the end date adjust when I choose a start date after the end date. I am going to +1 on the end date, so if I select, let’s say, January 21 and the end date is January 4, the end date will be changed to January 22.

How? Let’s first add this function that counts the difference of days between 2 dates:

const numberOfNightsBetweenDates = (startDate, endDate) => {
const start = new Date(startDate) //clone
const end = new Date(endDate) //clone
let dayCount = 0

while (end > start) {
dayCount++
start.setDate(start.getDate() + 1)
}

return dayCount
}

I picked it from https://flaviocopes.com/how-to-count-days-between-dates-javascript/.

Now inside the onDayChange prop of the first DayPickerInput, which now contains:

onDayChange={day => {
setStartDate(day)
}}

onDayChange={day => {
setStartDate(day)
if (numberOfNightsBetweenDates(day, endDate) < 1) {
const newEndDate = new Date(day)
newEndDate.setDate(newEndDate.getDate() + 1)
setEndDate(newEndDate)
}
}}

Now, let’s make sure we can’t select an end date prior to startDate. How?

In the end date’s DayPickerInput I change the dayPickerProps to:

dayPickerProps={{
modifiers: {
disabled: [
startDate,
{
before: startDate
}
]
}
}}

so we can’t select startDate (which defaults to “today”) and we can’t select dates prior to startDate.

That’s it! Now if you choose a checkin date in the future, or the same day of the checkout date, the checkout date will change!

See the code on GitHub

Next part: Show the price for the chosen dates

Want to become a better Web Developer? Join the 2022 Web Development Bootcamp!

⭐️⭐️⭐️ Join the 2022 Web Development Bootcamp ⭐️⭐️⭐️