Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix blocked days when moment obj time isn't noon #310

Merged
merged 1 commit into from Feb 11, 2017
Merged

Fix blocked days when moment obj time isn't noon #310

merged 1 commit into from Feb 11, 2017

Conversation

timhwang21
Copy link
Collaborator

References #306.

Currently, the logic for checking if days are blocked by looking at number of days difference in doesNotMeetMinimumNights(). However, the day difference rounds down to zero if the time difference is anything < 24hr.

This patch checks if minimumNights === 1 and if so uses isSameDay() instead.

I looked through the specs and couldn't figure out a good place to add a check for this base case, and would appreciate suggestions.

Before
screen shot 2017-02-08 at 2 53 52 am
screen shot 2017-02-08 at 2 54 01 am
(Note that after adding 5 minutes, the next day is now blocked)

After
screen shot 2017-02-08 at 2 56 52 am
screen shot 2017-02-08 at 2 56 59 am
(Day is not blocked after adding 5 minutes)
screen shot 2017-02-08 at 2 57 10 am
(Looking @ the console output, we see that the date has successfully been selected)

@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 86.52% when pulling d4bfb48 on timhwang21:fix-blocked-days-when-moment-not-noon into 4c2c604 on airbnb:master.

@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 86.52% when pulling 00a8e45 on timhwang21:fix-blocked-days-when-moment-not-noon into 4c2c604 on airbnb:master.

@@ -160,6 +160,8 @@ export default class DayPickerRangeController extends React.Component {
if (focusedInput !== END_DATE) return false;

if (startDate) {
if (minimumNights === 1) return isSameDay(day, startDate);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to be an issue that would just be relegated to minimumNights not equaling 1... It seems like it would cause problems for any minimumNights value, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh you're right. I just tested this with my use case, which was without a minimumNights prop (so default 1). Will look into a more robust fix

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I think the helper methods (isSameDay, etc.) all compare both dates at midnight. If we were to change the dayDiff line to:

      const dayDiff = day.clone().startOf('day').diff(startDate.clone().startOf('day'), 'days');

that should work.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying a similar approach just now, but figured I'd describe it here first. I was worried about clone()'s performance, so I was doing dayDiff = day.day() - startDate.day(). Does this look better to you?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

screen shot 2017-02-09 at 7 39 51 pm

That did it, also works for other values of minimum nights.

@@ -303,6 +303,19 @@ describe('DayPickerRangeController', () => {
);
expect(wrapper.instance().doesNotMeetMinimumNights(testDate)).to.equal(false);
});

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New test fails without above change

@coveralls
Copy link

Coverage Status

Coverage remained the same at 86.501% when pulling 424d1db on timhwang21:fix-blocked-days-when-moment-not-noon into 3eafa08 on airbnb:master.

@coveralls
Copy link

Coverage Status

Coverage remained the same at 86.501% when pulling 424d1db on timhwang21:fix-blocked-days-when-moment-not-noon into 3eafa08 on airbnb:master.

@@ -163,7 +163,7 @@ export default class DayPickerRangeController extends React.Component {
if (focusedInput !== END_DATE) return false;

if (startDate) {
const dayDiff = day.diff(startDate, 'days');
const dayDiff = day.day() - startDate.day();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not going to work over week borders as it will only return 0-6 and .date() and .dayOfYear() have similar problems over month and year boundaries respectively. I think unfortunately, something like I recommended earlier with comparing the startOf both days seems the most reasonable. Alternatively, because you are guaranteed that day will always be at noon, you could set startDate.hour('12) and compare those, although that is more brittle.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh, I meant date() which gets date of month and not day(). But that has the same issue with year boundaries. I then tried comparing both .year() and then comparing .dayOfYear(), but it seems like this is a lot less performant than the clone strategy, which surprised me. So looks like yes, that is the way to go.

For what it's worth, I also tested skipping setting day, and it's quite a bit better. What do you think?

I can go ahead with whichever strategy is the most ideal.

Thanks!

screen shot 2017-02-10 at 5 11 41 pm

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Yeah, let's skip doing it for day, but because of https://github.com/airbnb/react-dates/blob/master/src/utils/getCalendarMonthWeeks.js#L5, let's actually do

day.diff(startDate.clone().startOf('day').hour(12), 'days');

just to cover all possible edge cases

@majapw majapw added the semver-patch: fixes/refactors/etc Anything that's not major or minor. label Feb 10, 2017
Copy link
Collaborator

@majapw majapw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@timhwang21
Copy link
Collaborator Author

So it looks like this is failing because the spec has this definition of 'today':

const today = moment().startOf('day');

Changing it to reflect the internal values in the actual picker (noon) fixes the issue. However, I was just hoping for a sanity check on that test change.

Copy link
Collaborator

@majapw majapw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

@@ -12,7 +12,7 @@ import isInclusivelyAfterDay from '../../src/utils/isInclusivelyAfterDay';

import { START_DATE, END_DATE } from '../../constants';

const today = moment().startOf('day');
const today = moment().startOf('day').hours(12);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense. Maybe add a comment about how this is due to the fact that all moment objects passed to interaction handlers from CalendarDay are set to noon. Not necessary but could be nice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That 'today' is in three other specs. For consistency I think it would be better to bring them all in line with this. I can comment on each.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM

@coveralls
Copy link

Coverage Status

Coverage remained the same at 86.501% when pulling 87a5fa0 on timhwang21:fix-blocked-days-when-moment-not-noon into cfc7b16 on airbnb:master.

@coveralls
Copy link

Coverage Status

Coverage remained the same at 86.501% when pulling 87a5fa0 on timhwang21:fix-blocked-days-when-moment-not-noon into cfc7b16 on airbnb:master.

@majapw majapw merged commit 0ab2062 into react-dates:master Feb 11, 2017
@timhwang21 timhwang21 deleted the fix-blocked-days-when-moment-not-noon branch February 11, 2017 00:28
@thecotne
Copy link

just spend about hour and half finding why my app was broken

and i need to say this is stupid (and i don't see this documented anywhere)

so if for example i take values from api/server i need to set hours to 12 in order to get startDate correctly highlighted in UI

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver-patch: fixes/refactors/etc Anything that's not major or minor.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants