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

Add DatePicker component #5509

Merged
merged 33 commits into from
Sep 29, 2021
Merged

Add DatePicker component #5509

merged 33 commits into from
Sep 29, 2021

Conversation

kidroca
Copy link
Contributor

@kidroca kidroca commented Sep 24, 2021

Details

Adds a native datepicker per each platform

Fixed Issues

$ #5340

Tests

  1. Go to a place that uses a DatePicker (Reimbursement Account Page)
    • IdentityForm: BeneficialOwner step, Requestor step,
    • Company Step
  2. Selecting a date field should bring a datepicker popup (ios/android)
    • on web/desktop we have a native <input type=date />. It supports both typing and popping a calendar picker
    • ios displays a spinner date picker
    • android displays a calendar date picker
  3. Selecting a date from the picker fills the date in the form
  4. Submitting the form should submit the correct value to the backend

⚠️ I couldn't submit any of these forms as I don't know how - I don't have a US bank account that I can register
I've made sure dates are sent as strings in the format YYYY-MM-DD and inspected that the submit payload contains the value

QA Steps

Same as above

Tested On

  • Web
  • Mobile Web
  • Desktop
  • iOS
  • Android

Screenshots

Web

Chrome
Screen.Recording.2021-09-24.at.22.44.52.mov
Safari
Screen.Recording.2021-09-24.at.22.50.37.mov
Firefox
New.Expensify.Mozilla.Firefox.2021-09-24.23-06-15.mp4

Mobile Web

iOS (Safari)
Screen.Recording.2021-09-27.at.10.25.55.mov
Android (Chrome)
Android.Emulator.-.Pixel_2_API_29_5554.2021-09-24.23-09-18.mp4

Desktop

Screen Recording 2021-09-24 at 22.53.19

iOS

Screen.Recording.2021-09-24.at.23.29.57.mov

Android

Android.Emulator.-.Pixel_2_API_29_5554.2021-09-24.23-02-40.mp4

On desktop and web the browser populates a pattern and a datepicker icon
Noticed the native picker on web has the word "reset"
And the behavior to return to the previous
value instead of closing the picker
@kidroca kidroca marked this pull request as ready for review September 24, 2021 20:37
@kidroca kidroca requested a review from a team as a code owner September 24, 2021 20:37
@MelvinBot MelvinBot requested review from deetergp and removed request for a team September 24, 2021 20:37
Pressing inside the field (e.g. not on the label)
is not activated without this
@roryabraham
Copy link
Contributor

@Expensify/design The color choices for the Android calendar picker (see last screen recording) don't feel on-brand. Thoughts?

Copy link
Contributor

@deetergp deetergp left a comment

Choose a reason for hiding this comment

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

The default date template conflicts with the placeholder in Web. Let's nudge the placeholder/title up a few pixels so they don't overlap.
Screen Shot 2021-09-27 at 3 46 01 PM

src/components/DatePicker/datepickerPropTypes.js Outdated Show resolved Hide resolved
Copy link
Contributor

@roryabraham roryabraham left a comment

Choose a reason for hiding this comment

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

Overall this implementation seems good to me. Didn't do much testing though

