-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Select multiple non-consecutive dates #4537
Conversation
…>> This PR adds 2 props which allow users to select multiple isolated dates on the calendar picker. It adds changes to Picker.onChange(), Day.isSelected(), and adds formatting for the input.
Co-authored-by: Thomas Mørch <[email protected]>
Co-authored-by: Thomas Mørch <[email protected]>
Co-authored-by: Thomas Mørch <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅ This pull request was sent to the PullRequest network.
@tbowmo you can click here to see the review status or cancel the code review job.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PullRequest Breakdown
Reviewable lines of change
+ 292
- 14
58% JavaScript (tests)
42% JavaScript
Type of change
Feature - These changes are adding a new feature or improvement to existing code.
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #4537 +/- ##
==========================================
+ Coverage 95.45% 95.51% +0.05%
==========================================
Files 29 29
Lines 2533 2566 +33
Branches 1039 1053 +14
==========================================
+ Hits 2418 2451 +33
Misses 115 115 ☔ View full report in Codecov by Sentry. |
@tbowmo Thanks for submitting this PR! Are you able to check out the missing coverage that Codecov is complaining about? |
Yup will do. |
@martijnrusschen Hmm.. could we bump codecov? I've updated code here and there, and would be nice to get a new status (I'm used to coverage reports running automatically) |
Running it now |
Results are updated now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this looks like a clean and well tested implementation. The only thing I'd necessarily want to block on is what seems to be a minor bug in the isSelected
function.
Ryan Lester <@buu700>
Reviewed with ❤️ by PullRequest
@@ -0,0 +1,15 @@ | |||
() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ISSUE: no-unused-expressions (Severity: Medium)
Expected an assignment or function call and instead saw an expression.
Remediation:
This may be a non-issue if there's an existing convention and bundler configuration that I'm unaware of, but should this not be exported?
🤖 powered by PullRequest Automation 👋 verified by Ryan Lester <@buu700>
setSelectedDates(dates); | ||
}; | ||
return ( | ||
<DatePicker |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ISSUE: react/jsx-no-undef (Severity: Medium)
'DatePicker' is not defined.
Remediation:
Similar to my other comment, not sure if there's a missing import statement for this.
🤖 powered by PullRequest Automation 👋 verified by Ryan Lester <@buu700>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's the same for all the example files, none of them import DatePicker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ryan Lester <@buu700>
@@ -197,6 +197,23 @@ export function safeDateRangeFormat(startDate, endDate, props) { | |||
return `${formattedStartDate} - ${formattedEndDate}`; | |||
} | |||
|
|||
export function safeMultipleDatesFormat(dates, props) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like a lot of care was put into defensive input handling here.
◽ Compliment
Ryan Lester <@buu700>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If length is zero, it should return an empty string. I haven't looked that deep into the underlying code to see if null / undefined is a valid input. But I'm used to do the ?.length test in our own code, so seemed natural for me to do that.
Now that I think of it, it could probably skip a couple of if branches here, and reduce cyclic complexity a bit, by using an array join, like this
export function safeMultipleDatesFormat(dates, props) {
if (dates?.length > 2) {
return `${safeDateFormat(dates[0], props)} (+${dates.length - 1})`;
}
return (dates || []).map((date) => safeDateFormat(date, props)).join(', ')
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also seems that the rest of the safeDateFormat methods is taking care of possible null/undefined inputs
src/day.jsx
Outdated
return false; | ||
} | ||
|
||
if (this.props.selectsMultiple) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be slightly more readable as something like:
const isSelectedDate = this.props.selectsMultiple
? this.props.selectedDates?.some(
(date) => this.isSameDay(date) || this.isSameWeek(date),
)
: this.isSameDay(this.props.selected) || this.isSameWeek(this.props.selected);
const isPreSelectedDate =
this.isSameDay(this.props.preSelection) ||
this.isSameWeek(this.props.preSelection);
return !isSelectedDate && isPreSelectedDate;
You could also go further and factor out (date) => this.isSameDay(date) || this.isSameWeek(date)
to a named isSameDayOrWeek
function, which could be used further below in isSelected
.
🔹 Code Reuse (Nice to have)
Ryan Lester <@buu700>
src/day.jsx
Outdated
isSelected = () => { | ||
if (this.props.selectsMultiple) { | ||
return this.props.selectedDates?.some( | ||
(date) => this.isSameDay(date) || this.isSameWeek(this.props.selected), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks like a bug: this.isSameWeek(this.props.selected)
-> this.isSameWeek(date)
.
In addition to fixing the bug, consider adding a test to cover this specific issue.
🔺 Bug (Critical)
Ryan Lester <@buu700>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added this.isSameWeek() as it apparently was used in "single selected" mode, and thought it was supposed to be there? (I'm fairly new to this react component, so bear with me if I'm mistaken ;))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oooh.. now I see it.. yup, that should be date and not props.selected :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, just to clarify, it seems to me from context that the correct argument to isSameWeek()
on this line should be date
rather than this.props.selected
. (If I misunderstood something, feel free to disregard.)
Ryan Lester <@buu700>
|
||
if ( | ||
!isEqual(this.props.selected, changedDate) || | ||
this.props.allowSameDay || | ||
selectsRange | ||
selectsRange || | ||
selectsMultiple | ||
) { | ||
if (changedDate !== null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be a pre-existing issue, but is there any scenario where changedDate
might be undefined
? If so, consider changing this to != null
(as used in code further below).
🔹 Bug (Nice to have)
Ryan Lester <@buu700>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about this one? haven't touched this part myself..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah okay, sounds good, just something that caught my attention while I was working backwards from your code to see what changedDate
was. Seems out of scope of this PR either way, but may be worth someone taking a look at separately.
Ryan Lester <@buu700>
@tbowmo Does this PR allow to select multiple date ranges? |
No, it does not. Date ranges is another set of properties. I would like to keep this pr as simple as possible, and keep dateranges separated. Also my current usecase is multiple single dates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return false; | ||
} | ||
|
||
const isSelectedDate = this.props.selectsMultiple |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -0,0 +1,59 @@ | |||
import React from "react"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tbowmo Will it be planned to support it in the future? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure how it should be implemented at the moment (should we add yet another set of properties for multiple date ranges?). |
There is one test failing, which also fails if I checkout upstream main branch? |
Yes it looks like the main branch is failing because of some end of month test that's failing. |
Here's a fix #4541 (comment) |
Try pulling in the latest main branch |
Yay.. all green now.. Let me know if there are anything that needs to be done further before it's ready to merge |
Good to go! Thanks for the effort and help getting this over the finish line. |
Rework of #3999 that seems to be stalled.