diff --git a/src/components/Search/FilterComponents/DateFilterBase.tsx b/src/components/Search/FilterComponents/DateFilterBase.tsx index 1f1fa7cffec78..e8b35089e94c2 100644 --- a/src/components/Search/FilterComponents/DateFilterBase.tsx +++ b/src/components/Search/FilterComponents/DateFilterBase.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import Button from '@components/Button'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; @@ -35,6 +35,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 */ @@ -59,6 +61,7 @@ function DateFilterBase({ isSearchAdvancedFiltersFormLoading, onBackButtonPress, onSubmit, + onReset, onDateValuesChange, onDateModifierChange, shouldShowButtonsOnlyWithDateModifier = false, @@ -72,6 +75,7 @@ function DateFilterBase({ const normalizedDefaultDateValues = useMemo(() => ({...getEmptyDateValues(), ...defaultDateValues}), [defaultDateValues]); const searchDatePresetFilterBaseRef = useRef(null); + const scrollViewRef = useRef>(null); const [selectedDateModifierState, setSelectedDateModifierState] = useState(null); const [shouldShowRangeError, setShouldShowRangeError] = useState(false); const [rangeDisplayText, setRangeDisplayText] = useState(() => @@ -150,6 +154,13 @@ function DateFilterBase({ const computedTitle = getDateModifierTitle(selectedDateModifier, title ?? '', translate); + useLayoutEffect(() => { + if (!shouldShowRangeError || selectedDateModifier !== CONST.SEARCH.DATE_MODIFIERS.RANGE) { + return; + } + scrollViewRef.current?.scrollToEnd({animated: true}); + }, [selectedDateModifier, shouldShowRangeError]); + const reset = useCallback(() => { if (!searchDatePresetFilterBaseRef.current) { return; @@ -157,15 +168,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) { @@ -201,6 +216,7 @@ function DateFilterBase({ /> )} diff --git a/src/components/Search/FilterComponents/DatePresetFilterBase.tsx b/src/components/Search/FilterComponents/DatePresetFilterBase.tsx index f38999e708b91..bade9e980bcb9 100644 --- a/src/components/Search/FilterComponents/DatePresetFilterBase.tsx +++ b/src/components/Search/FilterComponents/DatePresetFilterBase.tsx @@ -257,6 +257,9 @@ function DatePresetFilterBase({ } // eslint-disable-next-line react-hooks/set-state-in-effect setDateValue(CONST.SEARCH.DATE_MODIFIERS.RANGE, getRangeQueryValue(rangeEphemeralValues.from, rangeEphemeralValues.to) || undefined); + if (rangeEphemeralValues.from && rangeEphemeralValues.to) { + onRangeValidationErrorChange?.(false); + } // eslint-disable-next-line react-hooks/exhaustive-deps }, [rangeEphemeralValues.from, rangeEphemeralValues.to]); @@ -345,6 +348,7 @@ function DatePresetFilterBase({ if (selectedDateModifier === CONST.SEARCH.DATE_MODIFIERS.RANGE) { setRangeEphemeralValues({}); + rangeEntrySnapshotRef.current = undefined; } else { setEphemeralDateValue(undefined); } @@ -440,10 +444,16 @@ function DatePresetFilterBase({ fromValue={rangeEphemeralValues.from} toValue={rangeEphemeralValues.to} onFromSelected={(date) => { + if (date && rangeEphemeralValues.to) { + onRangeValidationErrorChange?.(false); + } setRangeEphemeralValues((prev) => ({...prev, from: date})); onRangeValidationErrorChange?.(false); }} onToSelected={(date) => { + if (rangeEphemeralValues.from && date) { + onRangeValidationErrorChange?.(false); + } setRangeEphemeralValues((prev) => ({...prev, to: date})); onRangeValidationErrorChange?.(false); }} diff --git a/src/components/Search/FilterComponents/RangeDatePicker.tsx b/src/components/Search/FilterComponents/RangeDatePicker.tsx index a9f368d33cf88..76f3fceb655f2 100644 --- a/src/components/Search/FilterComponents/RangeDatePicker.tsx +++ b/src/components/Search/FilterComponents/RangeDatePicker.tsx @@ -40,7 +40,7 @@ function RangeDatePicker({fromValue, toValue, onFromSelected, onToSelected, forc // eslint-disable-next-line rulesdir/prefer-shouldUseNarrowLayout-instead-of-isSmallScreenWidth const {isSmallScreenWidth} = useResponsiveLayout(); const shouldStack = forceVertical || isSmallScreenWidth; - const fromMaxDate = parseCalendarDate(toValue) ?? CONST.CALENDAR_PICKER.MAX_DATE; + const fromMaxDate = parseCalendarDate(toValue); const toMinDate = parseCalendarDate(fromValue) ?? CONST.CALENDAR_PICKER.MIN_DATE; return (