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

minDate and maxDate to block navigation #1311

Merged
merged 14 commits into from
Nov 28, 2018
Merged

minDate and maxDate to block navigation #1311

merged 14 commits into from
Nov 28, 2018

Conversation

pedroabreu
Copy link
Contributor

Adds feature to block month navigation depending on a minDate/maxDate prop.

Resolves #339

@coveralls
Copy link

coveralls commented Aug 14, 2018

Coverage Status

Coverage increased (+0.03%) to 85.104% when pulling 9767c36 on pedroabreu:feat/disable-navigation into 9426234 on airbnb:master.

ljharb
ljharb previously requested changes Aug 15, 2018
@@ -33,6 +35,8 @@ const propTypes = forbidExtraProps({
});

const defaultProps = {
hasPrev: true,
Copy link
Member

Choose a reason for hiding this comment

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

boolean props should default to false, so that absence and falsiness are the same. Can the naming of these be inverted?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed! Let's call this disablePrev and disableNext instead

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair point. I've come up with isPrevMonthBlocked/isNextMonthBlocked, to try and keep it consistent with isDayBlocked prop.

enableOutsideDays,
} = this.props;

const isMinDateVisible = isDayVisible(minDate, visibleMonth, numberOfMonths, enableOutsideDays);
Copy link
Member

Choose a reason for hiding this comment

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

If minDate is falsy, it seems like there’s no point in calling isDayVisible?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, it will return false in that case.

Happy to change it to make it more readable. I guess it's a good thing not to rely on the method accounting for that scenario (non-moment date). Make it less "magical"

} = this.props;

const isMinDateVisible = isDayVisible(minDate, visibleMonth, numberOfMonths, enableOutsideDays);
const isMaxDateVisible = isDayVisible(maxDate, visibleMonth, numberOfMonths, enableOutsideDays);
Copy link
Member

Choose a reason for hiding this comment

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

Same here

import isBeforeDay from './isBeforeDay';
import isAfterDay from './isAfterDay';

