React-dates: Custom date range enables 1 date outside of the range in the UI

Created on 25 Jun 2018  路  5Comments  路  Source: airbnb/react-dates

Hello,

I have a very specific requirement for selecting date range in my application. I'm trying out this library and I was able to customize date range with the help of following issue #1137

Requirement:

  1. Block future dates from being selected
  2. Allow current date to be selected
  3. Block dates from 1 year ago from today to be selected.

This is what my code looks like inside of my component that is using the DateRangePicker.

render() {
        const isOutsideRange = (day => {
            let dayIsBlocked = false;
            //Block future dates
            if(Moment().diff(day, 'days') < 0) {
                dayIsBlocked = true;
            }

            //Block days from 1 year ago
            if(Moment().diff(day, 'years') > 0) {
                dayIsBlocked = true;
            }

            return dayIsBlocked;
        })
        return (
                                <div>TBI: Calendar for selecting date range</div>
                                <DateRangePicker
                                    startDate={this.state.startDate} // momentPropTypes.momentObj or null,
                                    startDateId="your_unique_start_date_id" // PropTypes.string.isRequired,
                                    endDate={this.state.endDate} // momentPropTypes.momentObj or null,
                                    endDateId="your_unique_end_date_id" // PropTypes.string.isRequired,
                                    onDatesChange={({ startDate, endDate }) => this.setState({ startDate, endDate })} // PropTypes.func.isRequired,
                                    focusedInput={this.state.focusedInput} // PropTypes.oneOf([START_DATE, END_DATE]) or null,
                                    onFocusChange={focusedInput => this.setState({ focusedInput })} // PropTypes.func.isRequired,
                                    showDefaultInputIcon
                                    isOutsideRange={isOutsideRange} 
                                    autoFocus
                                />
}

Problem:
The date range appears to be working. Future dates are blocked; Current day is enabled; and dates from 1 year ago is also blocked. Problem is, whenever I start selecting a date range, 1 extra date in future gets enabled in the Calendar. Good thing is that I'm not able to select that future date as my "End Date".

For example: Today is June 25, 2018. In the Calendar, I don't see any dates after June 25, 2018 as enabled. I select a "Start Date" (i.e. June 20, 2018) and right away, June 26, 2018 becomes enabled in the Calendar. I can only select up to June 25, 2018 as my "End Date". Once the range is selected and the calendar disappears, if I click on the calendar icon or input fields to see the range, June 26, 2018 is disabled again. But, it will become visually enabled again if I start to select a new date.

What did I do wrong in the sample code above? Could this be a bug?

Most helpful comment

Never mind about the 1 day selection comment above. I needed to add minimumNights={0} to the DateRangePicker component's configuration. With this and your suggestion about isAfterDay method, now everything looks good. Thanks a lot for your help.

All 5 comments

...and suddenly that 1 future date is now always enabled and allows me to select it. I made some minor changes (even tried undoing all the changes) but for some reason it's working differently now. I'm now able to select that 1 future date as part of the date range. This what my current code looks like. If you compare with my snippet in the description above, you'll see very minor changes.

render() {
        const isOutsideRange = (day => {
            let dayIsBlocked = false;
            //Block future dates
            if(Moment().diff(day, 'days') < 0) {
                dayIsBlocked = true;
            }

            //Block days from 1 year ago
            if(Moment().diff(day, 'years') > 0) {
                dayIsBlocked = true;
            }

            return dayIsBlocked;
        })
        return (
                                <div>TBI: Calendar for selecting date range</div>
                                <DateRangePicker
                                    startDate={this.state.startDate} // momentPropTypes.momentObj or null,
                                    startDateId="reportCalendar-startDate" // PropTypes.string.isRequired,
                                    endDate={this.state.endDate} // momentPropTypes.momentObj or null,
                                    endDateId="reportCalendar-endDate" // PropTypes.string.isRequired,
                                    onDatesChange={({ startDate, endDate }) => this.setState({ startDate, endDate })} // PropTypes.func.isRequired,
                                    focusedInput={this.state.focusedInput} // PropTypes.oneOf([START_DATE, END_DATE]) or null,
                                    onFocusChange={focusedInput => this.setState({ focusedInput })} // PropTypes.func.isRequired,
                                    showDefaultInputIcon
                                    isOutsideRange={isOutsideRange}
                                />
}

very confused at this point...

hmm, the initial bug you filed seems like it could be some faulty minimum nights logic. Could there be some time zone trickery happening as well?

Instead of:

if(Moment().diff(day, 'days') < 0) {
  dayIsBlocked = true;
}

does using the react-dates isAfterDay helper change anything?

import isAfterDay from 'react-dates/lib/utils/isAfterDay';
...
if (isAfterDay(day, Moment())) {
  dayIsBlocked = true;
}

interesting... it does fix the issue, although I'm not really sure why the timezone would play a role here. It's all on the client side, right?

With your suggestion of using isAfterDay() method, I don't see that 1 extra future date enabled/selectable anymore. Now I just need to figure out how to allow selecting 1 day to be selected as the entire range (both start date and end date). The way I had it before I could select 1 day as the range.

Never mind about the 1 day selection comment above. I needed to add minimumNights={0} to the DateRangePicker component's configuration. With this and your suggestion about isAfterDay method, now everything looks good. Thanks a lot for your help.

Glad to see it worked out!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mccambridge picture mccambridge  路  20Comments

thinhdd88 picture thinhdd88  路  22Comments

asulaiman picture asulaiman  路  28Comments

wub picture wub  路  20Comments

comron picture comron  路  22Comments