diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 4d977ea8e219d..ccc7217ad29b0 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -49,13 +49,19 @@ const ROUTES = { }, }, + SEARCH_ADVANCED_FILTERS: 'search/filters', + + SEARCH_ADVANCED_FILTERS_DATE: 'search/filters/date', + + SEARCH_ADVANCED_FILTERS_TYPE: 'search/filters/type', + SEARCH_REPORT: { - route: '/search/:query/view/:reportID', + route: 'search/:query/view/:reportID', getRoute: (query: string, reportID: string) => `search/${query}/view/${reportID}` as const, }, TRANSACTION_HOLD_REASON_RHP: { - route: '/search/:query/hold/:transactionID', + route: 'search/:query/hold/:transactionID', getRoute: (query: string, transactionID: string) => `search/${query}/hold/${transactionID}` as const, }, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index e5710380102d8..6e58142091711 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -30,6 +30,9 @@ const SCREENS = { SEARCH: { CENTRAL_PANE: 'Search_Central_Pane', REPORT_RHP: 'Search_Report_RHP', + ADVANCED_FILTERS_RHP: 'Search_Advanced_Filters_RHP', + ADVANCED_FILTERS_DATE_RHP: 'Search_Advanced_Filters_Date_RHP', + ADVANCED_FILTERS_TYPE_RHP: 'Search_Advanced_Filters_Type_RHP', TRANSACTION_HOLD_REASON_RHP: 'Search_Transaction_Hold_Reason_RHP', BOTTOM_TAB: 'Search_Bottom_Tab', }, @@ -145,6 +148,7 @@ const SCREENS = { TRANSACTION_DUPLICATE: 'TransactionDuplicate', TRAVEL: 'Travel', SEARCH_REPORT: 'SearchReport', + SEARCH_ADVANCED_FILTERS: 'SearchAdvancedFilters', SETTINGS_CATEGORIES: 'SettingsCategories', RESTRICTED_ACTION: 'RestrictedAction', REPORT_EXPORT: 'Report_Export', diff --git a/src/languages/en.ts b/src/languages/en.ts index b9328d8d59acd..b5b898fc6a14d 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3530,6 +3530,13 @@ export default { noOptionsAvailable: 'No options available for the selected group of expenses.', }, offlinePrompt: "You can't take this action right now.", + filtersHeader: 'Filters', + filters: { + date: { + before: 'Before', + after: 'After', + }, + }, }, genericErrorPage: { title: 'Uh-oh, something went wrong!', diff --git a/src/languages/es.ts b/src/languages/es.ts index bade8f6b5b51e..d3197afa68d41 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3585,6 +3585,13 @@ export default { noOptionsAvailable: 'No hay opciones disponibles para el grupo de gastos seleccionado.', }, offlinePrompt: 'No puedes realizar esta acción ahora mismo.', + filtersHeader: 'Filtros', + filters: { + date: { + before: 'Antes de', + after: 'Después de', + }, + }, }, genericErrorPage: { title: '¡Oh-oh, algo salió mal!', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 33d496c9d914e..6a89d4bb08511 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -20,6 +20,7 @@ import type { ReportSettingsNavigatorParamList, RoomInviteNavigatorParamList, RoomMembersNavigatorParamList, + SearchAdvancedFiltersParamList, SearchReportParamList, SettingsNavigatorParamList, SignInNavigatorParamList, @@ -496,6 +497,12 @@ const SearchReportModalStackNavigator = createModalStackNavigator require('../../../../pages/Search/SearchHoldReasonPage').default, }); +const SearchAdvancedFiltersModalStackNavigator = createModalStackNavigator({ + [SCREENS.SEARCH.ADVANCED_FILTERS_RHP]: () => require('../../../../pages/Search/SearchAdvancedFiltersPage').default, + [SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP]: () => require('../../../../pages/Search/SearchFiltersDatePage').default, + [SCREENS.SEARCH.ADVANCED_FILTERS_TYPE_RHP]: () => require('../../../../pages/Search/SearchFiltersTypePage').default, +}); + const RestrictedActionModalStackNavigator = createModalStackNavigator({ [SCREENS.RESTRICTED_ACTION_ROOT]: () => require('../../../../pages/RestrictedAction/Workspace/WorkspaceRestrictedActionPage').default, }); @@ -530,4 +537,5 @@ export { TransactionDuplicateStackNavigator, SearchReportModalStackNavigator, RestrictedActionModalStackNavigator, + SearchAdvancedFiltersModalStackNavigator, }; diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx index 6b83c19976932..c32e94d659627 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx +++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx @@ -165,6 +165,10 @@ function RightModalNavigator({navigation}: RightModalNavigatorProps) { name={SCREENS.RIGHT_MODAL.RESTRICTED_ACTION} component={ModalStackNavigators.RestrictedActionModalStackNavigator} /> + diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts index 83929b7e7d02c..c6f3aa2f17b53 100755 --- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -38,7 +38,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = [SCREENS.SETTINGS.ABOUT]: [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS], [SCREENS.SETTINGS.SAVE_THE_WORLD]: [SCREENS.I_KNOW_A_TEACHER, SCREENS.INTRO_SCHOOL_PRINCIPAL, SCREENS.I_AM_A_TEACHER], [SCREENS.SETTINGS.TROUBLESHOOT]: [SCREENS.SETTINGS.CONSOLE], - [SCREENS.SEARCH.CENTRAL_PANE]: [SCREENS.SEARCH.REPORT_RHP, SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP], + [SCREENS.SEARCH.CENTRAL_PANE]: [SCREENS.SEARCH.REPORT_RHP, SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP, SCREENS.SEARCH.ADVANCED_FILTERS_RHP], [SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: [ SCREENS.SETTINGS.SUBSCRIPTION.ADD_PAYMENT_CARD, SCREENS.SETTINGS.SUBSCRIPTION.SIZE, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 386bbe51d2d96..c37536dc5419d 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -968,6 +968,13 @@ const config: LinkingOptions['config'] = { [SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP]: ROUTES.TRANSACTION_HOLD_REASON_RHP.route, }, }, + [SCREENS.RIGHT_MODAL.SEARCH_ADVANCED_FILTERS]: { + screens: { + [SCREENS.SEARCH.ADVANCED_FILTERS_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS, + [SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_DATE, + [SCREENS.SEARCH.ADVANCED_FILTERS_TYPE_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_TYPE, + }, + }, [SCREENS.RIGHT_MODAL.RESTRICTED_ACTION]: { screens: { [SCREENS.RESTRICTED_ACTION_ROOT]: ROUTES.RESTRICTED_ACTION.route, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index c31bf6dcddc9e..6666275fbd8b3 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1063,6 +1063,7 @@ type RightModalNavigatorParamList = { [SCREENS.RIGHT_MODAL.TRAVEL]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.SEARCH_REPORT]: NavigatorScreenParams; [SCREENS.RIGHT_MODAL.RESTRICTED_ACTION]: NavigatorScreenParams; + [SCREENS.RIGHT_MODAL.SEARCH_ADVANCED_FILTERS]: NavigatorScreenParams; }; type TravelNavigatorParamList = { @@ -1254,6 +1255,10 @@ type SearchReportParamList = { }; }; +type SearchAdvancedFiltersParamList = { + [SCREENS.SEARCH.ADVANCED_FILTERS_RHP]: Record; +}; + type RestrictedActionParamList = { [SCREENS.RESTRICTED_ACTION_ROOT]: { policyID: string; @@ -1332,5 +1337,6 @@ export type { WelcomeVideoModalNavigatorParamList, TransactionDuplicateNavigatorParamList, SearchReportParamList, + SearchAdvancedFiltersParamList, RestrictedActionParamList, }; diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx new file mode 100644 index 0000000000000..171e2c45dbd76 --- /dev/null +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -0,0 +1,58 @@ +import React, {useMemo} from 'react'; +import {View} from 'react-native'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import useLocalize from '@hooks/useLocalize'; +import useSingleExecution from '@hooks/useSingleExecution'; +import useWaitForNavigation from '@hooks/useWaitForNavigation'; +import Navigation from '@libs/Navigation/Navigation'; +import ROUTES from '@src/ROUTES'; + +function getFilterDisplayTitle(filters: Record, fieldName: string) { + // This is temporary because the full parsing of search query is not yet done + // TODO once we have values from query, this value should be `filters[fieldName].value` + return fieldName; +} + +function AdvancedSearchFilters() { + const {translate} = useLocalize(); + const {singleExecution} = useSingleExecution(); + const waitForNavigate = useWaitForNavigation(); + + const advancedFilters = useMemo( + () => [ + { + title: getFilterDisplayTitle({}, 'title'), + description: 'common.type' as const, + route: ROUTES.SEARCH_ADVANCED_FILTERS_TYPE, + }, + { + title: getFilterDisplayTitle({}, 'date'), + description: 'common.date' as const, + route: ROUTES.SEARCH_ADVANCED_FILTERS_DATE, + }, + ], + [], + ); + + return ( + + {advancedFilters.map((item) => { + const onPress = singleExecution(waitForNavigate(() => Navigation.navigate(item.route))); + + return ( + + ); + })} + + ); +} + +AdvancedSearchFilters.displayName = 'AdvancedSearchFilters'; + +export default AdvancedSearchFilters; diff --git a/src/pages/Search/SearchAdvancedFiltersPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage.tsx new file mode 100644 index 0000000000000..9d4864bce8eba --- /dev/null +++ b/src/pages/Search/SearchAdvancedFiltersPage.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import AdvancedSearchFilters from './AdvancedSearchFilters'; + +function SearchAdvancedFiltersPage() { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + return ( + + + + + + + ); +} + +SearchAdvancedFiltersPage.displayName = 'SearchAdvancedFiltersPage'; + +export default SearchAdvancedFiltersPage; diff --git a/src/pages/Search/SearchFilters.tsx b/src/pages/Search/SearchFilters.tsx index bbb861364f00b..0728743c1875b 100644 --- a/src/pages/Search/SearchFilters.tsx +++ b/src/pages/Search/SearchFilters.tsx @@ -25,6 +25,7 @@ type SearchMenuFilterItem = { route: Route; }; +// Because we will add have AdvancedFilters, in future rename this component to `SearchTypeMenu|Tabs|Filters` to avoid confusion function SearchFilters({query}: SearchFiltersProps) { const styles = useThemeStyles(); const {isSmallScreenWidth} = useWindowDimensions(); diff --git a/src/pages/Search/SearchFiltersDatePage.tsx b/src/pages/Search/SearchFiltersDatePage.tsx new file mode 100644 index 0000000000000..6565da0783675 --- /dev/null +++ b/src/pages/Search/SearchFiltersDatePage.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import {View} from 'react-native'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Text from '@src/components/Text'; + +function SearchFiltersDatePage() { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + return ( + + + + + {/* temporary placeholder, will be implemented in https://github.com/Expensify/App/issues/45026 */} + Advanced filters Date form + + + + ); +} + +SearchFiltersDatePage.displayName = 'SearchFiltersDatePage'; + +export default SearchFiltersDatePage; diff --git a/src/pages/Search/SearchFiltersTypePage.tsx b/src/pages/Search/SearchFiltersTypePage.tsx new file mode 100644 index 0000000000000..e18b865f20ef6 --- /dev/null +++ b/src/pages/Search/SearchFiltersTypePage.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import {View} from 'react-native'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Text from '@src/components/Text'; + +function SearchFiltersTypePage() { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + return ( + + + + + {/* temporary placeholder, will be implemented in https://github.com/Expensify/App/issues/45026 */} + Advanced filters Type form + + + + ); +} + +SearchFiltersTypePage.displayName = 'SearchFiltersTypePage'; + +export default SearchFiltersTypePage;