From 346a55cce902965a66a57f080e093a3f4b8bdd92 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Mon, 22 Jul 2024 12:48:55 +0200 Subject: [PATCH 1/9] Add displaying chosen date advanced filters value --- src/languages/en.ts | 5 ++- src/languages/es.ts | 5 ++- src/pages/Search/AdvancedSearchFilters.tsx | 46 +++++++++++++++++++--- 3 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index ca181b3f8573..45d0e5668c53 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3559,6 +3559,7 @@ export default { search: { selectMultiple: 'Select multiple', resultsAreLimited: 'Search results are limited.', + viewResults: 'View results', searchResults: { emptyResults: { title: 'Nothing to show', @@ -3576,8 +3577,8 @@ export default { filtersHeader: 'Filters', filters: { date: { - before: 'Before', - after: 'After', + before: (date: string) => `Before ${date || ''}`, + after: (date: string) => `After ${date || ''}`, }, }, }, diff --git a/src/languages/es.ts b/src/languages/es.ts index 70d417423998..94ab71a5544f 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3616,6 +3616,7 @@ export default { search: { selectMultiple: 'Seleccionar varios', resultsAreLimited: 'Los resultados de búsqueda están limitados.', + viewResults: 'Ver resultados', searchResults: { emptyResults: { title: 'No hay nada que ver aquí', @@ -3633,8 +3634,8 @@ export default { filtersHeader: 'Filtros', filters: { date: { - before: 'Antes de', - after: 'Después de', + before: (date: string) => `Antes de ${date || ''}`, + after: (date: string) => `Después de ${date || ''}`, }, }, }, diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 171e2c45dbd7..2f6faffeed2c 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -1,37 +1,62 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; +import type {LocaleContextProps} from '@components/LocaleContextProvider'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import useLocalize from '@hooks/useLocalize'; import useSingleExecution from '@hooks/useSingleExecution'; +import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import Navigation from '@libs/Navigation/Navigation'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type {SearchAdvancedFiltersForm} from '@src/types/form'; + +type AvailableFilters = 'type' | 'date'; + +function getFilterDisplayTitle(filters: Partial, fieldName: AvailableFilters, translate: LocaleContextProps['translate']) { + if (fieldName === 'date') { + const {dateAfter, dateBefore} = filters; + let dateValue = ''; + if (dateBefore) { + dateValue = translate('search.filters.date.before', dateBefore); + } + if (dateBefore && dateAfter) { + dateValue += ', '; + } + if (dateAfter) { + dateValue += translate('search.filters.date.after', dateAfter); + } + + return dateValue; + } -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 styles = useThemeStyles(); const {singleExecution} = useSingleExecution(); const waitForNavigate = useWaitForNavigation(); + const [searchAdvancedFilters = {}] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); + const advancedFilters = useMemo( () => [ { - title: getFilterDisplayTitle({}, 'title'), + title: getFilterDisplayTitle(searchAdvancedFilters, 'type', translate), description: 'common.type' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_TYPE, }, { - title: getFilterDisplayTitle({}, 'date'), + title: getFilterDisplayTitle(searchAdvancedFilters, 'date', translate), description: 'common.date' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_DATE, }, ], - [], + [searchAdvancedFilters], ); return ( @@ -49,6 +74,15 @@ function AdvancedSearchFilters() { /> ); })} + { + // here set the selected filters as new query and redirecting to SearchResults page + // once these are ready: https://github.com/Expensify/App/issues/45028 and https://github.com/Expensify/App/issues/45027 + Navigation.goBack(); + }} + /> ); } From 22693d45a53f422f92c4963ce4e6f95324be61a2 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Mon, 22 Jul 2024 16:51:03 +0200 Subject: [PATCH 2/9] Update search filters type page --- src/CONST.ts | 3 ++ src/pages/Search/AdvancedSearchFilters.tsx | 18 +++++++--- src/pages/Search/SearchFiltersTypePage.tsx | 42 ++++++++++++++++++++-- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index c7a6741da314..42d172d4fead 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -5239,6 +5239,9 @@ const CONST = { DRAFTS: 'drafts', FINISHED: 'finished', }, + TYPE: { + EXPENSES: 'expenses', + }, TABLE_COLUMNS: { RECEIPT: 'receipt', DATE: 'date', diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 2f6faffeed2c..67731ff2a16c 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -1,6 +1,7 @@ import React, {useMemo} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; +import type {ValueOf} from 'type-fest'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import type {LocaleContextProps} from '@components/LocaleContextProvider'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; @@ -12,8 +13,10 @@ import Navigation from '@libs/Navigation/Navigation'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {SearchAdvancedFiltersForm} from '@src/types/form'; +import INPUT_IDS from '@src/types/form/SearchAdvancedFiltersForm'; -type AvailableFilters = 'type' | 'date'; +// the values of dateBefore+dateAfter map to just a single 'date' field on advanced filters +type AvailableFilters = ValueOf | 'date'; function getFilterDisplayTitle(filters: Partial, fieldName: AvailableFilters, translate: LocaleContextProps['translate']) { if (fieldName === 'date') { @@ -32,7 +35,12 @@ function getFilterDisplayTitle(filters: Partial, fiel return dateValue; } - return fieldName; + if (fieldName === INPUT_IDS.TYPE) { + // return filters[fieldName] ? filters[fieldName].toUpperCase() : ''; + return filters[fieldName]; + } + + return filters[fieldName]; } function AdvancedSearchFilters() { @@ -56,7 +64,7 @@ function AdvancedSearchFilters() { route: ROUTES.SEARCH_ADVANCED_FILTERS_DATE, }, ], - [searchAdvancedFilters], + [searchAdvancedFilters, translate], ); return ( @@ -78,8 +86,8 @@ function AdvancedSearchFilters() { buttonText={translate('search.viewResults')} containerStyles={[styles.mh4, styles.mt4]} onSubmit={() => { - // here set the selected filters as new query and redirecting to SearchResults page - // once these are ready: https://github.com/Expensify/App/issues/45028 and https://github.com/Expensify/App/issues/45027 + // here set the selected filters as new query and redirect to SearchResults page + // waiting for: https://github.com/Expensify/App/issues/45028 and https://github.com/Expensify/App/issues/45027 Navigation.goBack(); }} /> diff --git a/src/pages/Search/SearchFiltersTypePage.tsx b/src/pages/Search/SearchFiltersTypePage.tsx index e18b865f20ef..72317a03c07f 100644 --- a/src/pages/Search/SearchFiltersTypePage.tsx +++ b/src/pages/Search/SearchFiltersTypePage.tsx @@ -1,16 +1,39 @@ import React from 'react'; import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; +import type {FormOnyxValues} from '@components/Form/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import Picker from '@components/Picker'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import Text from '@src/components/Text'; +import Navigation from '@navigation/Navigation'; +import * as SearchActions from '@userActions/Search'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import INPUT_IDS from '@src/types/form/SearchAdvancedFiltersForm'; function SearchFiltersTypePage() { const styles = useThemeStyles(); const {translate} = useLocalize(); + const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); + + const filterTypeItems = [ + { + label: translate('common.expenses'), + value: CONST.SEARCH.TYPE.EXPENSES, + }, + ]; + + const updateType = (value: FormOnyxValues) => { + SearchActions.mergeFilters(value); + Navigation.goBack(); + }; + return ( - {/* temporary placeholder, will be implemented in https://github.com/Expensify/App/issues/45026 */} - Advanced filters Type form + + + From 9927d4adf9127a2ed79509882af0455ac39565ef Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Tue, 23 Jul 2024 14:41:11 +0200 Subject: [PATCH 3/9] Finalize SearchFiltersTypePage with correct input UI --- src/libs/actions/Search.ts | 2 +- src/pages/Search/AdvancedSearchFilters.tsx | 1 - src/pages/Search/SearchFiltersTypePage.tsx | 59 +++++++++++----------- 3 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index 245192ff6e0a..7cf0a739fcd2 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -113,7 +113,7 @@ function exportSearchItemsToCSV(query: string, reportIDList: Array) { +function updateAdvancedFilters(values: Partial>) { Onyx.merge(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, values); } diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 67731ff2a16c..79cb4383fc63 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -36,7 +36,6 @@ function getFilterDisplayTitle(filters: Partial, fiel } if (fieldName === INPUT_IDS.TYPE) { - // return filters[fieldName] ? filters[fieldName].toUpperCase() : ''; return filters[fieldName]; } diff --git a/src/pages/Search/SearchFiltersTypePage.tsx b/src/pages/Search/SearchFiltersTypePage.tsx index 72317a03c07f..5b16de7457cf 100644 --- a/src/pages/Search/SearchFiltersTypePage.tsx +++ b/src/pages/Search/SearchFiltersTypePage.tsx @@ -1,20 +1,18 @@ -import React from 'react'; +import React, {useMemo} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; import type {FormOnyxValues} from '@components/Form/types'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; -import Picker from '@components/Picker'; import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@navigation/Navigation'; import * as SearchActions from '@userActions/Search'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import INPUT_IDS from '@src/types/form/SearchAdvancedFiltersForm'; function SearchFiltersTypePage() { const styles = useThemeStyles(); @@ -22,15 +20,22 @@ function SearchFiltersTypePage() { const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); - const filterTypeItems = [ - { - label: translate('common.expenses'), - value: CONST.SEARCH.TYPE.EXPENSES, - }, - ]; + const activeItem = searchAdvancedFiltersForm?.type ?? CONST.SEARCH.TYPE.EXPENSES; - const updateType = (value: FormOnyxValues) => { - SearchActions.mergeFilters(value); + const filterTypeItems = useMemo( + () => [ + { + text: translate('common.expenses'), + value: CONST.SEARCH.TYPE.EXPENSES, + keyForList: CONST.SEARCH.TYPE.EXPENSES, + isSelected: activeItem === CONST.SEARCH.TYPE.EXPENSES, + }, + ], + [translate, activeItem], + ); + + const updateType = (values: Partial>) => { + SearchActions.mergeFilters(values); Navigation.goBack(); }; @@ -42,22 +47,18 @@ function SearchFiltersTypePage() { > - - - - + + { + updateType({ + type: item.value, + }); + }} + initiallyFocusedOptionKey={activeItem} + shouldStopPropagation + ListItem={RadioListItem} + /> From 422d75cab8ee0259d93285e38039d0fda577622a Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Tue, 23 Jul 2024 15:23:27 +0200 Subject: [PATCH 4/9] Add status advanced filter for Search --- src/ROUTES.ts | 2 + src/SCREENS.ts | 1 + src/languages/en.ts | 1 + src/languages/es.ts | 1 + .../ModalStackNavigators/index.tsx | 1 + src/libs/Navigation/linkingConfig/config.ts | 1 + src/pages/Search/AdvancedSearchFilters.tsx | 5 ++ src/pages/Search/SearchFiltersStatusPage.tsx | 88 +++++++++++++++++++ src/pages/Search/SearchFiltersTypePage.tsx | 2 +- src/types/form/SearchAdvancedFiltersForm.ts | 2 + 10 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/pages/Search/SearchFiltersStatusPage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 3bda25d4699b..ddfe42354fef 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -55,6 +55,8 @@ const ROUTES = { SEARCH_ADVANCED_FILTERS_TYPE: 'search/filters/type', + SEARCH_ADVANCED_FILTERS_STATUS: 'search/filters/status', + SEARCH_REPORT: { route: 'search/:query/view/:reportID', getRoute: (query: string, reportID: string) => `search/${query}/view/${reportID}` as const, diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 44ac2677db68..6221fcd1dee7 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -33,6 +33,7 @@ const SCREENS = { 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', + ADVANCED_FILTERS_STATUS_RHP: 'Search_Advanced_Filters_Status_RHP', TRANSACTION_HOLD_REASON_RHP: 'Search_Transaction_Hold_Reason_RHP', BOTTOM_TAB: 'Search_Bottom_Tab', }, diff --git a/src/languages/en.ts b/src/languages/en.ts index 45d0e5668c53..c0a11dd21299 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3580,6 +3580,7 @@ export default { before: (date: string) => `Before ${date || ''}`, after: (date: string) => `After ${date || ''}`, }, + status: 'Status', }, }, genericErrorPage: { diff --git a/src/languages/es.ts b/src/languages/es.ts index 94ab71a5544f..65719a500428 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3637,6 +3637,7 @@ export default { before: (date: string) => `Antes de ${date || ''}`, after: (date: string) => `Después de ${date || ''}`, }, + status: 'Estado', }, }, genericErrorPage: { diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index b612d4a3f0cd..91b13e1def41 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -509,6 +509,7 @@ const SearchAdvancedFiltersModalStackNavigator = createModalStackNavigator 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, + [SCREENS.SEARCH.ADVANCED_FILTERS_STATUS_RHP]: () => require('../../../../pages/Search/SearchFiltersStatusPage').default, }); const RestrictedActionModalStackNavigator = createModalStackNavigator({ diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 47a9d3f70d6a..97abed1fe00b 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -1000,6 +1000,7 @@ const config: LinkingOptions['config'] = { [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.SEARCH.ADVANCED_FILTERS_STATUS_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_STATUS, }, }, [SCREENS.RIGHT_MODAL.RESTRICTED_ACTION]: { diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 79cb4383fc63..e7323401dc46 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -62,6 +62,11 @@ function AdvancedSearchFilters() { description: 'common.date' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_DATE, }, + { + title: getFilterDisplayTitle(searchAdvancedFilters, 'status', translate), + description: 'search.filters.status' as const, + route: ROUTES.SEARCH_ADVANCED_FILTERS_STATUS, + }, ], [searchAdvancedFilters, translate], ); diff --git a/src/pages/Search/SearchFiltersStatusPage.tsx b/src/pages/Search/SearchFiltersStatusPage.tsx new file mode 100644 index 000000000000..319703af7151 --- /dev/null +++ b/src/pages/Search/SearchFiltersStatusPage.tsx @@ -0,0 +1,88 @@ +import React, {useMemo} from 'react'; +import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import type {FormOnyxValues} from '@components/Form/types'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import SelectionList from '@components/SelectionList'; +import RadioListItem from '@components/SelectionList/RadioListItem'; +import useLocalize from '@hooks/useLocalize'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@navigation/Navigation'; +import * as SearchActions from '@userActions/Search'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; + +function SearchFiltersStatusPage() { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + + const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); + + const activeItem = searchAdvancedFiltersForm?.status; + + const filterStatusItems = useMemo( + () => [ + { + text: translate('common.all'), + value: CONST.SEARCH.TAB.ALL, + keyForList: CONST.SEARCH.TAB.ALL, + isSelected: activeItem === CONST.SEARCH.TAB.ALL, + }, + { + text: translate('common.shared'), + value: CONST.SEARCH.TAB.SHARED, + keyForList: CONST.SEARCH.TAB.SHARED, + isSelected: activeItem === CONST.SEARCH.TAB.SHARED, + }, + { + text: translate('common.drafts'), + value: CONST.SEARCH.TAB.DRAFTS, + keyForList: CONST.SEARCH.TAB.DRAFTS, + isSelected: activeItem === CONST.SEARCH.TAB.DRAFTS, + }, + { + text: translate('common.finished'), + value: CONST.SEARCH.TAB.FINISHED, + keyForList: CONST.SEARCH.TAB.FINISHED, + isSelected: activeItem === CONST.SEARCH.TAB.FINISHED, + }, + ], + [translate, activeItem], + ); + + const updateType = (values: Partial>) => { + SearchActions.updateAdvancedFilters(values); + Navigation.goBack(); + }; + + return ( + + + + + { + updateType({ + status: item.value, + }); + }} + initiallyFocusedOptionKey={activeItem} + shouldStopPropagation + ListItem={RadioListItem} + /> + + + + ); +} + +SearchFiltersStatusPage.displayName = 'SearchFiltersStatusPage'; + +export default SearchFiltersStatusPage; diff --git a/src/pages/Search/SearchFiltersTypePage.tsx b/src/pages/Search/SearchFiltersTypePage.tsx index 5b16de7457cf..c9f4774eb9ba 100644 --- a/src/pages/Search/SearchFiltersTypePage.tsx +++ b/src/pages/Search/SearchFiltersTypePage.tsx @@ -35,7 +35,7 @@ function SearchFiltersTypePage() { ); const updateType = (values: Partial>) => { - SearchActions.mergeFilters(values); + SearchActions.updateAdvancedFilters(values); Navigation.goBack(); }; diff --git a/src/types/form/SearchAdvancedFiltersForm.ts b/src/types/form/SearchAdvancedFiltersForm.ts index 46808954f661..3c9a64a06976 100644 --- a/src/types/form/SearchAdvancedFiltersForm.ts +++ b/src/types/form/SearchAdvancedFiltersForm.ts @@ -3,6 +3,7 @@ import type Form from './Form'; const INPUT_IDS = { TYPE: 'type', + STATUS: 'status', DATE_AFTER: 'dateAfter', DATE_BEFORE: 'dateBefore', } as const; @@ -15,6 +16,7 @@ type SearchAdvancedFiltersForm = Form< [INPUT_IDS.TYPE]: string; [INPUT_IDS.DATE_AFTER]: string; [INPUT_IDS.DATE_BEFORE]: string; + [INPUT_IDS.STATUS]: string; } >; From 9aa2ffbeac482a85cd676873c6d8a92870ce8ac2 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Wed, 24 Jul 2024 12:04:49 +0200 Subject: [PATCH 5/9] Improve styling of advanced search filters --- src/languages/en.ts | 4 +- src/languages/es.ts | 4 +- src/pages/Search/AdvancedSearchFilters.tsx | 40 ++++++++++---------- src/pages/Search/SearchFiltersStatusPage.tsx | 2 +- src/pages/Search/SearchFiltersTypePage.tsx | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index c0a11dd21299..c0973eb1193f 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3577,8 +3577,8 @@ export default { filtersHeader: 'Filters', filters: { date: { - before: (date: string) => `Before ${date || ''}`, - after: (date: string) => `After ${date || ''}`, + before: (date?: string) => `Before ${date ?? ''}`, + after: (date?: string) => `After ${date ?? ''}`, }, status: 'Status', }, diff --git a/src/languages/es.ts b/src/languages/es.ts index 65719a500428..c99af47d34f9 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -3634,8 +3634,8 @@ export default { filtersHeader: 'Filtros', filters: { date: { - before: (date: string) => `Antes de ${date || ''}`, - after: (date: string) => `Después de ${date || ''}`, + before: (date?: string) => `Antes de ${date ?? ''}`, + after: (date?: string) => `Después de ${date ?? ''}`, }, status: 'Estado', }, diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index e7323401dc46..139190603a00 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -1,3 +1,4 @@ +import {Str} from 'expensify-common'; import React, {useMemo} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; @@ -13,7 +14,7 @@ import Navigation from '@libs/Navigation/Navigation'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {SearchAdvancedFiltersForm} from '@src/types/form'; -import INPUT_IDS from '@src/types/form/SearchAdvancedFiltersForm'; +import type INPUT_IDS from '@src/types/form/SearchAdvancedFiltersForm'; // the values of dateBefore+dateAfter map to just a single 'date' field on advanced filters type AvailableFilters = ValueOf | 'date'; @@ -35,11 +36,8 @@ function getFilterDisplayTitle(filters: Partial, fiel return dateValue; } - if (fieldName === INPUT_IDS.TYPE) { - return filters[fieldName]; - } - - return filters[fieldName]; + const filterValue = filters[fieldName]; + return filterValue ? Str.recapitalize(filterValue) : undefined; } function AdvancedSearchFilters() { @@ -72,23 +70,25 @@ function AdvancedSearchFilters() { ); return ( - - {advancedFilters.map((item) => { - const onPress = singleExecution(waitForNavigate(() => Navigation.navigate(item.route))); + + + {advancedFilters.map((item) => { + const onPress = singleExecution(waitForNavigate(() => Navigation.navigate(item.route))); - return ( - - ); - })} + return ( + + ); + })} + { // here set the selected filters as new query and redirect to SearchResults page // waiting for: https://github.com/Expensify/App/issues/45028 and https://github.com/Expensify/App/issues/45027 diff --git a/src/pages/Search/SearchFiltersStatusPage.tsx b/src/pages/Search/SearchFiltersStatusPage.tsx index 319703af7151..8a981f3a4b28 100644 --- a/src/pages/Search/SearchFiltersStatusPage.tsx +++ b/src/pages/Search/SearchFiltersStatusPage.tsx @@ -65,7 +65,7 @@ function SearchFiltersStatusPage() { > - + { diff --git a/src/pages/Search/SearchFiltersTypePage.tsx b/src/pages/Search/SearchFiltersTypePage.tsx index c9f4774eb9ba..f065ee827aed 100644 --- a/src/pages/Search/SearchFiltersTypePage.tsx +++ b/src/pages/Search/SearchFiltersTypePage.tsx @@ -47,7 +47,7 @@ function SearchFiltersTypePage() { > - + { From e373c47bee964e7c4fb5b1a927f09b3e5645fee7 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Thu, 25 Jul 2024 09:42:40 +0200 Subject: [PATCH 6/9] Add small fixes to Search after review --- src/CONST.ts | 2 +- src/libs/actions/Search.ts | 20 ++++++++++++++++++-- src/pages/Search/AdvancedSearchFilters.tsx | 2 ++ src/pages/Search/SearchFiltersStatusPage.tsx | 4 ++-- src/pages/Search/SearchFiltersTypePage.tsx | 8 ++++---- 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 42d172d4fead..ab6aa7e86611 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -5240,7 +5240,7 @@ const CONST = { FINISHED: 'finished', }, TYPE: { - EXPENSES: 'expenses', + EXPENSE: 'expense', }, TABLE_COLUMNS: { RECEIPT: 'receipt', diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts index 7cf0a739fcd2..f9f380c19c1f 100644 --- a/src/libs/actions/Search.ts +++ b/src/libs/actions/Search.ts @@ -111,10 +111,26 @@ function exportSearchItemsToCSV(query: string, reportIDList: Array>) { Onyx.merge(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, values); } -export {search, createTransactionThread, deleteMoneyRequestOnSearch, holdMoneyRequestOnSearch, unholdMoneyRequestOnSearch, exportSearchItemsToCSV, updateAdvancedFilters}; +/** + * Clears all values for the advanced filters search form. + */ +function clearAdvancedFilters() { + Onyx.set(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, null); +} + +export { + search, + createTransactionThread, + deleteMoneyRequestOnSearch, + holdMoneyRequestOnSearch, + unholdMoneyRequestOnSearch, + exportSearchItemsToCSV, + updateAdvancedFilters, + clearAdvancedFilters, +}; diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 139190603a00..ed06e55cc7e9 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -11,6 +11,7 @@ import useSingleExecution from '@hooks/useSingleExecution'; import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import Navigation from '@libs/Navigation/Navigation'; +import * as SearchActions from '@userActions/Search'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {SearchAdvancedFiltersForm} from '@src/types/form'; @@ -92,6 +93,7 @@ function AdvancedSearchFilters() { onSubmit={() => { // here set the selected filters as new query and redirect to SearchResults page // waiting for: https://github.com/Expensify/App/issues/45028 and https://github.com/Expensify/App/issues/45027 + SearchActions.clearAdvancedFilters(); Navigation.goBack(); }} /> diff --git a/src/pages/Search/SearchFiltersStatusPage.tsx b/src/pages/Search/SearchFiltersStatusPage.tsx index 8a981f3a4b28..444acadc3d1c 100644 --- a/src/pages/Search/SearchFiltersStatusPage.tsx +++ b/src/pages/Search/SearchFiltersStatusPage.tsx @@ -52,7 +52,7 @@ function SearchFiltersStatusPage() { [translate, activeItem], ); - const updateType = (values: Partial>) => { + const updateStatus = (values: Partial>) => { SearchActions.updateAdvancedFilters(values); Navigation.goBack(); }; @@ -69,7 +69,7 @@ function SearchFiltersStatusPage() { { - updateType({ + updateStatus({ status: item.value, }); }} diff --git a/src/pages/Search/SearchFiltersTypePage.tsx b/src/pages/Search/SearchFiltersTypePage.tsx index f065ee827aed..b9bf453e4471 100644 --- a/src/pages/Search/SearchFiltersTypePage.tsx +++ b/src/pages/Search/SearchFiltersTypePage.tsx @@ -20,15 +20,15 @@ function SearchFiltersTypePage() { const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); - const activeItem = searchAdvancedFiltersForm?.type ?? CONST.SEARCH.TYPE.EXPENSES; + const activeItem = searchAdvancedFiltersForm?.type ?? CONST.SEARCH.TYPE.EXPENSE; const filterTypeItems = useMemo( () => [ { text: translate('common.expenses'), - value: CONST.SEARCH.TYPE.EXPENSES, - keyForList: CONST.SEARCH.TYPE.EXPENSES, - isSelected: activeItem === CONST.SEARCH.TYPE.EXPENSES, + value: CONST.SEARCH.TYPE.EXPENSE, + keyForList: CONST.SEARCH.TYPE.EXPENSE, + isSelected: activeItem === CONST.SEARCH.TYPE.EXPENSE, }, ], [translate, activeItem], From b7387c018f1f02ee1b0c5b66a310692033dcf0fe Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Fri, 26 Jul 2024 15:41:49 +0200 Subject: [PATCH 7/9] Improve usage of CONSTs for Search Filters --- src/components/Search/index.tsx | 1 + src/components/Search/types.ts | 8 ++-- src/libs/SearchUtils.ts | 16 +++++-- src/pages/Search/AdvancedSearchFilters.tsx | 48 ++++++++++++-------- src/pages/Search/SearchFiltersStatusPage.tsx | 27 +++++------ src/pages/Search/SearchFiltersTypePage.tsx | 3 +- 6 files changed, 62 insertions(+), 41 deletions(-) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index b8d7c02fc7d8..3f2ed651eadd 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -41,6 +41,7 @@ const transactionItemMobileHeight = 100; const reportItemTransactionHeight = 52; const listItemPadding = 12; // this is equivalent to 'mb3' on every transaction/report list item const searchHeaderHeight = 54; + function Search({queryJSON, policyIDs, isMobileSelectionModeActive, setIsMobileSelectionModeActive}: SearchProps) { const {isOffline} = useNetwork(); const styles = useThemeStyles(); diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index cf8a2eb04e14..360a8456bda7 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -44,10 +44,10 @@ type QueryFilter = { value: string | number; }; -type AllFieldKeys = ValueOf | ValueOf; +type AdvancedFiltersKeys = ValueOf | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.TYPE | typeof CONST.SEARCH.SYNTAX_ROOT_KEYS.STATUS; type QueryFilters = { - [K in AllFieldKeys]: QueryFilter | QueryFilter[]; + [K in AdvancedFiltersKeys]?: QueryFilter | QueryFilter[]; }; type SearchQueryString = string; @@ -61,7 +61,7 @@ type SearchQueryAST = { }; type SearchQueryJSON = { - input: string; + inputQuery: SearchQueryString; hash: number; } & SearchQueryAST; @@ -78,5 +78,5 @@ export type { ASTNode, QueryFilter, QueryFilters, - AllFieldKeys, + AdvancedFiltersKeys, }; diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 18888903053e..148f2f8ea631 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -1,10 +1,11 @@ import type {ValueOf} from 'type-fest'; -import type {AllFieldKeys, ASTNode, QueryFilter, QueryFilters, SearchColumnType, SearchQueryJSON, SearchQueryString, SortOrder} from '@components/Search/types'; +import type {AdvancedFiltersKeys, ASTNode, QueryFilter, QueryFilters, SearchColumnType, SearchQueryJSON, SearchQueryString, SortOrder} from '@components/Search/types'; import ReportListItem from '@components/SelectionList/Search/ReportListItem'; import TransactionListItem from '@components/SelectionList/Search/TransactionListItem'; import type {ListItem, ReportListItemType, TransactionListItemType} from '@components/SelectionList/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type {SearchAdvancedFiltersForm} from '@src/types/form'; import type * as OnyxTypes from '@src/types/onyx'; import type {SearchAccountDetails, SearchDataTypes, SearchPersonalDetails, SearchTransaction, SearchTypeToItemMap, SectionsType} from '@src/types/onyx/SearchResults'; import type SearchResults from '@src/types/onyx/SearchResults'; @@ -316,7 +317,7 @@ function buildSearchQueryJSON(query: SearchQueryString, policyID?: string) { try { // Add the full input and hash to the results const result = searchParser.parse(query) as SearchQueryJSON; - result.input = query; + result.inputQuery = query; // Temporary solution until we move policyID filter into the AST - then remove this line and keep only query const policyIDPart = policyID ?? ''; @@ -351,7 +352,15 @@ function normalizeQuery(query: string) { return buildSearchQueryString(normalizedQueryJSON); } -function getFilters(query: SearchQueryString, fields: Array>) { +function buildQueryStringFromFilters(filterValues: Partial) { + // Object.entries(filterValues).map(([filterKey, filterValue]) => { + // if (filterKey === 'dateFrom' || filterKey === 'dateTo') { + // } + // }); + return ''; +} + +function getFilters(query: SearchQueryString, fields: Array>) { let queryAST; try { @@ -427,4 +436,5 @@ export { isSearchResultsEmpty, getFilters, normalizeQuery, + buildQueryStringFromFilters, }; diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index ed06e55cc7e9..6d7fe76232e4 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -2,26 +2,25 @@ import {Str} from 'expensify-common'; import React, {useMemo} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; -import type {ValueOf} from 'type-fest'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import type {LocaleContextProps} from '@components/LocaleContextProvider'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import type {AdvancedFiltersKeys} from '@components/Search/types'; import useLocalize from '@hooks/useLocalize'; import useSingleExecution from '@hooks/useSingleExecution'; import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import Navigation from '@libs/Navigation/Navigation'; +import * as SearchUtils from '@libs/SearchUtils'; import * as SearchActions from '@userActions/Search'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {SearchAdvancedFiltersForm} from '@src/types/form'; -import type INPUT_IDS from '@src/types/form/SearchAdvancedFiltersForm'; -// the values of dateBefore+dateAfter map to just a single 'date' field on advanced filters -type AvailableFilters = ValueOf | 'date'; - -function getFilterDisplayTitle(filters: Partial, fieldName: AvailableFilters, translate: LocaleContextProps['translate']) { +function getFilterDisplayTitle(filters: Partial, fieldName: AdvancedFiltersKeys, translate: LocaleContextProps['translate']) { if (fieldName === 'date') { + // the value of date filter is a combination of dateBefore + dateAfter values const {dateAfter, dateBefore} = filters; let dateValue = ''; if (dateBefore) { @@ -37,7 +36,10 @@ function getFilterDisplayTitle(filters: Partial, fiel return dateValue; } - const filterValue = filters[fieldName]; + // Todo Once all Advanced filters are implemented this line can be cleaned up. See: https://github.com/Expensify/App/issues/45026 + // @ts-expect-error this property access is temporarily an error, because not every SYNTAX_FILTER_KEYS is handled by form. + // When all filters are updated here: src/types/form/SearchAdvancedFiltersForm.ts this line comment + type cast can be removed. + const filterValue = filters[fieldName] as string; return filterValue ? Str.recapitalize(filterValue) : undefined; } @@ -52,24 +54,35 @@ function AdvancedSearchFilters() { const advancedFilters = useMemo( () => [ { - title: getFilterDisplayTitle(searchAdvancedFilters, 'type', translate), + title: getFilterDisplayTitle(searchAdvancedFilters, CONST.SEARCH.SYNTAX_ROOT_KEYS.TYPE, translate), description: 'common.type' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_TYPE, }, { - title: getFilterDisplayTitle(searchAdvancedFilters, 'date', translate), - description: 'common.date' as const, - route: ROUTES.SEARCH_ADVANCED_FILTERS_DATE, - }, - { - title: getFilterDisplayTitle(searchAdvancedFilters, 'status', translate), + title: getFilterDisplayTitle(searchAdvancedFilters, CONST.SEARCH.SYNTAX_ROOT_KEYS.STATUS, translate), description: 'search.filters.status' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_STATUS, }, + { + title: getFilterDisplayTitle(searchAdvancedFilters, CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE, translate), + description: 'common.date' as const, + route: ROUTES.SEARCH_ADVANCED_FILTERS_DATE, + }, ], [searchAdvancedFilters, translate], ); + const onFormSubmit = () => { + const query = SearchUtils.buildQueryStringFromFilters(searchAdvancedFilters); + SearchActions.clearAdvancedFilters(); + Navigation.navigate( + ROUTES.SEARCH_CENTRAL_PANE.getRoute({ + query, + isCustomQuery: true, + }), + ); + }; + return ( @@ -90,12 +103,7 @@ function AdvancedSearchFilters() { { - // here set the selected filters as new query and redirect to SearchResults page - // waiting for: https://github.com/Expensify/App/issues/45028 and https://github.com/Expensify/App/issues/45027 - SearchActions.clearAdvancedFilters(); - Navigation.goBack(); - }} + onSubmit={onFormSubmit} /> ); diff --git a/src/pages/Search/SearchFiltersStatusPage.tsx b/src/pages/Search/SearchFiltersStatusPage.tsx index 444acadc3d1c..55274b770adc 100644 --- a/src/pages/Search/SearchFiltersStatusPage.tsx +++ b/src/pages/Search/SearchFiltersStatusPage.tsx @@ -13,6 +13,7 @@ import Navigation from '@navigation/Navigation'; import * as SearchActions from '@userActions/Search'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; function SearchFiltersStatusPage() { const styles = useThemeStyles(); @@ -26,27 +27,27 @@ function SearchFiltersStatusPage() { () => [ { text: translate('common.all'), - value: CONST.SEARCH.TAB.ALL, - keyForList: CONST.SEARCH.TAB.ALL, - isSelected: activeItem === CONST.SEARCH.TAB.ALL, + value: CONST.SEARCH.STATUS.ALL, + keyForList: CONST.SEARCH.STATUS.ALL, + isSelected: activeItem === CONST.SEARCH.STATUS.ALL, }, { text: translate('common.shared'), - value: CONST.SEARCH.TAB.SHARED, - keyForList: CONST.SEARCH.TAB.SHARED, - isSelected: activeItem === CONST.SEARCH.TAB.SHARED, + value: CONST.SEARCH.STATUS.SHARED, + keyForList: CONST.SEARCH.STATUS.SHARED, + isSelected: activeItem === CONST.SEARCH.STATUS.SHARED, }, { text: translate('common.drafts'), - value: CONST.SEARCH.TAB.DRAFTS, - keyForList: CONST.SEARCH.TAB.DRAFTS, - isSelected: activeItem === CONST.SEARCH.TAB.DRAFTS, + value: CONST.SEARCH.STATUS.DRAFTS, + keyForList: CONST.SEARCH.STATUS.DRAFTS, + isSelected: activeItem === CONST.SEARCH.STATUS.DRAFTS, }, { text: translate('common.finished'), - value: CONST.SEARCH.TAB.FINISHED, - keyForList: CONST.SEARCH.TAB.FINISHED, - isSelected: activeItem === CONST.SEARCH.TAB.FINISHED, + value: CONST.SEARCH.STATUS.FINISHED, + keyForList: CONST.SEARCH.STATUS.FINISHED, + isSelected: activeItem === CONST.SEARCH.STATUS.FINISHED, }, ], [translate, activeItem], @@ -54,7 +55,7 @@ function SearchFiltersStatusPage() { const updateStatus = (values: Partial>) => { SearchActions.updateAdvancedFilters(values); - Navigation.goBack(); + Navigation.goBack(ROUTES.SEARCH_ADVANCED_FILTERS); }; return ( diff --git a/src/pages/Search/SearchFiltersTypePage.tsx b/src/pages/Search/SearchFiltersTypePage.tsx index b9bf453e4471..a10252996ad5 100644 --- a/src/pages/Search/SearchFiltersTypePage.tsx +++ b/src/pages/Search/SearchFiltersTypePage.tsx @@ -13,6 +13,7 @@ import Navigation from '@navigation/Navigation'; import * as SearchActions from '@userActions/Search'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; function SearchFiltersTypePage() { const styles = useThemeStyles(); @@ -36,7 +37,7 @@ function SearchFiltersTypePage() { const updateType = (values: Partial>) => { SearchActions.updateAdvancedFilters(values); - Navigation.goBack(); + Navigation.goBack(ROUTES.SEARCH_ADVANCED_FILTERS); }; return ( From 5efe081ecc51b123726e1a5f71aa577c7f52c430 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Mon, 29 Jul 2024 12:10:05 +0200 Subject: [PATCH 8/9] add handling of search query from advanced filters --- src/libs/SearchUtils.ts | 41 +++++++++++++++++++--- src/pages/Search/SearchFiltersTypePage.tsx | 2 +- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 148f2f8ea631..fa6bddcbd884 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -6,6 +6,7 @@ import type {ListItem, ReportListItemType, TransactionListItemType} from '@compo import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {SearchAdvancedFiltersForm} from '@src/types/form'; +import INPUT_IDS from '@src/types/form/SearchAdvancedFiltersForm'; import type * as OnyxTypes from '@src/types/onyx'; import type {SearchAccountDetails, SearchDataTypes, SearchPersonalDetails, SearchTransaction, SearchTypeToItemMap, SectionsType} from '@src/types/onyx/SearchResults'; import type SearchResults from '@src/types/onyx/SearchResults'; @@ -352,12 +353,42 @@ function normalizeQuery(query: string) { return buildSearchQueryString(normalizedQueryJSON); } +/** + * Given object with chosen search filters builds correct query string from them + * Note: date filter value is built from 2 form fields so needs special handling, all other filters map 1-to-1 + */ function buildQueryStringFromFilters(filterValues: Partial) { - // Object.entries(filterValues).map(([filterKey, filterValue]) => { - // if (filterKey === 'dateFrom' || filterKey === 'dateTo') { - // } - // }); - return ''; + const dateBefore = filterValues[INPUT_IDS.DATE_BEFORE]; + const dateAfter = filterValues[INPUT_IDS.DATE_AFTER]; + + let dateFilter = ''; + if (dateBefore) { + dateFilter += `${CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE}<${dateBefore}`; + } + if (dateBefore && dateAfter) { + dateFilter += ' '; + } + if (dateAfter) { + dateFilter += `${CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE}>${dateAfter}`; + } + + // TODO add handling of multiple values picked + const filtersString = Object.entries(filterValues) + .map(([filterKey, filterValue]) => { + if (filterKey === INPUT_IDS.TYPE && filterValue) { + return `${CONST.SEARCH.SYNTAX_ROOT_KEYS.TYPE}:${filterValue as string}`; + } + + if (filterKey === INPUT_IDS.STATUS && filterValue) { + return `${CONST.SEARCH.SYNTAX_ROOT_KEYS.STATUS}:${filterValue as string}`; + } + + return undefined; + }) + .filter(Boolean) + .join(' '); + + return dateFilter ? `${filtersString} ${dateFilter}` : filtersString; } function getFilters(query: SearchQueryString, fields: Array>) { diff --git a/src/pages/Search/SearchFiltersTypePage.tsx b/src/pages/Search/SearchFiltersTypePage.tsx index a10252996ad5..df5d55739884 100644 --- a/src/pages/Search/SearchFiltersTypePage.tsx +++ b/src/pages/Search/SearchFiltersTypePage.tsx @@ -21,7 +21,7 @@ function SearchFiltersTypePage() { const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); - const activeItem = searchAdvancedFiltersForm?.type ?? CONST.SEARCH.TYPE.EXPENSE; + const activeItem = searchAdvancedFiltersForm?.type; const filterTypeItems = useMemo( () => [ From 153102ffde44ef29025881da91c4502ef23a9ed5 Mon Sep 17 00:00:00 2001 From: Mateusz Titz Date: Mon, 29 Jul 2024 16:58:17 +0200 Subject: [PATCH 9/9] add small fixes to search filters after review --- src/libs/SearchUtils.ts | 15 ++++++++++++--- src/pages/Search/AdvancedSearchFilters.tsx | 3 ++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index fa6bddcbd884..4c3229760d71 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -354,10 +354,10 @@ function normalizeQuery(query: string) { } /** - * Given object with chosen search filters builds correct query string from them - * Note: date filter value is built from 2 form fields so needs special handling, all other filters map 1-to-1 + * @private + * returns Date filter query string part, which needs special logic */ -function buildQueryStringFromFilters(filterValues: Partial) { +function buildDateFilterQuery(filterValues: Partial) { const dateBefore = filterValues[INPUT_IDS.DATE_BEFORE]; const dateAfter = filterValues[INPUT_IDS.DATE_AFTER]; @@ -372,6 +372,13 @@ function buildQueryStringFromFilters(filterValues: Partial${dateAfter}`; } + return dateFilter; +} + +/** + * Given object with chosen search filters builds correct query string from them + */ +function buildQueryStringFromFilters(filterValues: Partial) { // TODO add handling of multiple values picked const filtersString = Object.entries(filterValues) .map(([filterKey, filterValue]) => { @@ -388,6 +395,8 @@ function buildQueryStringFromFilters(filterValues: Partial, fieldName: AdvancedFiltersKeys, translate: LocaleContextProps['translate']) { - if (fieldName === 'date') { + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE) { // the value of date filter is a combination of dateBefore + dateAfter values const {dateAfter, dateBefore} = filters; let dateValue = ''; @@ -104,6 +104,7 @@ function AdvancedSearchFilters() { buttonText={translate('search.viewResults')} containerStyles={[styles.m4]} onSubmit={onFormSubmit} + enabledWhenOffline /> );