export default function isDayVisible(day, month, numberOfMonths, enableOutsideDays) {
if (!moment.isMoment(day)) return false;
Copy link
Member

Choose a reason for hiding this comment

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

This is a good change, even if my above comments are addressed (either this function should throw or return false on a non-moment object)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Followed the same pattern as other utils that do an early return if non-moment object, not sure if it was intended not to have a check but the tests don't break

@ljharb ljharb added the semver-minor: new stuff Any feature or API addition. label Aug 15, 2018
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.

I'm super hype on this idea. Thank you for contributing!

One thing I was thinking about is that I'd love to align this somehow with the concept of the blocked-outside-range modifier. Specifically, I'd like to eventually replace isOutsideRange with minDate and maxDate in a follow-up breaking change. However, that means that I don't think disabling the month navigation should be intrinsically tied to these props. Maybe we could have:

maxInRangeDate
minInRangeDate
disableMonthNavOnOutsideRange

(it could be less verbose, but that's the general gist of what I am thinking)

@@ -73,6 +73,8 @@ const propTypes = forbidExtraProps({
horizontalMonthPadding: nonNegativeInteger,

// navigation props
hasPrev: PropTypes.bool,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's call this disablePrev and disableNext to address Jordan's comments.

@@ -33,6 +35,8 @@ const propTypes = forbidExtraProps({
});

const defaultProps = {
hasPrev: true,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed! Let's call this disablePrev and disableNext instead

@@ -138,8 +147,9 @@ function DayPickerNavigation({
]),
)}
aria-label={phrases.jumpToPrevMonth}
onClick={onPrevMonthClick}
onClick={hasPrev ? onPrevMonthClick : () => {}}
Copy link
Collaborator

Choose a reason for hiding this comment

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

let's have this be undefined if it's disabled, so something like hasPrev ? onPrevMonthClick : undefined instead

onKeyUp={(e) => {
if (!hasPrev) return;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here. let's just not define this function if hasPrev is false.

@@ -177,8 +188,9 @@ function DayPickerNavigation({
]),
)}
aria-label={phrases.jumpToNextMonth}
onClick={onNextMonthClick}
onClick={hasNext ? onNextMonthClick : () => {}}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same comments apply here about using undefined instead of a thunk

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Curious: I guess there's an advantage by using undefined instead of a thunk ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Setting it to undefined is akin to not having that prop set at all, which means no unnecessary click handler. Otherwise you're adding a click handlers to things that don't need them, only to call an empty function upon invocation.

onKeyUp={(e) => {
if (!hasNext) return;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's not define this when we're disabling the button.

src/components/DayPickerNavigation.jsx Show resolved Hide resolved
@@ -747,6 +752,23 @@ export default class DayPickerRangeController extends React.Component {
});
}

getNavigationStatus(visibleMonth) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm, I'm not sure that this name is clear. I'd almost rather have two methods, one that asks if we should disable prev month navigation and one that asks about next month navigation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it should be kept as one method, as the only difference between them would be the arguments (date, visibleMonth). Maybe shouldDisableMonthNavigation ?

@pedroabreu
Copy link
Contributor Author

pedroabreu commented Aug 15, 2018

@majapw I'm not that familiar with all features of the component but is isOutsideRange used to detect if a range is bigger than the one specified ?

I noticed that isOutsideRange is a function, so is there any range specified besides minimumNights ?

I can see a use case (not sure if it's the one you're mentioning) where I specify that I can only select a maxNumberOfNights of 4 months, so the calendar would block navigation past/before 4 months from the startDate.

Can you expand a bit on your idea ? I can try to have a look (perhaps not for this PR)

Also, I think I addresed all the comments (cc @ljharb)

@ljharb ljharb dismissed their stale review August 15, 2018 20:46

LGTM, deferring to maja and diane

@pedroabreu
Copy link
Contributor Author

@majapw any other thoughts on this ?

@saadulde45
Copy link

Any update on this? This seems like a good feature to have, if there are no blockers can it please be merged?

@pedroabreu
Copy link
Contributor Author

Anything missing ? cc @majapw @ljharb @backwardok

@ljharb
Copy link
Member

ljharb commented Oct 19, 2018

Please do rebase it, instead of clicking "update branch" which produces a merge commit.

@pedroabreu
Copy link
Contributor Author

Anything missing ? cc @majapw @ljharb @backwardok

Copy link
Contributor

@backwardok backwardok left a comment

Choose a reason for hiding this comment

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

Sorry for the delay! I'm good after the changes I suggested but I defer stamping to @majapw since she's more familiar with the codebase than I am

src/components/DayPickerNavigation.jsx Outdated Show resolved Hide resolved
src/components/DayPickerNavigation.jsx Show resolved Hide resolved
src/components/DayPickerNavigation.jsx Outdated Show resolved Hide resolved
src/components/DayPickerRangeController.jsx Outdated Show resolved Hide resolved
@elinskytap
Copy link

@majapw do you have time to review this? Really looking forward to seeing this to be released. Thanks!!

@backwardok backwardok merged commit 37f8aba into react-dates:master Nov 28, 2018
@avivash
Copy link

avivash commented Mar 12, 2019

I see these props were only added to DayPickerRangeController. Is there any way to use them with the DateRangePicker component? CC: @pedroabreu @ljharb @backwardok

@pedroabreu
Copy link
Contributor Author

Seems to be as easy as adding minDate and maxDate to the DateRangePicker component. I can have a look with more time tomorrow

@avivash
Copy link

avivash commented Mar 12, 2019

@pedroabreu thanks for the quick reply. When I try adding them to DateRangePicker, I get an error, as it doesn't recognize the props
image

@pedroabreu
Copy link
Contributor Author

pedroabreu commented Mar 13, 2019 via email

@avivash
Copy link

avivash commented Mar 13, 2019

Sorry, I mean add them as props to the component and pass it down to the
controller.

@pedroabreu sorry, I think I'm misunderstanding you. Are you suggesting a hierarchy like this?:

<DateRangePicker>
  <DayPickerRangeController
    startDate={this.state.startDate} // momentPropTypes.momentObj or null,
    endDate={this.state.endDate} // momentPropTypes.momentObj or null,
    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,
    maxdate={moment().endOf('month')}
  />
</DateRangePicker>

@ljharb
Copy link
Member

ljharb commented Mar 13, 2019

I believe they are suggesting making a change in this package itself to pass those props down.

@pedroabreu
Copy link
Contributor Author

Sorry, it's what @ljharb mentioned. These props are not part of the DateRangePicker, only the DateRangePickerController.

I'll open a PR for this, should be pretty straightforward (famous last words)

@avivash
Copy link

avivash commented Mar 13, 2019

Thanks @ljharb / @pedroabreu. That's great! I'll be sure to look out for a PR

@pedroabreu
Copy link
Contributor Author

PR opened: #1582

@avivash
Copy link

avivash commented Mar 13, 2019

Thanks for getting this addressed so quickly!

@ianduvall
Copy link
Contributor

PR to improve upon the stories created by this PR: #1598

@bdrazen
Copy link

bdrazen commented Apr 20, 2020

Does this not work for the SingleDatePicker?

Edit: Nvm, addressed in later PR: #1927

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
semver-minor: new stuff Any feature or API addition.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Limited months range navigation (add min / max date props)