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 () => {
  const [startDate, setStartDate] = useState(new Date())
  const [endDate, setEndDate] = useState(new Date())

  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)
}}

I add:

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 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!

The code for this lesson is available at https://github.com/flaviocopes/airbnb-clone-react-nextjs/commit/53abb6805ce82e15f5e55eb4c2941d87f3dd6be2


Go to the next module