diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 92fd2c5f9c40b..066fd2030914e 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -7822,6 +7822,11 @@ const CONST = { AFTER: 'After', BEFORE: 'Before', }, + DATE_FILTER_SUB_PAGE: { + ON: 'on', + AFTER: 'after', + BEFORE: 'before', + }, AMOUNT_MODIFIERS: { LESS_THAN: 'LessThan', GREATER_THAN: 'GreaterThan', diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 6e04cf34c102d..26765e71ce798 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -137,9 +137,13 @@ const ROUTES = { }, SEARCH_COLUMNS: 'search/columns', SEARCH_ADVANCED_FILTERS: { - route: 'search/filters/:filterKey?', - getRoute: (filterKey?: SearchFilterKey | UserFriendlyKey) => { - return `search/filters/${filterKey ?? ''}` as const; + route: 'search/filters/:filterKey?/:subPage?', + getRoute: (filterKey?: SearchFilterKey | UserFriendlyKey, subPage?: string) => { + const baseRoute = `search/filters/${filterKey ?? ''}` as const; + if (!subPage || !filterKey) { + return baseRoute; + } + return `${baseRoute}/${subPage}` as const; }, }, SEARCH_REPORT: { diff --git a/src/components/Search/FilterComponents/DateFilterBase.tsx b/src/components/Search/FilterComponents/DateFilterBase.tsx index 4993720b22f0b..35fe6478f47c7 100644 --- a/src/components/Search/FilterComponents/DateFilterBase.tsx +++ b/src/components/Search/FilterComponents/DateFilterBase.tsx @@ -33,6 +33,10 @@ type DateFilterBaseProps = { onSubmit: (values: SearchDateValues) => void; /** Callback when a date value changes (e.g. preset click or calendar save) */ onDateValuesChange?: (values: SearchDateValues) => void; + /** Controlled selected date modifier */ + selectedDateModifier?: SearchDateModifier | null; + /** Callback for controlled selected date modifier */ + onSelectDateModifier?: (dateModifier: SearchDateModifier | null) => void; /** Callback when the date modifier screen is opened or closed (on/after/before) */ onDateModifierChange?: (isOpen: boolean) => void; /** If true, the Reset/Save buttons are only shown when a date modifier (On/After/Before) is selected. Defaults to false (always show buttons). */ @@ -56,12 +60,26 @@ function DateFilterBase({ shouldShowButtonsOnlyWithDateModifier = false, shouldShowHeader = true, ref, + selectedDateModifier: selectedDateModifierProp, + onSelectDateModifier, }: DateFilterBaseProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const searchDatePresetFilterBaseRef = useRef(null); - const [selectedDateModifier, setSelectedDateModifier] = useState(null); + const [selectedDateModifierState, setSelectedDateModifierState] = useState(null); + + const isDateModifierControlled = selectedDateModifierProp !== undefined; + const selectedDateModifier = isDateModifierControlled ? selectedDateModifierProp : selectedDateModifierState; + + const setSelectedDateModifier = (dateModifier: SearchDateModifier | null) => { + if (isDateModifierControlled) { + onSelectDateModifier?.(dateModifier); + return; + } + + setSelectedDateModifierState(dateModifier); + }; const handleSelectDateModifier = (dateModifier: SearchDateModifier | null) => { setSelectedDateModifier(dateModifier); diff --git a/src/components/Search/SearchDatePresetFilterBasePage.tsx b/src/components/Search/SearchDatePresetFilterBasePage.tsx index cd6fe83002e3c..0fae8d0c58570 100644 --- a/src/components/Search/SearchDatePresetFilterBasePage.tsx +++ b/src/components/Search/SearchDatePresetFilterBasePage.tsx @@ -1,4 +1,5 @@ -import React from 'react'; +import {useRoute} from '@react-navigation/native'; +import React, {useCallback} from 'react'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; @@ -6,17 +7,18 @@ import useThemeStyles from '@hooks/useThemeStyles'; import {updateAdvancedFilters} from '@libs/actions/Search'; import Navigation from '@libs/Navigation/Navigation'; import {getDatePresets} from '@libs/SearchUIUtils'; +import type {SearchDateModifier} from '@libs/SearchUIUtils'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue'; import DateFilterBase from './FilterComponents/DateFilterBase'; -import type {ReportFieldDateKey, SearchDateFilterKeys} from './types'; +import type {ReportFieldDateKey, SearchDateFilterKeys, SearchFilterKey} from './types'; type SearchDatePresetFilterBasePageProps = { /** Key used for the date filter */ - dateKey: SearchDateFilterKeys; + dateKey: Extract; /** The translation key for the page title */ titleKey: TranslationPaths; @@ -25,6 +27,8 @@ type SearchDatePresetFilterBasePageProps = { function SearchDatePresetFilterBasePage({dateKey, titleKey}: SearchDatePresetFilterBasePageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); + const route = useRoute(); + const params = route.params as {subPage?: string} | undefined; const [searchAdvancedFiltersForm, searchAdvancedFiltersFormMetadata] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); const isSearchAdvancedFiltersFormLoading = isLoadingOnyxValue(searchAdvancedFiltersFormMetadata); @@ -58,9 +62,42 @@ function SearchDatePresetFilterBasePage({dateKey, titleKey}: SearchDatePresetFil return getDatePresets(dateKey, hasFeed); } - const goBack = () => { + const goBack = useCallback(() => { Navigation.goBack(ROUTES.SEARCH_ADVANCED_FILTERS.getRoute()); - }; + }, []); + + const buildSubPageRoute = useCallback((subPage?: string) => ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(dateKey, subPage), [dateKey]); + + let selectedDateModifier: SearchDateModifier | null = null; + if (params?.subPage === CONST.SEARCH.DATE_FILTER_SUB_PAGE.ON) { + selectedDateModifier = CONST.SEARCH.DATE_MODIFIERS.ON; + } else if (params?.subPage === CONST.SEARCH.DATE_FILTER_SUB_PAGE.AFTER) { + selectedDateModifier = CONST.SEARCH.DATE_MODIFIERS.AFTER; + } else if (params?.subPage === CONST.SEARCH.DATE_FILTER_SUB_PAGE.BEFORE) { + selectedDateModifier = CONST.SEARCH.DATE_MODIFIERS.BEFORE; + } + + const selectDateModifier = useCallback( + (dateModifier: SearchDateModifier | null) => { + if (!dateModifier) { + Navigation.goBack(buildSubPageRoute()); + return; + } + + if (dateModifier === CONST.SEARCH.DATE_MODIFIERS.ON) { + Navigation.navigate(buildSubPageRoute(CONST.SEARCH.DATE_FILTER_SUB_PAGE.ON)); + return; + } + + if (dateModifier === CONST.SEARCH.DATE_MODIFIERS.AFTER) { + Navigation.navigate(buildSubPageRoute(CONST.SEARCH.DATE_FILTER_SUB_PAGE.AFTER)); + return; + } + + Navigation.navigate(buildSubPageRoute(CONST.SEARCH.DATE_FILTER_SUB_PAGE.BEFORE)); + }, + [buildSubPageRoute], + ); const defaultDateValues = getDefaultDateValues(); const presets = getPresets(); @@ -79,6 +116,8 @@ function SearchDatePresetFilterBasePage({dateKey, titleKey}: SearchDatePresetFil presets={presets} isSearchAdvancedFiltersFormLoading={isSearchAdvancedFiltersFormLoading} onBackButtonPress={goBack} + selectedDateModifier={selectedDateModifier} + onSelectDateModifier={selectDateModifier} onSubmit={(values) => { updateAdvancedFilters({ [dateOnKey]: values[CONST.SEARCH.DATE_MODIFIERS.ON] ?? null, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 8efb471ea5298..9f5a9eb013cdd 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1904,14 +1904,14 @@ const config: LinkingOptions['config'] = { [SCREENS.SEARCH.ADVANCED_FILTERS_GROUP_BY_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.GROUP_BY), [SCREENS.SEARCH.ADVANCED_FILTERS_VIEW_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.VIEW), [SCREENS.SEARCH.ADVANCED_FILTERS_STATUS_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.STATUS), - [SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE), - [SCREENS.SEARCH.ADVANCED_FILTERS_SUBMITTED_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.SUBMITTED), - [SCREENS.SEARCH.ADVANCED_FILTERS_APPROVED_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.APPROVED), - [SCREENS.SEARCH.ADVANCED_FILTERS_PAID_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.PAID), - [SCREENS.SEARCH.ADVANCED_FILTERS_EXPORTED_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED), + [SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP]: `${ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE)}/:subPage?`, + [SCREENS.SEARCH.ADVANCED_FILTERS_SUBMITTED_RHP]: `${ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.SUBMITTED)}/:subPage?`, + [SCREENS.SEARCH.ADVANCED_FILTERS_APPROVED_RHP]: `${ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.APPROVED)}/:subPage?`, + [SCREENS.SEARCH.ADVANCED_FILTERS_PAID_RHP]: `${ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.PAID)}/:subPage?`, + [SCREENS.SEARCH.ADVANCED_FILTERS_EXPORTED_RHP]: `${ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED)}/:subPage?`, + [SCREENS.SEARCH.ADVANCED_FILTERS_POSTED_RHP]: `${ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED)}/:subPage?`, + [SCREENS.SEARCH.ADVANCED_FILTERS_WITHDRAWN_RHP]: `${ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWN)}/:subPage?`, [SCREENS.SEARCH.ADVANCED_FILTERS_EXPORTED_TO_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.EXPORTED_TO), - [SCREENS.SEARCH.ADVANCED_FILTERS_POSTED_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED), - [SCREENS.SEARCH.ADVANCED_FILTERS_WITHDRAWN_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.WITHDRAWN), [SCREENS.SEARCH.ADVANCED_FILTERS_CURRENCY_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY), [SCREENS.SEARCH.ADVANCED_FILTERS_GROUP_CURRENCY_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.GROUP_CURRENCY), [SCREENS.SEARCH.ADVANCED_FILTERS_MERCHANT_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS.getRoute(CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT),