feat: date range filter UI and year picker fix (#81501)#85313
feat: date range filter UI and year picker fix (#81501)#85313neil-marcellini merged 26 commits intoExpensify:mainfrom
Conversation
|
Hey, I noticed you changed If you want to automatically generate translations for other locales, an Expensify employee will have to:
Alternatively, if you are an external contributor, you can run the translation script locally with your own OpenAI API key. To learn more, try running: npx ts-node ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
|
Hey! I see that you made changes to our Form component. Make sure to update the docs in FORMS.md accordingly. Cheers! |
|
Note for reviewer, IOS testing still in progress, I've done a small workaround for YearPicker autofocus, adding disableautofocus prop, will try for better fix parellely |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 66ac605396
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const fromMaxDate = toValue ? new Date(toValue) : CONST.CALENDAR_PICKER.MAX_DATE; | ||
| const toMinDate = fromValue ? new Date(fromValue) : CONST.CALENDAR_PICKER.MIN_DATE; |
There was a problem hiding this comment.
Parse range boundary dates in local time
Using new Date(toValue) / new Date(fromValue) for yyyy-MM-dd strings makes the boundary dates UTC-based, which shifts them by one day in non-UTC timezones. Because these values are passed as maxDate/minDate to CalendarPicker, users west of UTC can be blocked from selecting the visible boundary day (for example, a selected to date can make the same calendar day unavailable in the from picker). This regression is specific to timezone context but affects core range selection behavior.
Useful? React with 👍 / 👎.
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
trjExpensify
left a comment
There was a problem hiding this comment.
Adding "Range" was an agreed product change in #convert. 👍
| <View | ||
| // Prevent Android from flattening this View, which can cause | ||
| // background color changes (day selection) to not trigger a native repaint. | ||
| collapsable={false} |
There was a problem hiding this comment.
I think this isn't required, inline styles for backgroundColor and text color are enough.
| // Always provide an explicit backgroundColor so Android (which | ||
| // does not reset a property when the style changes to {}) | ||
| // correctly transitions the selection highlight on every render. | ||
| {backgroundColor: selected ? theme.success : 'transparent'}, |
There was a problem hiding this comment.
| {backgroundColor: selected ? theme.success : 'transparent'}, | |
| {backgroundColor: selected ? theme.success : theme.transparent}, |
| headerMessage, | ||
| maxLength: 4, | ||
| inputMode: CONST.INPUT_MODE.NUMERIC, | ||
| disableAutoFocus: Platform.OS === CONST.PLATFORM.ANDROID, |
There was a problem hiding this comment.
This doesn't look like a correct change, we need to fix it properly as it is working for other CalendarPicker places.
There was a problem hiding this comment.
Working on it, still couldn't find the cause clearly
There was a problem hiding this comment.
We need to use keyboardShouldPersistTaps="handled" for the ScrollView in the DateSelectPopup and DateFilterBase component as suggested by Melvin here. It works well.
There was a problem hiding this comment.
Plz test and then we can revert this file(YearPickerModal) changes.
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppam1.webmAndroid: mWeb ChromeiOS: HybridAppSimulator.Screen.Recording.-.iPhone.15.Pro.-.2026-03-25.at.22.04.16.moviOS: mWeb SafariSimulator.Screen.Recording.-.iPhone.15.Pro.-.2026-03-25.at.22.33.33.movMacOS: Chrome / SafariScreen.Recording.2026-03-25.at.21.59.56.mov |
Mac OS Chrome
Screen.Recording.2026-03-29.at.1.06.39.PM.moviOS
Screen.Recording.2026-03-29.at.1.37.44.PM.movAndroid
HnVideoEditor_2026_03_29_132548730.mp4 |
There was a problem hiding this comment.
Thank you for your updates and applying my requested changes. It's looking pretty good, but there are still some merge conflicts.
Also, please update the manual test videos in the pull request description, showing that you tested the new cases for the previous deploy blockers. For android native it looks like the last video was from March 16.
There was a problem hiding this comment.
NAB: This is not a blocker for merging, but we should really extract some of the sub components to separate files and try to split out separate components as much as possible until each component is very easy to understand on its own and then ideally it's also easy to understand how they relate.
| /** Callback when date values change */ | ||
| onDateValuesChange?: (dateValues: SearchDateValues) => void; | ||
|
|
||
| /** Backward-compatible alias for onDateValuesChange */ | ||
| onDateValueChange?: (dateValues: SearchDateValues) => void; |
There was a problem hiding this comment.
Why do we need both of these. Can we consolidate into onDateValuesChange instead?
|
neil-marcellini
left a comment
There was a problem hiding this comment.
I think it's good to go. Thanks!
|
🚧 @neil-marcellini has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/neil-marcellini in version: 9.3.52-0 🚀
Bundle Size Analysis (Sentry): |
|
I reviewed the changes in this PR against the help site files under Finding: The search operators article ( Changes made:
PR created: #86992 No other help site articles required changes — the "Custom Range" UI feature is a new interaction pattern for existing date filter capabilities, and the other search-related articles (Export Expenses, Using Search on the Reports Page) don't cover filter syntax. |
|
Deploy Blocker ##87017 was identified to be related to this PR. |
|
Deploy Blocker #87019 was identified to be related to this PR. |
|
Deploy Blocker #87020 was identified to be related to this PR. |
|
Deploy Blocker #87026 was identified to be related to this PR. |
|
Follow-up PR: #87055 |
Explanation of Change
Added a new Range date filter option with dual side-by-side calendars for easier date range selection across all search date filters (Date, Approved, Paid, Submitted, Withdrawn, Posted, Exported).
Key Improvements
New Range Mode: Users can now select date ranges using two calendars displayed side-by-side (desktop) or stacked (mobile/sidebar)
Two-Date Validation: Enforces that both From and To dates must be selected when using Range mode, preventing incomplete date ranges
Consistent Display: Date ranges are now displayed as "Range: Jan 1, 2024 - Jan 31, 2024" entries in filter lists and titles
Auto-Detection: When both After and Before dates exist on page load, it automatically switches to Range mode for better UX
Responsive Layouts:
Updated workflow: Custom Date and Custom Range are added for splitting one filter at a time
Fixed Issues
$ #81501
PROPOSAL: #81501 (comment)
Tests
Test Steps
Range Mode - Desktop Popup
Range Mode - Sidebar Filters
Two-Date Validation
Individual After/Before Editing
Mobile/Narrow Layout
Android & iOS - Select year when keyboard is opened
Android - Search - Change dates multiple times
Offline tests
Same as above
QA Steps
Design verification
Verify that the designs are as given in the issue section
Range Mode - Desktop Popup
Range Mode - Sidebar Filters
Two-Date Validation
Individual After/Before Editing
Mobile/Narrow Layout
Android & iOS - Select year when keyboard is opened
Android - Search - Change dates multiple times
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
SVID_20260401_222642_1.mp4
Android: mWeb Chrome
SVID_20260401_222422_1.mp4
iOS: Native
Screen.Recording.2026-04-01.at.10.37.21.PM.mov
iOS: mWeb Safari
Screen.Recording.2026-04-01.at.10.41.55.PM.mov
MacOS: Chrome / Safari
Screen.Recording.2026-04-01.at.9.55.53.PM.mov