From 187e466239316c0ae9855c968e0cd16fb9a0447f Mon Sep 17 00:00:00 2001 From: "Pujan Shah (via MelvinBot)" Date: Fri, 3 Apr 2026 12:31:08 +0000 Subject: [PATCH 1/6] Fix date filter reset not persisting cleared values to Onyx Add onReset callback to DateFilterBase that persists cleared date values to Onyx without triggering navigation. This prevents the sync effect in DatePresetFilterBase from restoring stale values after a reset from the calendar/range picker view. Co-authored-by: Pujan Shah --- .../Search/FilterComponents/DateFilterBase.tsx | 9 ++++++++- src/components/Search/SearchDatePresetFilterBasePage.tsx | 8 ++++++++ .../SearchFiltersReportFieldPage/ReportFieldDate.tsx | 8 ++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/components/Search/FilterComponents/DateFilterBase.tsx b/src/components/Search/FilterComponents/DateFilterBase.tsx index 308f98091269..9ce9459097c5 100644 --- a/src/components/Search/FilterComponents/DateFilterBase.tsx +++ b/src/components/Search/FilterComponents/DateFilterBase.tsx @@ -34,6 +34,8 @@ type DateFilterBaseProps = { onBackButtonPress?: () => void; /** Callback when the filter is submitted with the selected date values */ onSubmit: (values: SearchDateValues) => void; + /** Callback when the filter is reset, used to persist cleared values without triggering navigation */ + onReset?: (values: SearchDateValues) => void; /** Callback when a date value changes (e.g. preset click or calendar save) */ onDateValuesChange?: (values: SearchDateValues) => void; /** Controlled selected date modifier */ @@ -58,6 +60,7 @@ function DateFilterBase({ isSearchAdvancedFiltersFormLoading, onBackButtonPress, onSubmit, + onReset, onDateValuesChange, onDateModifierChange, shouldShowButtonsOnlyWithDateModifier = false, @@ -156,15 +159,19 @@ function DateFilterBase({ if (selectedDateModifier) { searchDatePresetFilterBaseRef.current.clearDateValueOfSelectedDateModifier(); + const dateValues = searchDatePresetFilterBaseRef.current.getDateValues(); setSelectedDateModifier(null); setShouldShowRangeError(false); onDateModifierChange?.(false); + onReset?.(dateValues); return; } searchDatePresetFilterBaseRef.current.clearDateValues(); + const dateValues = searchDatePresetFilterBaseRef.current.getDateValues(); setShouldShowRangeError(false); - }, [onDateModifierChange, selectedDateModifier, setSelectedDateModifier]); + onReset?.(dateValues); + }, [onDateModifierChange, onReset, selectedDateModifier, setSelectedDateModifier]); const save = useCallback(() => { if (!searchDatePresetFilterBaseRef.current) { diff --git a/src/components/Search/SearchDatePresetFilterBasePage.tsx b/src/components/Search/SearchDatePresetFilterBasePage.tsx index 5852acaa81aa..200cf9260388 100644 --- a/src/components/Search/SearchDatePresetFilterBasePage.tsx +++ b/src/components/Search/SearchDatePresetFilterBasePage.tsx @@ -139,6 +139,14 @@ function SearchDatePresetFilterBasePage({dateKey, titleKey}: SearchDatePresetFil }); Navigation.goBack(ROUTES.SEARCH_ADVANCED_FILTERS.getRoute()); }} + onReset={(values) => { + updateAdvancedFilters({ + [dateOnKey]: values[CONST.SEARCH.DATE_MODIFIERS.ON] ?? null, + [dateBeforeKey]: values[CONST.SEARCH.DATE_MODIFIERS.BEFORE] ?? null, + [dateAfterKey]: values[CONST.SEARCH.DATE_MODIFIERS.AFTER] ?? null, + [dateRangeKey]: values[CONST.SEARCH.DATE_MODIFIERS.RANGE] ?? null, + }); + }} /> ); diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersReportFieldPage/ReportFieldDate.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersReportFieldPage/ReportFieldDate.tsx index 695d06ddae02..2302db658ece 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersReportFieldPage/ReportFieldDate.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersReportFieldPage/ReportFieldDate.tsx @@ -68,6 +68,14 @@ function ReportFieldDate({field, close}: ReportFieldDateProps) { isSearchAdvancedFiltersFormLoading={isSearchAdvancedFiltersFormLoading} onBackButtonPress={close} onSubmit={updateFilter} + onReset={(values) => { + updateAdvancedFilters({ + [dateOnKey]: values[CONST.SEARCH.DATE_MODIFIERS.ON] ?? null, + [dateBeforeKey]: values[CONST.SEARCH.DATE_MODIFIERS.BEFORE] ?? null, + [dateAfterKey]: values[CONST.SEARCH.DATE_MODIFIERS.AFTER] ?? null, + [dateRangeKey]: values[CONST.SEARCH.DATE_MODIFIERS.RANGE] ?? null, + }); + }} /> ); } From b796c3b20c9eee63b464a671fa22a0511df617b4 Mon Sep 17 00:00:00 2001 From: "Pujan Shah (via MelvinBot)" Date: Thu, 16 Apr 2026 10:26:24 +0000 Subject: [PATCH 2/6] Add unit test for DateFilterBase onReset callback Verifies that pressing reset calls onReset with cleared date values, and that omitting onReset does not throw. Co-authored-by: Pujan Shah --- tests/ui/DateFilterBaseResetTest.tsx | 74 ++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 tests/ui/DateFilterBaseResetTest.tsx diff --git a/tests/ui/DateFilterBaseResetTest.tsx b/tests/ui/DateFilterBaseResetTest.tsx new file mode 100644 index 000000000000..735d1ce7b1f6 --- /dev/null +++ b/tests/ui/DateFilterBaseResetTest.tsx @@ -0,0 +1,74 @@ +import {fireEvent, render, screen} from '@testing-library/react-native'; +import React from 'react'; +import Onyx from 'react-native-onyx'; +import ComposeProviders from '@components/ComposeProviders'; +import {LocaleContextProvider} from '@components/LocaleContextProvider'; +import OnyxListItemProvider from '@components/OnyxListItemProvider'; +import DateFilterBase from '@components/Search/FilterComponents/DateFilterBase'; +import type {SearchDateValues} from '@components/Search/FilterComponents/DatePresetFilterBase'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; + +jest.mock('@components/ConfirmedRoute.tsx'); +jest.mock('@libs/Navigation/Navigation'); + +const defaultDateValues: SearchDateValues = { + [CONST.SEARCH.DATE_MODIFIERS.ON]: '2025-01-15', + [CONST.SEARCH.DATE_MODIFIERS.BEFORE]: undefined, + [CONST.SEARCH.DATE_MODIFIERS.AFTER]: undefined, + [CONST.SEARCH.DATE_MODIFIERS.RANGE]: undefined, +}; + +const emptyDateValues: SearchDateValues = { + [CONST.SEARCH.DATE_MODIFIERS.ON]: undefined, + [CONST.SEARCH.DATE_MODIFIERS.BEFORE]: undefined, + [CONST.SEARCH.DATE_MODIFIERS.AFTER]: undefined, + [CONST.SEARCH.DATE_MODIFIERS.RANGE]: undefined, +}; + +function renderDateFilterBase(props: {onSubmit?: jest.Mock; onReset?: jest.Mock; defaultDateValues?: SearchDateValues}) { + return render( + + + , + ); +} + +describe('DateFilterBase reset', () => { + beforeAll(() => + Onyx.init({ + keys: ONYXKEYS, + evictableKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], + }), + ); + + afterEach(async () => { + await Onyx.clear(); + jest.clearAllMocks(); + }); + + it('calls onReset with cleared date values when reset is pressed', () => { + const onReset = jest.fn(); + renderDateFilterBase({onReset}); + + const resetButton = screen.getByText(/^(Reset|common\.reset)$/); + fireEvent.press(resetButton); + + expect(onReset).toHaveBeenCalledTimes(1); + expect(onReset).toHaveBeenCalledWith(emptyDateValues); + }); + + it('does not call onReset when onReset is not provided', () => { + renderDateFilterBase({}); + + const resetButton = screen.getByText(/^(Reset|common\.reset)$/); + // Should not throw when reset is pressed without onReset callback + fireEvent.press(resetButton); + }); +}); From ab08416d2b9dfff0c6a2d3ebba9d52a2dc2adc7c Mon Sep 17 00:00:00 2001 From: "Pujan Shah (via MelvinBot)" Date: Thu, 16 Apr 2026 10:37:55 +0000 Subject: [PATCH 3/6] Remove unnecessary onReset-not-provided test case Co-authored-by: Pujan Shah --- tests/ui/DateFilterBaseResetTest.tsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/ui/DateFilterBaseResetTest.tsx b/tests/ui/DateFilterBaseResetTest.tsx index 735d1ce7b1f6..94a5733aac7d 100644 --- a/tests/ui/DateFilterBaseResetTest.tsx +++ b/tests/ui/DateFilterBaseResetTest.tsx @@ -64,11 +64,4 @@ describe('DateFilterBase reset', () => { expect(onReset).toHaveBeenCalledWith(emptyDateValues); }); - it('does not call onReset when onReset is not provided', () => { - renderDateFilterBase({}); - - const resetButton = screen.getByText(/^(Reset|common\.reset)$/); - // Should not throw when reset is pressed without onReset callback - fireEvent.press(resetButton); - }); }); From be8c21538fb5db932a4e20dddd44496773d68fa0 Mon Sep 17 00:00:00 2001 From: "Pujan Shah (via MelvinBot)" Date: Thu, 16 Apr 2026 10:39:45 +0000 Subject: [PATCH 4/6] Fix: remove trailing blank line to pass Prettier check Co-authored-by: Pujan Shah --- tests/ui/DateFilterBaseResetTest.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ui/DateFilterBaseResetTest.tsx b/tests/ui/DateFilterBaseResetTest.tsx index 94a5733aac7d..b158650ffd1c 100644 --- a/tests/ui/DateFilterBaseResetTest.tsx +++ b/tests/ui/DateFilterBaseResetTest.tsx @@ -63,5 +63,4 @@ describe('DateFilterBase reset', () => { expect(onReset).toHaveBeenCalledTimes(1); expect(onReset).toHaveBeenCalledWith(emptyDateValues); }); - }); From 46442dcfab583d10d1fba8c162c33f67397457c9 Mon Sep 17 00:00:00 2001 From: "Pujan Shah (via MelvinBot)" Date: Thu, 16 Apr 2026 11:15:26 +0000 Subject: [PATCH 5/6] Trigger CI re-run for flaky perf-test The perf-test failure (SidebarLinks render count difference of 1) is unrelated to this PR's date filter changes. Re-triggering CI. Co-authored-by: Pujan Shah From 6a96bd7067a260f34011cde420db018db3b7c7dd Mon Sep 17 00:00:00 2001 From: "Pujan Shah (via MelvinBot)" Date: Fri, 17 Apr 2026 14:26:44 +0000 Subject: [PATCH 6/6] Hide Reset button in nested date filter view Only show the Reset button at the top-level date filter view. When a date modifier is selected (nested view), the Reset button is hidden since the top-level view already has one. Co-authored-by: Pujan Shah --- .../Search/FilterComponents/DateFilterBase.tsx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/Search/FilterComponents/DateFilterBase.tsx b/src/components/Search/FilterComponents/DateFilterBase.tsx index 4ffe356a23d6..78f9dec21a27 100644 --- a/src/components/Search/FilterComponents/DateFilterBase.tsx +++ b/src/components/Search/FilterComponents/DateFilterBase.tsx @@ -238,12 +238,14 @@ function DateFilterBase({ )} {shouldShowActionButtons && ( <> -