src/components/DatePicker/index.android.js Show resolved Hide resolved
src/components/DatePicker/index.android.js Outdated Show resolved Hide resolved
src/components/DatePicker/index.android.js Outdated Show resolved Hide resolved
src/components/DatePicker/index.android.js Outdated Show resolved Hide resolved
src/components/DatePicker/index.js Outdated Show resolved Hide resolved
src/components/DatePicker/index.ios.js Outdated Show resolved Hide resolved
src/components/DatePicker/index.js Outdated Show resolved Hide resolved
componentDidMount() {
if (this.inputRef) {
// Adds nice native datepicker on web/desktop. Not possible to set this through props
this.inputRef.type = 'date';
Copy link
Contributor

Choose a reason for hiding this comment

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

This feels like a hack/code smell to me, but I don't have a better suggestion atm. Seems like it works so we can go with it for now.

Copy link
Contributor Author

@kidroca kidroca Sep 28, 2021

Choose a reason for hiding this comment

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

Yep, it's hackish ⌨️ but allows us to reuse ExpensiTextInput
Other options are:

  • don't set the type to "date" and not have the native picker for web/mWeb/desktop.
  • use html elements (since we're on a web/desktop file) and return <input type=date />. But we'll have to refactor or re-code all the styles to match ExpensiTextInput

I did a quick search for other ways to pass this attribute to the native element and didn't find anything


If it makes sense to refine this in the future, we can swap a web specific library (like react-datepicker) and provide a uniform datepicker experience

src/components/DatePicker/index.js Outdated Show resolved Hide resolved
We're using ExpensiInput which override some styles and render the input differently
There's no dropdown arrow.
When we focus the empty datepicker field it's only highlighted in blue. The user
needs to tap again in order to see the native datepicker
To avoid this confusion we're showing the datepicker immediately
# Conflicts:
#	src/pages/ReimbursementAccount/IdentityForm.js
On safari the datepicker would show a done and reset buttons

We're also passing the locale to the datepicker, because
we're partially localizing the modal ourselves it will be
weird if the buttons are shown in one locale while the month
names in another.
RNDatepicker respects the locale only on iOS
Copy link
Contributor Author

@kidroca kidroca left a comment

Choose a reason for hiding this comment

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

Added notes on the last changes

Comment on lines +52 to +61
/**
* Pops the datepicker up when we focus this field. This only works on mWeb
* On mWeb the user needs to tap on the field again in order to bring the datepicker. But our current styles
* don't make this very obvious. To avoid confusion we open the datepicker when the user focuses the field
*/
showDatepicker() {
if (this.inputRef) {
this.inputRef.click();
}
}
Copy link
Contributor Author

@kidroca kidroca Sep 28, 2021

Choose a reason for hiding this comment

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

This was mainly added due to very bad UX on mWeb Android (Chrome).
Tapping on the field would first highlight it. The datepicker would appear if you tap on the input element but due to our styles (from ExpensiInput the input wrapped in a <div>) the target area is actually smaller

Before

Android.Emulator.-.Pixel_2_API_29_5554.2021-09-28.21-22-55.mp4
  • it might not be obvious but the picker would appear only when we tap below the field label near the middle of the field. And only after we've focused the field...

After

Android.Emulator.-.Pixel_2_API_29_5554.2021-09-28.21-24-08.mp4
  • The picker appears as soon as we tap the field (similar to how it works on Android native)
    Tested the rest of the platforms and there aren't any issues

web/index.html Outdated
Comment on lines 31 to 35
input[type=date]::-webkit-calendar-picker-indicator {
position: absolute;
right: 12px;
top: 16px;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This positions the datepicker calendar icon similar to how we do it on other fields (select picker)

  • Edge:
    Edge
  • Chrome:
    image
  • Firefox and Safari are not displaying an icon:
    image

@kidroca
Copy link
Contributor Author

kidroca commented Sep 28, 2021

@deetergp regarding:

In order to test this on iOS, I had to manually install react-native-iphone-x-helper. Is that a requirement of this PR? If so please add it.

...

I'm going to merge the latest changes from main to fix a conflict an the package discrepancy should be fixed as well

After merging latest main I've experienced the same problem, it's seems to be related to cache. The metro bundler suggested to reset it and indeed after clearing cache there were no issues for me

If this error happens again, try this, stop the RN metro server and start it again like this:

npm start -- --reset-cache

@kidroca
Copy link
Contributor Author

kidroca commented Sep 28, 2021

Changes are ready for review

Copy link
Contributor

@deetergp deetergp left a comment

Choose a reason for hiding this comment

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

Code changes look good, but I have one last nitpick: that the Incorporation Date appears center justified in mWeb on iOS at Workspace > Get Started > Connect Manually
Screen Shot 2021-09-28 at 4 01 44 PM

The styles are not getting applied in storybook because they were in web/index.html
To avoid such problems let's move them to the datepicker that uses them

Using a `.css` file is a special case here, because it's impossible to target
pseudo-elements from js code (e.g. ::-webkit)
Copy link
Contributor Author

@kidroca kidroca left a comment

Choose a reason for hiding this comment

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

Notes on the latest changes

Code changes look good, but I have one last nitpick: that the Incorporation Date appears center justified in mWeb on iOS

This should be fixed
image
image

Comment on lines +1 to +8
.expensify-datepicker::-webkit-calendar-picker-indicator {
position: absolute;
right: 12px;
top: 13px;
}
.expensify-datepicker::-webkit-date-and-time-value {
text-align: left;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Noticed these styles weren't getting applied in storybook so I moved them here - in a .css file

Using a .css file is a special case here, because it's impossible to target pseudo-elements from js code (e.g. ::-webkit)

It also keeps things together. It was a bit weird for me to have these defined in index.html

Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a code comment explaining this 😄

Comment on lines +9 to +22
export default {
title: 'Components/Datepicker',
component: DatePicker,
argTypes: {
onChange: {action: 'date changed'},
},
args: {
value: '',
label: 'Select Date',
placeholder: 'Date Placeholder',
errorText: '',
hasError: false,
},
};
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a storybook sample as per: #5509 (comment)

cc @roryabraham

Copy link
Contributor

@deetergp deetergp 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—-thank you for the changes.

Datepicker.propTypes = datepickerPropTypes;
Datepicker.defaultProps = defaultProps;

export default withLocalize(Datepicker);
Copy link
Contributor

Choose a reason for hiding this comment

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

NAB but maybe useful to mention somewhere that iOS is the only platform where we have to manage localization ourselves, and on all others it's controlled by the OS

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'll open a separate request to put a note about this

We're localizing the "Reset" and "Done" button that we put on our own popup.
RNDatepicker would be shown in the system locale. I'm passing the locale to RNDatepicker because it will be weird to have the "Done" and "Reset" buttons in one locale and the picker months in another - it can happen

On Android the buttons and the modal are handled by the system so they are always in the system locale

Comment on lines +1 to +8
.expensify-datepicker::-webkit-calendar-picker-indicator {
position: absolute;
right: 12px;
top: 13px;
}
.expensify-datepicker::-webkit-date-and-time-value {
text-align: left;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a code comment explaining this 😄

@roryabraham roryabraham dismissed their stale review September 29, 2021 19:27

I'm not explicitly approving because I don't have time to test atm, but I'm removing my request for changes. @deetergp feel free to move forward on this PR without me if you've tested and feel comfortable

@deetergp deetergp merged commit ce056a4 into Expensify:main Sep 29, 2021
@OSBotify
Copy link
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@kidroca kidroca deleted the kidroca/datepicker branch September 30, 2021 10:43
@OSBotify
Copy link
Contributor

🚀 Deployed to staging by @deetergp in version: 1.1.3-2 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@OSBotify
Copy link
Contributor

OSBotify commented Oct 4, 2021

🚀 Deployed to production by @chiragsalian in version: 1.1.4-0 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants