From 2dd0e87fe2b97bacd6d5a35ce64ff62bd849adce Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Thu, 26 Sep 2024 16:54:50 +0200 Subject: [PATCH 01/14] add display name replacement --- .../Search/SearchRouter/SearchRouter.tsx | 14 ++++- src/libs/SearchUtils.ts | 59 +++++++++++++++++++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index dfe2cbbe16c6..d9e8b8bd37df 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -1,15 +1,19 @@ import debounce from 'lodash/debounce'; import React, {useCallback, useState} from 'react'; import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import FocusTrapForModal from '@components/FocusTrap/FocusTrapForModal'; import Modal from '@components/Modal'; import type {SearchQueryJSON} from '@components/Search/types'; import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; +import {getAllTaxRates} from '@libs/PolicyUtils'; import * as SearchUtils from '@libs/SearchUtils'; 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'; import {useSearchRouterContext} from './SearchRouterContext'; import SearchRouterInput from './SearchRouterInput'; @@ -22,6 +26,10 @@ function SearchRouter() { const {isSmallScreenWidth} = useResponsiveLayout(); const {isSearchRouterDisplayed, closeSearchRouter} = useSearchRouterContext(); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); + const taxRates = getAllTaxRates(); + const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST); + const [userSearchQuery, setUserSearchQuery] = useState(undefined); const clearUserQuery = () => { @@ -53,11 +61,13 @@ function SearchRouter() { closeSearchRouter(); - const query = SearchUtils.buildSearchQueryString(userSearchQuery); + const standardQuery = SearchUtils.standardizeQueryJSON(userSearchQuery, cardList, reports, taxRates); + const query = SearchUtils.buildSearchQueryString(standardQuery); + SearchActions.clearAllFilters(); Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query})); clearUserQuery(); - }, [closeSearchRouter, userSearchQuery]); + }, [closeSearchRouter, userSearchQuery, cardList, reports, taxRates]); useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ESCAPE, () => { closeSearchRouter(); diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index e178c7dcb77b..13cad8edc401 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -1,3 +1,4 @@ +import cloneDeep from 'lodash/cloneDeep'; import type {OnyxCollection} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import type {ASTNode, QueryFilter, QueryFilters, SearchColumnType, SearchQueryJSON, SearchQueryString, SearchStatus, SortOrder} from '@components/Search/types'; @@ -803,6 +804,63 @@ function getOverflowMenu(itemName: string, hash: number, inputQuery: string, sho ]; } +function getIDFromDisplayValue(filterName: string, filter: string | string[], cardList: OnyxTypes.CardList, reports: OnyxCollection, taxRates: Record) { + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO) { + if (typeof filter === 'string') { + const email = filter; + return PersonalDetailsUtils.getPersonalDetailByEmail(email)?.accountID.toString() ?? filter; + } + const emails = filter; + return emails.map((email) => PersonalDetailsUtils.getPersonalDetailByEmail(email)?.accountID.toString() ?? email); + } + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE) { + const names = Array.isArray(filter) ? filter : ([filter] as string[]); + return names.map((name) => taxRates[name] ?? name).flat(); + } + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID) { + if (typeof filter === 'string') { + const bank = filter; + return Object.values(cardList) + .filter((card) => card.bank === bank) + .map((card) => card.cardID.toString()); + } + const banks = filter; + return Object.values(cardList) + .filter((card) => banks.includes(card.bank)) + .map((card) => card.cardID.toString()); + } + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { + const names = Array.isArray(filter) ? filter : ([filter] as string[]); + + return Object.values(reports ?? {}) + .filter((report) => names.includes(ReportUtils.getReportName(report))) + .map((report) => report?.reportID.toString() ?? ''); + } + return filter; +} + +function standardizeQueryJSON(queryJSON: SearchQueryJSON, cardList: OnyxTypes.CardList, reports: OnyxCollection, taxRates: Record) { + const standardQuery = cloneDeep(queryJSON); + const filters = standardQuery.filters; + const traverse = (node: ASTNode) => { + if (!node.operator) { + return; + } + if (typeof node.left === 'object' && node.left) { + traverse(node.left); + } + if (typeof node.right === 'object' && node.right && !Array.isArray(node.right)) { + traverse(node.right); + } + // eslint-disable-next-line no-param-reassign + node.right = getIDFromDisplayValue(node.left as string, node.right as string | string[], cardList, reports, taxRates); + }; + + traverse(filters); + standardQuery.flatFilters = getFilters(standardQuery); + return standardQuery; +} + /** * Returns whether a given search query is a Canned query. * @@ -839,4 +897,5 @@ export { getExpenseTypeTranslationKey, getOverflowMenu, isCorrectSearchUserName, + standardizeQueryJSON, }; From c2a1dddef5ebecbf5ec9c3eaf0c2f9d886721dad Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Wed, 2 Oct 2024 12:58:55 +0200 Subject: [PATCH 02/14] make input editable and allow names --- src/components/Search/SearchPageHeader.tsx | 23 +++++++++- .../Search/SearchRouter/SearchRouterInput.tsx | 1 + src/libs/SearchUtils.ts | 44 +++++++++++-------- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 5fff92213969..6ca236446fa7 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -44,10 +44,30 @@ type HeaderWrapperProps = Pick & function HeaderWrapper({icon, children, text, isCannedQuery}: HeaderWrapperProps) { const styles = useThemeStyles(); + const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); + const taxRates = getAllTaxRates(); + const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST); + + const [input, setInput] = useState(text); // If the icon is present, the header bar should be taller and use different font. const isCentralPaneSettings = !!icon; + const onSubmit = () => { + if (!input) { + return; + } + const queryJSON = SearchUtils.buildSearchQueryJSON(input); + if (queryJSON) { + const standardQuery = SearchUtils.standardizeQueryJSON(queryJSON, cardList, reports, taxRates); + const query = SearchUtils.buildSearchQueryString(standardQuery); + SearchActions.clearAllFilters(); + Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query})); + } else { + // Handle query parsing error + } + }; + return ( )} diff --git a/src/components/Search/SearchRouter/SearchRouterInput.tsx b/src/components/Search/SearchRouter/SearchRouterInput.tsx index 046386416259..5992e5bac54f 100644 --- a/src/components/Search/SearchRouter/SearchRouterInput.tsx +++ b/src/components/Search/SearchRouter/SearchRouterInput.tsx @@ -56,6 +56,7 @@ function SearchRouterInput({isFullWidth, onChange, onSubmit, defaultValue = '', onSubmitEditing={onSubmit} role={CONST.ROLE.PRESENTATION} autoCapitalize="none" + autoCorrect={false} disabled={disabled} shouldUseDisabledStyles={false} textInputContainerStyles={styles.borderNone} diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 1e7baf562dc6..7afccdc0c98e 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -729,10 +729,10 @@ function getPolicyIDFromSearchQuery(queryJSON: SearchQueryJSON) { function getDisplayValue(filterName: string, filter: string, personalDetails: OnyxTypes.PersonalDetailsList, cardList: OnyxTypes.CardList, reports: OnyxCollection) { if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO) { - return PersonalDetailsUtils.createDisplayName(personalDetails?.[filter]?.login ?? '', personalDetails?.[filter]); + return personalDetails?.[filter]?.login ?? filter; } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID) { - return cardList[filter].bank; + return cardList[filter]?.bank ?? filter; } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { return ReportUtils.getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filter}`]); @@ -774,9 +774,15 @@ function getSearchHeaderTitle( let displayQueryFilters: QueryFilter[] = []; if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE) { const taxRateIDs = queryFilter.map((filter) => filter.value.toString()); - const taxRateNames = Object.entries(TaxRates) - .filter(([, taxRateKeys]) => taxRateKeys.some((taxID) => taxRateIDs.includes(taxID))) - .map(([taxRate]) => taxRate); + const taxRateNames = taxRateIDs + .map((id) => { + const taxRate = Object.entries(TaxRates) + .filter(([, IDs]) => IDs.includes(id)) + .map(([name]) => name); + return taxRate?.length > 0 ? taxRate : id; + }) + .flat(); + displayQueryFilters = taxRateNames.map((taxRate) => ({ operator: queryFilter.at(0)?.operator ?? CONST.SEARCH.SYNTAX_OPERATORS.AND, value: taxRate, @@ -787,7 +793,7 @@ function getSearchHeaderTitle( value: getDisplayValue(key, filter.value.toString(), PersonalDetails, cardList, reports), })); } - title += buildFilterString(key, displayQueryFilters, ' '); + title += buildFilterString(key, displayQueryFilters, key === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD ? ' ' : ','); }); return title; @@ -850,21 +856,21 @@ function getIDFromDisplayValue(filterName: string, filter: string | string[], ca if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID) { if (typeof filter === 'string') { const bank = filter; - return Object.values(cardList) - .filter((card) => card.bank === bank) - .map((card) => card.cardID.toString()); + const ids = + Object.values(cardList) + .filter((card) => card.bank === bank) + .map((card) => card.cardID.toString()) ?? filter; + return ids.length > 0 ? ids : bank; } const banks = filter; - return Object.values(cardList) - .filter((card) => banks.includes(card.bank)) - .map((card) => card.cardID.toString()); - } - if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { - const names = Array.isArray(filter) ? filter : ([filter] as string[]); - - return Object.values(reports ?? {}) - .filter((report) => names.includes(ReportUtils.getReportName(report))) - .map((report) => report?.reportID.toString() ?? ''); + return banks + .map( + (bank) => + Object.values(cardList) + .filter((card) => card.bank === bank) + .map((card) => card.cardID.toString()) ?? bank, + ) + .flat(); } return filter; } From 08e045dc9639d4393ad15a7ef5927dd732e2db58 Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Thu, 3 Oct 2024 13:39:40 +0200 Subject: [PATCH 03/14] improve variable and function names --- src/components/Search/SearchPageHeader.tsx | 4 ++-- src/libs/SearchUtils.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 6ca236446fa7..21141f63ad91 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -59,8 +59,8 @@ function HeaderWrapper({icon, children, text, isCannedQuery}: HeaderWrapperProps } const queryJSON = SearchUtils.buildSearchQueryJSON(input); if (queryJSON) { - const standardQuery = SearchUtils.standardizeQueryJSON(queryJSON, cardList, reports, taxRates); - const query = SearchUtils.buildSearchQueryString(standardQuery); + const standardizedQuery = SearchUtils.standardizeQueryJSON(queryJSON, cardList, reports, taxRates); + const query = SearchUtils.buildSearchQueryString(standardizedQuery); SearchActions.clearAllFilters(); Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query})); } else { diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 7afccdc0c98e..281f01e260bb 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -840,7 +840,7 @@ function getOverflowMenu(itemName: string, hash: number, inputQuery: string, sho ]; } -function getIDFromDisplayValue(filterName: string, filter: string | string[], cardList: OnyxTypes.CardList, reports: OnyxCollection, taxRates: Record) { +function findIDFromDisplayValue(filterName: string, filter: string | string[], cardList: OnyxTypes.CardList, reports: OnyxCollection, taxRates: Record) { if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO) { if (typeof filter === 'string') { const email = filter; @@ -889,7 +889,7 @@ function standardizeQueryJSON(queryJSON: SearchQueryJSON, cardList: OnyxTypes.Ca traverse(node.right); } // eslint-disable-next-line no-param-reassign - node.right = getIDFromDisplayValue(node.left as string, node.right as string | string[], cardList, reports, taxRates); + node.right = findIDFromDisplayValue(node.left as string, node.right as string | string[], cardList, reports, taxRates); }; traverse(filters); From f23f6373979f6f7735dfaf378be7efe201e18869 Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Thu, 3 Oct 2024 14:23:28 +0200 Subject: [PATCH 04/14] improve HeaderWrapper --- src/components/Search/SearchPageHeader.tsx | 51 +++++++++++----------- src/libs/SearchUtils.ts | 5 ++- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 21141f63ad91..661e4d6f88d3 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -40,34 +40,15 @@ import type {SearchQueryJSON} from './types'; type HeaderWrapperProps = Pick & { text: string; isCannedQuery: boolean; + onSubmit?: () => void; + onChange?: (input: string) => void; }; -function HeaderWrapper({icon, children, text, isCannedQuery}: HeaderWrapperProps) { +function HeaderWrapper({icon, children, text, isCannedQuery, onSubmit, onChange}: HeaderWrapperProps) { const styles = useThemeStyles(); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); - const taxRates = getAllTaxRates(); - const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST); - - const [input, setInput] = useState(text); - // If the icon is present, the header bar should be taller and use different font. const isCentralPaneSettings = !!icon; - const onSubmit = () => { - if (!input) { - return; - } - const queryJSON = SearchUtils.buildSearchQueryJSON(input); - if (queryJSON) { - const standardizedQuery = SearchUtils.standardizeQueryJSON(queryJSON, cardList, reports, taxRates); - const query = SearchUtils.buildSearchQueryString(standardizedQuery); - SearchActions.clearAllFilters(); - Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query})); - } else { - // Handle query parsing error - } - }; - return ( )} @@ -146,13 +127,14 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false); const [isDownloadErrorModalVisible, setIsDownloadErrorModalVisible] = useState(false); - const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {}); - const {status, type} = queryJSON; const isCannedQuery = SearchUtils.isCannedSearchQuery(queryJSON); + const headerText = isCannedQuery ? translate(getHeaderContent(type).titleText) : SearchUtils.getSearchHeaderTitle(queryJSON, personalDetails, cardList, reports, taxRates); + const [input, setInput] = useState(headerText); + + const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {}); const headerIcon = getHeaderContent(type).icon; - const headerText = isCannedQuery ? translate(getHeaderContent(type).titleText) : SearchUtils.getSearchHeaderTitle(queryJSON, personalDetails, cardList, reports, taxRates); const handleDeleteExpenses = () => { if (selectedTransactionsKeys.length === 0) { @@ -339,12 +321,29 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { Navigation.navigate(ROUTES.SEARCH_ADVANCED_FILTERS); }; + const onSubmit = () => { + if (!input) { + return; + } + const inputQueryJSON = SearchUtils.buildSearchQueryJSON(input); + if (inputQueryJSON) { + const standardizedQuery = SearchUtils.standardizeQueryJSON(inputQueryJSON, cardList, reports, taxRates); + const query = SearchUtils.buildSearchQueryString(standardizedQuery); + SearchActions.clearAllFilters(); + Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query})); + } else { + // Handle query parsing error + } + }; + return ( <> {headerButtonsOptions.length > 0 ? ( Date: Thu, 3 Oct 2024 18:36:55 +0200 Subject: [PATCH 05/14] fix merge --- src/components/Search/SearchPageHeader.tsx | 3 +-- src/components/Search/SearchRouter/SearchRouter.tsx | 5 +++-- src/components/Search/SearchRouter/SearchRouterInput.tsx | 5 +++++ 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index d9f278115902..397ad2a5d46a 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -74,7 +74,6 @@ function HeaderWrapper({icon, children, text, isCannedQuery, onSubmit, onChange} setValue={onChange} onSubmit={onSubmit} updateSearch={() => {}} - disabled isFullWidth wrapperStyle={[styles.searchRouterInputResults, styles.br2]} wrapperFocusedStyle={styles.searchRouterInputResultsFocused} @@ -343,7 +342,7 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { <> (null); - const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); + const [reportsList] = useOnyx(ONYXKEYS.COLLECTION.REPORT); const taxRates = getAllTaxRates(); const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST); @@ -151,7 +151,8 @@ function SearchRouter() { return; } closeSearchRouter(); - const queryString = SearchUtils.buildSearchQueryString(query); + const standardizedQuery = SearchUtils.standardizeQueryJSON(query, cardList, reportsList, taxRates); + const queryString = SearchUtils.buildSearchQueryString(standardizedQuery); Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: queryString})); clearUserQuery(); }, diff --git a/src/components/Search/SearchRouter/SearchRouterInput.tsx b/src/components/Search/SearchRouter/SearchRouterInput.tsx index ac5357f399e0..405093ca1f0d 100644 --- a/src/components/Search/SearchRouter/SearchRouterInput.tsx +++ b/src/components/Search/SearchRouter/SearchRouterInput.tsx @@ -19,6 +19,9 @@ type SearchRouterInputProps = { /** Callback to update search in SearchRouter */ updateSearch: (searchTerm: string) => void; + /** Callback invoked when the user submits the input */ + onSubmit?: () => void; + /** SearchRouterList ref for managing TextInput and SearchRouterList focus */ routerListRef?: RefObject; @@ -45,6 +48,7 @@ function SearchRouterInput({ value, setValue, updateSearch, + onSubmit = () => {}, routerListRef, isFullWidth, disabled = false, @@ -77,6 +81,7 @@ function SearchRouterInput({ autoCapitalize="none" autoCorrect={false} disabled={disabled} + onSubmitEditing={onSubmit} shouldUseDisabledStyles={false} textInputContainerStyles={styles.borderNone} inputStyle={[styles.searchInputStyle, inputWidth, styles.pl3, styles.pr3]} From b8c7e0bc4757e04f5b17084d7de0131cde688690 Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Fri, 4 Oct 2024 10:03:54 +0200 Subject: [PATCH 06/14] improve input for keywords --- src/components/Search/SearchPageHeader.tsx | 16 ++++++++-------- src/libs/SearchUtils.ts | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 397ad2a5d46a..cb9848450c49 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -41,10 +41,10 @@ type HeaderWrapperProps = Pick & text: string; isCannedQuery: boolean; onSubmit: () => void; - onChange: (input: string) => void; + setValue: (input: string) => void; }; -function HeaderWrapper({icon, children, text, isCannedQuery, onSubmit, onChange}: HeaderWrapperProps) { +function HeaderWrapper({icon, children, text, isCannedQuery, onSubmit, setValue}: HeaderWrapperProps) { const styles = useThemeStyles(); // If the icon is present, the header bar should be taller and use different font. const isCentralPaneSettings = !!icon; @@ -71,7 +71,7 @@ function HeaderWrapper({icon, children, text, isCannedQuery, onSubmit, onChange} {}} isFullWidth @@ -132,7 +132,7 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { const {status, type} = queryJSON; const isCannedQuery = SearchUtils.isCannedSearchQuery(queryJSON); const headerText = isCannedQuery ? translate(getHeaderContent(type).titleText) : SearchUtils.getSearchHeaderTitle(queryJSON, personalDetails, cardList, reports, taxRates); - const [input, setInput] = useState(headerText); + const [inputValue, setInputValue] = useState(headerText); const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {}); @@ -324,10 +324,10 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { }; const onSubmit = () => { - if (!input) { + if (!inputValue) { return; } - const inputQueryJSON = SearchUtils.buildSearchQueryJSON(input); + const inputQueryJSON = SearchUtils.buildSearchQueryJSON(inputValue); if (inputQueryJSON) { const standardizedQuery = SearchUtils.standardizeQueryJSON(inputQueryJSON, cardList, reports, taxRates); const query = SearchUtils.buildSearchQueryString(standardizedQuery); @@ -342,10 +342,10 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { <> {headerButtonsOptions.length > 0 ? ( Date: Fri, 4 Oct 2024 19:32:02 +0200 Subject: [PATCH 07/14] fix status bar for qustom queries --- src/components/Search/SearchPageHeader.tsx | 14 ++++++++++---- src/components/Search/SearchStatusBar.tsx | 14 ++++++-------- src/pages/Search/SearchPage.tsx | 6 +----- src/pages/Search/SearchPageBottomTab.tsx | 4 +--- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index cb9848450c49..1ab89b4440d2 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -1,4 +1,4 @@ -import React, {useMemo, useState} from 'react'; +import React, {useEffect, useMemo, useState} from 'react'; import {InteractionManager, View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; @@ -39,12 +39,13 @@ import type {SearchQueryJSON} from './types'; type HeaderWrapperProps = Pick & { text: string; + value: string; isCannedQuery: boolean; onSubmit: () => void; setValue: (input: string) => void; }; -function HeaderWrapper({icon, children, text, isCannedQuery, onSubmit, setValue}: HeaderWrapperProps) { +function HeaderWrapper({icon, children, text, value, isCannedQuery, onSubmit, setValue}: HeaderWrapperProps) { const styles = useThemeStyles(); // If the icon is present, the header bar should be taller and use different font. const isCentralPaneSettings = !!icon; @@ -70,7 +71,7 @@ function HeaderWrapper({icon, children, text, isCannedQuery, onSubmit, setValue} ) : ( {}} @@ -134,6 +135,10 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { const headerText = isCannedQuery ? translate(getHeaderContent(type).titleText) : SearchUtils.getSearchHeaderTitle(queryJSON, personalDetails, cardList, reports, taxRates); const [inputValue, setInputValue] = useState(headerText); + useEffect(() => { + setInputValue(headerText); + }, [headerText]); + const selectedTransactionsKeys = Object.keys(selectedTransactions ?? {}); const headerIcon = getHeaderContent(type).icon; @@ -342,7 +347,8 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { <> void; }; @@ -154,13 +152,13 @@ function getOptions(type: SearchDataTypes) { } } -function SearchStatusBar({type, status, policyID, onStatusChange}: SearchStatusBarProps) { +function SearchStatusBar({queryJSON, onStatusChange}: SearchStatusBarProps) { const {singleExecution} = useSingleExecution(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const theme = useTheme(); const {translate} = useLocalize(); - const options = getOptions(type); + const options = getOptions(queryJSON.type); const scrollRef = useRef(null); const isScrolledRef = useRef(false); const {shouldShowStatusBarLoading} = useSearchContext(); @@ -179,10 +177,10 @@ function SearchStatusBar({type, status, policyID, onStatusChange}: SearchStatusB {options.map((item, index) => { const onPress = singleExecution(() => { onStatusChange?.(); - const query = SearchUtils.buildCannedSearchQuery({type: item.type, status: item.status, policyID}); + const query = SearchUtils.buildSearchQueryString({...queryJSON, status: item.status}); Navigation.setParams({q: query}); }); - const isActive = status === item.status; + const isActive = queryJSON.status === item.status; const isFirstItem = index === 0; const isLastItem = index === options.length - 1; diff --git a/src/pages/Search/SearchPage.tsx b/src/pages/Search/SearchPage.tsx index 7f82aaabfc6f..82c502febaf8 100644 --- a/src/pages/Search/SearchPage.tsx +++ b/src/pages/Search/SearchPage.tsx @@ -47,11 +47,7 @@ function SearchPage({route}: SearchPageProps) { queryJSON={queryJSON} hash={queryJSON.hash} /> - + )} diff --git a/src/pages/Search/SearchPageBottomTab.tsx b/src/pages/Search/SearchPageBottomTab.tsx index 38e4c5166884..baad23eaec14 100644 --- a/src/pages/Search/SearchPageBottomTab.tsx +++ b/src/pages/Search/SearchPageBottomTab.tsx @@ -109,9 +109,7 @@ function SearchPageBottomTab() { /> {shouldUseNarrowLayout && ( { topBarOffset.value = withTiming(variables.searchHeaderHeight, {duration: ANIMATION_DURATION_IN_MS}); }} From 1b0e25904ae8a9a6bf419a2600f1c0b31bf63a5f Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Fri, 4 Oct 2024 20:04:34 +0200 Subject: [PATCH 08/14] review --- src/components/Search/SearchPageHeader.tsx | 5 ++-- .../Search/SearchRouter/SearchRouter.tsx | 3 +-- src/libs/SearchUtils.ts | 25 +++++++++++++------ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 1ab89b4440d2..d972fc013683 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -20,6 +20,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import * as SearchActions from '@libs/actions/Search'; +import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import {getAllTaxRates} from '@libs/PolicyUtils'; import * as SearchUtils from '@libs/SearchUtils'; @@ -334,12 +335,12 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { } const inputQueryJSON = SearchUtils.buildSearchQueryJSON(inputValue); if (inputQueryJSON) { - const standardizedQuery = SearchUtils.standardizeQueryJSON(inputQueryJSON, cardList, reports, taxRates); + const standardizedQuery = SearchUtils.standardizeQueryJSON(inputQueryJSON, cardList, taxRates); const query = SearchUtils.buildSearchQueryString(standardizedQuery); SearchActions.clearAllFilters(); Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query})); } else { - // Handle query parsing error + Log.alert(`${CONST.ERROR.ENSURE_BUGBOT} user query failed to parse`, inputValue, false); } }; diff --git a/src/components/Search/SearchRouter/SearchRouter.tsx b/src/components/Search/SearchRouter/SearchRouter.tsx index c28dcb806365..8ac7c5f92bc5 100644 --- a/src/components/Search/SearchRouter/SearchRouter.tsx +++ b/src/components/Search/SearchRouter/SearchRouter.tsx @@ -42,7 +42,6 @@ function SearchRouter() { const {isSearchRouterDisplayed, closeSearchRouter} = useSearchRouterContext(); const listRef = useRef(null); - const [reportsList] = useOnyx(ONYXKEYS.COLLECTION.REPORT); const taxRates = getAllTaxRates(); const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST); @@ -151,7 +150,7 @@ function SearchRouter() { return; } closeSearchRouter(); - const standardizedQuery = SearchUtils.standardizeQueryJSON(query, cardList, reportsList, taxRates); + const standardizedQuery = SearchUtils.standardizeQueryJSON(query, cardList, taxRates); const queryString = SearchUtils.buildSearchQueryString(standardizedQuery); Navigation.navigate(ROUTES.SEARCH_CENTRAL_PANE.getRoute({query: queryString})); clearUserQuery(); diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index d904756a1ad4..55b499b40175 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -740,7 +740,8 @@ function getDisplayValue(filterName: string, filter: string, personalDetails: On return filter; } -function buildFilterString(filterName: string, queryFilters: QueryFilter[], delimiter = ',') { +function buildFilterString(filterName: string, queryFilters: QueryFilter[]) { + const delimiter = filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD ? ' ' : ','; let filterValueString = ''; queryFilters.forEach((queryFilter, index) => { // If the previous queryFilter has the same operator (this rule applies only to eq and neq operators) then append the current value @@ -750,7 +751,7 @@ function buildFilterString(filterName: string, queryFilters: QueryFilter[], deli ) { filterValueString += `${delimiter}${sanitizeString(queryFilter.value.toString())}`; } else if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD) { - filterValueString += ` ${sanitizeString(queryFilter.value.toString())}`; + filterValueString += `${delimiter}${sanitizeString(queryFilter.value.toString())}`; } else { filterValueString += ` ${filterName}${operatorToSignMap[queryFilter.operator]}${sanitizeString(queryFilter.value.toString())}`; } @@ -795,7 +796,7 @@ function getSearchHeaderTitle( value: getDisplayValue(key, filter.value.toString(), PersonalDetails, cardList, reports), })); } - title += buildFilterString(key, displayQueryFilters, key === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD ? ' ' : ','); + title += buildFilterString(key, displayQueryFilters); }); return title; @@ -842,7 +843,11 @@ function getOverflowMenu(itemName: string, hash: number, inputQuery: string, sho ]; } -function findIDFromDisplayValue(filterName: string, filter: string | string[], cardList: OnyxTypes.CardList, reports: OnyxCollection, taxRates: Record) { +/** + * @private + * Given a filter name and its value, this function will try to find the corresponding ID. + */ +function findIDFromDisplayValue(filterName: ValueOf, filter: string | string[], cardList: OnyxTypes.CardList, taxRates: Record) { if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO) { if (typeof filter === 'string') { const email = filter; @@ -877,7 +882,10 @@ function findIDFromDisplayValue(filterName: string, filter: string | string[], c return filter; } -function standardizeQueryJSON(queryJSON: SearchQueryJSON, cardList: OnyxTypes.CardList, reports: OnyxCollection, taxRates: Record) { +/** + * Given a search query, this function will standardize the query by replacing display values with their corresponding IDs. + */ +function standardizeQueryJSON(queryJSON: SearchQueryJSON, cardList: OnyxTypes.CardList, taxRates: Record) { const standardQuery = cloneDeep(queryJSON); const filters = standardQuery.filters; const traverse = (node: ASTNode) => { @@ -890,8 +898,11 @@ function standardizeQueryJSON(queryJSON: SearchQueryJSON, cardList: OnyxTypes.Ca if (typeof node.right === 'object' && node.right && !Array.isArray(node.right)) { traverse(node.right); } - // eslint-disable-next-line no-param-reassign - node.right = findIDFromDisplayValue(node.left as string, node.right as string | string[], cardList, reports, taxRates); + + if (typeof node.left !== 'object') { + // eslint-disable-next-line no-param-reassign + node.right = findIDFromDisplayValue(node.left, node.right as string | string[], cardList, taxRates); + } }; if (filters) { From 35e32baed4c2b34de5150ffaae25e09d5c00877b Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Mon, 7 Oct 2024 11:34:28 +0200 Subject: [PATCH 09/14] fix type, expensetype, amount, and date --- src/libs/SearchUtils.ts | 11 ++++++----- src/pages/Search/AdvancedSearchFilters.tsx | 5 ++++- .../SearchFiltersDatePage.tsx | 6 ++++-- .../SearchFiltersExpenseTypePage.tsx | 10 ++++++---- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 55b499b40175..af20d1e8ef7e 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -19,6 +19,7 @@ import type {ListItemDataType, ListItemType, SearchDataTypes, SearchPersonalDeta import * as CurrencyUtils from './CurrencyUtils'; import DateUtils from './DateUtils'; import {translateLocal} from './Localize'; +import {validateAmount} from './MoneyRequestUtils'; import Navigation from './Navigation/Navigation'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; @@ -689,12 +690,12 @@ function buildFilterFormValuesFromQuery(queryJSON: SearchQueryJSON) { .join(' '); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE) { - filtersForm[FILTER_KEYS.DATE_BEFORE] = filters[filterKey]?.find((filter) => filter.operator === 'lt')?.value.toString(); - filtersForm[FILTER_KEYS.DATE_AFTER] = filters[filterKey]?.find((filter) => filter.operator === 'gt')?.value.toString(); + filtersForm[FILTER_KEYS.DATE_BEFORE] = filters[filterKey]?.find((filter) => filter.operator === 'lt' && DateUtils.isDate(filter.value))?.value.toString(); + filtersForm[FILTER_KEYS.DATE_AFTER] = filters[filterKey]?.find((filter) => filter.operator === 'gt' && DateUtils.isDate(filter.value))?.value.toString(); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT) { - filtersForm[FILTER_KEYS.LESS_THAN] = filters[filterKey]?.find((filter) => filter.operator === 'lt')?.value.toString(); - filtersForm[FILTER_KEYS.GREATER_THAN] = filters[filterKey]?.find((filter) => filter.operator === 'gt')?.value.toString(); + filtersForm[FILTER_KEYS.LESS_THAN] = filters[filterKey]?.find((filter) => filter.operator === 'lt' && validateAmount(filter.value.toString(), 2))?.value.toString(); + filtersForm[FILTER_KEYS.GREATER_THAN] = filters[filterKey]?.find((filter) => filter.operator === 'gt' && validateAmount(filter.value.toString(), 2))?.value.toString(); } } @@ -735,7 +736,7 @@ function getDisplayValue(filterName: string, filter: string, personalDetails: On return cardList[filter]?.bank ?? filter; } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { - return ReportUtils.getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filter}`]); + return ReportUtils.getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filter}`]) || filter; } return filter; } diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 7009764629ba..131c84e4b353 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -231,7 +231,10 @@ function AdvancedSearchFilters() { const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST); const taxRates = getAllTaxRates(); const personalDetails = usePersonalDetails(); - const currentType = searchAdvancedFilters?.type ?? CONST.SEARCH.DATA_TYPES.EXPENSE; + let currentType = searchAdvancedFilters?.type ?? CONST.SEARCH.DATA_TYPES.EXPENSE; + if (!Object.keys(typeFiltersKeys).includes(currentType)) { + currentType = CONST.SEARCH.DATA_TYPES.EXPENSE; + } const queryString = useMemo(() => SearchUtils.buildQueryStringFromFilterFormValues(searchAdvancedFilters), [searchAdvancedFilters]); const queryJSON = useMemo(() => SearchUtils.buildSearchQueryJSON(queryString || SearchUtils.buildCannedSearchQuery()), [queryString]); diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersDatePage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersDatePage.tsx index b019a6995cec..f50417c325e3 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersDatePage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersDatePage.tsx @@ -9,6 +9,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {updateAdvancedFilters} from '@libs/actions/Search'; +import DateUtils from '@libs/DateUtils'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -20,8 +21,9 @@ function SearchFiltersDatePage() { const {translate} = useLocalize(); const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); - const dateAfter = searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_AFTER]; - const dateBefore = searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_BEFORE]; + + const dateAfter = DateUtils.isDate(searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_AFTER]) ? searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_AFTER] : undefined; + const dateBefore = DateUtils.isDate(searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_BEFORE]) ? searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_BEFORE] : undefined; const updateDateFilter = (values: FormOnyxValues) => { updateAdvancedFilters(values); diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersExpenseTypePage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersExpenseTypePage.tsx index 941602f8efe8..5f1fed2f1efa 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersExpenseTypePage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersExpenseTypePage.tsx @@ -21,10 +21,12 @@ function SearchFiltersExpenseTypePage() { const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); const initiallySelectedItems = useMemo( () => - searchAdvancedFiltersForm?.expenseType?.map((expenseType) => { - const expenseTypeName = translate(getExpenseTypeTranslationKey(expenseType as ValueOf)); - return {name: expenseTypeName, value: expenseType}; - }), + searchAdvancedFiltersForm?.expenseType + ?.filter((expenseType) => Object.values(CONST.SEARCH.TRANSACTION_TYPE).includes(expenseType as ValueOf)) + .map((expenseType) => { + const expenseTypeName = translate(getExpenseTypeTranslationKey(expenseType as ValueOf)); + return {name: expenseTypeName, value: expenseType}; + }), [searchAdvancedFiltersForm, translate], ); const allExpenseTypes = Object.values(CONST.SEARCH.TRANSACTION_TYPE); From 7ca5af192330b666cb6cb0869a1e5190b58d3941 Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Mon, 7 Oct 2024 17:32:33 +0200 Subject: [PATCH 10/14] fix search bar loading --- src/components/Search/SearchContext.tsx | 7 ++++++- src/components/Search/index.tsx | 14 +++++++++++--- src/components/Search/types.ts | 2 ++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/components/Search/SearchContext.tsx b/src/components/Search/SearchContext.tsx index 50b84ae68469..30825ed3bfba 100644 --- a/src/components/Search/SearchContext.tsx +++ b/src/components/Search/SearchContext.tsx @@ -13,6 +13,8 @@ const defaultSearchContext = { clearSelectedTransactions: () => {}, shouldShowStatusBarLoading: false, setShouldShowStatusBarLoading: () => {}, + lastSearchType: undefined, + setLastSearchType: () => {}, }; const Context = React.createContext(defaultSearchContext); @@ -69,6 +71,7 @@ function SearchContextProvider({children}: ChildrenProps) { ); const [shouldShowStatusBarLoading, setShouldShowStatusBarLoading] = useState(false); + const [lastSearchType, setLastSearchType] = useState(undefined); const searchContext = useMemo( () => ({ @@ -78,8 +81,10 @@ function SearchContextProvider({children}: ChildrenProps) { clearSelectedTransactions, shouldShowStatusBarLoading, setShouldShowStatusBarLoading, + lastSearchType, + setLastSearchType, }), - [searchContextData, setCurrentSearchHash, setSelectedTransactions, clearSelectedTransactions, shouldShowStatusBarLoading], + [searchContextData, setCurrentSearchHash, setSelectedTransactions, clearSelectedTransactions, shouldShowStatusBarLoading, lastSearchType, setLastSearchType], ); return {children}; diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index e459be1815bc..4db351da59f2 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -91,7 +91,8 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr const {isSmallScreenWidth, isLargeScreenWidth} = useResponsiveLayout(); const navigation = useNavigation>(); const lastSearchResultsRef = useRef>(); - const {setCurrentSearchHash, setSelectedTransactions, selectedTransactions, clearSelectedTransactions, setShouldShowStatusBarLoading} = useSearchContext(); + const {setCurrentSearchHash, setSelectedTransactions, selectedTransactions, clearSelectedTransactions, setShouldShowStatusBarLoading, lastSearchType, setLastSearchType} = + useSearchContext(); const {selectionMode} = useMobileSelectionMode(); const [offset, setOffset] = useState(0); @@ -101,6 +102,13 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr const [transactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION); const previousTransactions = usePrevious(transactions); + useEffect(() => { + if (!currentSearchResults?.search?.type) { + return; + } + setLastSearchType(currentSearchResults.search.type); + }, [lastSearchType, queryJSON, setLastSearchType, currentSearchResults]); + const canSelectMultiple = isSmallScreenWidth ? !!selectionMode?.isEnabled : true; useEffect(() => { @@ -183,8 +191,8 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr useEffect(() => { /** We only want to display the skeleton for the status filters the first time we load them for a specific data type */ - setShouldShowStatusBarLoading(shouldShowLoadingState && searchResults?.search?.type !== type); - }, [searchResults?.search?.type, setShouldShowStatusBarLoading, shouldShowLoadingState, type]); + setShouldShowStatusBarLoading(shouldShowLoadingState && lastSearchType !== type); + }, [lastSearchType, setShouldShowStatusBarLoading, shouldShowLoadingState, type]); useEffect(() => { if (!isSearchResultsEmpty || prevIsSearchResultEmpty) { diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index 3d35190bf1a4..4f96090be9d0 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -41,6 +41,8 @@ type SearchContext = { clearSelectedTransactions: (hash?: number) => void; shouldShowStatusBarLoading: boolean; setShouldShowStatusBarLoading: (shouldShow: boolean) => void; + setLastSearchType: (type: string | undefined) => void; + lastSearchType: string | undefined; }; type ASTNode = { From ee430d16c0093da61b827a35651b4593c01eee8e Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Wed, 9 Oct 2024 09:25:48 +0200 Subject: [PATCH 11/14] fix to, from filters and auto focus --- src/components/Search/SearchFiltersChatsSelector.tsx | 12 +++++++----- src/components/Search/SearchPageHeader.tsx | 1 + .../Search/SearchRouter/SearchRouterInput.tsx | 6 +++++- src/pages/Search/AdvancedSearchFilters.tsx | 8 +++++++- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index 36b56867b99f..e6e8e0085f17 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -54,11 +54,13 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen const cleanSearchTerm = useMemo(() => searchTerm.trim().toLowerCase(), [searchTerm]); const selectedOptions = useMemo(() => { - return selectedReportIDs.map((id) => { - const report = getSelectedOptionData(OptionsListUtils.createOptionFromReport({...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, personalDetails)); - const alternateText = OptionsListUtils.getAlternateText(report, {}); - return {...report, alternateText}; - }); + return selectedReportIDs + .filter((id) => reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`]) + .map((id) => { + const report = getSelectedOptionData(OptionsListUtils.createOptionFromReport({...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, personalDetails)); + const alternateText = OptionsListUtils.getAlternateText(report, {}); + return {...report, alternateText}; + }); }, [personalDetails, reports, selectedReportIDs]); const defaultOptions = useMemo(() => { diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index d972fc013683..8436089718c5 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -76,6 +76,7 @@ function HeaderWrapper({icon, children, text, value, isCannedQuery, onSubmit, se setValue={setValue} onSubmit={onSubmit} updateSearch={() => {}} + autoFocus={false} isFullWidth wrapperStyle={[styles.searchRouterInputResults, styles.br2]} wrapperFocusedStyle={styles.searchRouterInputResultsFocused} diff --git a/src/components/Search/SearchRouter/SearchRouterInput.tsx b/src/components/Search/SearchRouter/SearchRouterInput.tsx index 405093ca1f0d..7b850f96efc1 100644 --- a/src/components/Search/SearchRouter/SearchRouterInput.tsx +++ b/src/components/Search/SearchRouter/SearchRouterInput.tsx @@ -31,6 +31,9 @@ type SearchRouterInputProps = { /** Whether the input is disabled */ disabled?: boolean; + /** Whether the input should be focused */ + autoFocus?: boolean; + /** Any additional styles to apply */ wrapperStyle?: StyleProp; @@ -52,6 +55,7 @@ function SearchRouterInput({ routerListRef, isFullWidth, disabled = false, + autoFocus = true, wrapperStyle, wrapperFocusedStyle, rightComponent, @@ -74,7 +78,7 @@ function SearchRouterInput({ , translate: LocaleContextProps['translate'], reports?: OnyxCollection) { - return filters.in ? filters.in.map((id) => ReportUtils.getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`])).join(', ') : undefined; + return filters.in + ? filters.in + .map((id) => ReportUtils.getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`])) + .filter(Boolean) + .join(', ') + : undefined; } function AdvancedSearchFilters() { const {translate} = useLocalize(); From 25b729bfca18f2fea2ce9ecb4a5c7ce8cad4622f Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Wed, 9 Oct 2024 13:20:33 +0200 Subject: [PATCH 12/14] fix currency, tag and category --- src/components/Search/SearchPageHeader.tsx | 5 +++- src/libs/SearchUtils.ts | 35 +++++++++++++++++++--- src/pages/Search/SearchTypeMenuNarrow.tsx | 7 ++++- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 8436089718c5..03aac7f4327e 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -128,6 +128,9 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); const taxRates = getAllTaxRates(); const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST); + const [currencyList = {}] = useOnyx(ONYXKEYS.CURRENCY_LIST); + const [policyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES); + const [policyTagsLists] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS); const [isDeleteExpensesConfirmModalVisible, setIsDeleteExpensesConfirmModalVisible] = useState(false); const [isOfflineModalVisible, setIsOfflineModalVisible] = useState(false); const [isDownloadErrorModalVisible, setIsDownloadErrorModalVisible] = useState(false); @@ -324,7 +327,7 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { } const onPress = () => { - const filterFormValues = SearchUtils.buildFilterFormValuesFromQuery(queryJSON); + const filterFormValues = SearchUtils.buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList); SearchActions.updateAdvancedFilters(filterFormValues); Navigation.navigate(ROUTES.SEARCH_ADVANCED_FILTERS); diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index af20d1e8ef7e..e94c4c441c8d 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -22,6 +22,7 @@ import {translateLocal} from './Localize'; import {validateAmount} from './MoneyRequestUtils'; import Navigation from './Navigation/Navigation'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; +import {getTagNamesFromTagsLists} from './PolicyUtils'; import * as ReportActionsUtils from './ReportActionsUtils'; import * as ReportUtils from './ReportUtils'; import * as searchParser from './SearchParser/searchParser'; @@ -657,7 +658,12 @@ function buildQueryStringFromFilterFormValues(filterValues: Partial, + policyTags: OnyxCollection, + currencyList: OnyxTypes.CurrencyList, +) { const filters = getFilters(queryJSON); const filterKeys = Object.keys(filters); const filtersForm = {} as Partial; @@ -666,18 +672,39 @@ function buildFilterFormValuesFromQuery(queryJSON: SearchQueryJSON) { filtersForm[filterKey] = filters[filterKey]?.[0]?.value.toString(); } if ( - filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPENSE_TYPE || - filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG || - filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN ) { filtersForm[filterKey] = filters[filterKey]?.map((filter) => filter.value.toString()); } + if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY) { + filtersForm[filterKey] = filters[filterKey]?.filter((currency) => Object.keys(currencyList).includes(currency.value.toString())).map((currency) => currency.value.toString()); + } + if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG) { + filtersForm[filterKey] = filters[filterKey] + ?.map((tag) => tag.value.toString()) + .filter((name) => + Object.values(policyTags ?? {}) + .map((tagList = {}) => getTagNamesFromTagsLists(tagList)) + .flat() + .includes(name), + ); + } + if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY) { + filtersForm[filterKey] = + filters[filterKey] + ?.map((category) => category.value.toString()) + .filter((name) => + Object.values(policyCategories ?? {}) + .map((xd) => Object.values(xd ?? {}).map((category) => category.name)) + .flat() + .includes(name), + ) ?? []; + } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD) { filtersForm[filterKey] = filters[filterKey] ?.map((filter) => filter.value.toString()) diff --git a/src/pages/Search/SearchTypeMenuNarrow.tsx b/src/pages/Search/SearchTypeMenuNarrow.tsx index d049e38bc436..0f0047a9e7d2 100644 --- a/src/pages/Search/SearchTypeMenuNarrow.tsx +++ b/src/pages/Search/SearchTypeMenuNarrow.tsx @@ -1,6 +1,7 @@ import React, {useCallback, useMemo, useRef, useState} from 'react'; import {Animated, View} from 'react-native'; import type {TextStyle, ViewStyle} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import Icon from '@components/Icon'; import type {MenuItemWithLink} from '@components/MenuItemList'; @@ -23,6 +24,7 @@ import * as SearchUtils from '@libs/SearchUtils'; import variables from '@styles/variables'; import * as Expensicons from '@src/components/Icon/Expensicons'; import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {SearchTypeMenuItem} from './SearchTypeMenu'; @@ -50,6 +52,9 @@ function SearchTypeMenuNarrow({typeMenuItems, activeItemIndex, queryJSON, title, const {translate} = useLocalize(); const {hash, policyID} = queryJSON; const {showDeleteModal, DeleteConfirmModal} = useDeleteSavedSearch(); + const [currencyList = {}] = useOnyx(ONYXKEYS.CURRENCY_LIST); + const [policyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES); + const [policyTagsLists] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS); const [isPopoverVisible, setIsPopoverVisible] = useState(false); const buttonRef = useRef(null); @@ -57,7 +62,7 @@ function SearchTypeMenuNarrow({typeMenuItems, activeItemIndex, queryJSON, title, const openMenu = useCallback(() => setIsPopoverVisible(true), []); const closeMenu = useCallback(() => setIsPopoverVisible(false), []); const onPress = () => { - const values = SearchUtils.buildFilterFormValuesFromQuery(queryJSON); + const values = SearchUtils.buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList); SearchActions.updateAdvancedFilters(values); Navigation.navigate(ROUTES.SEARCH_ADVANCED_FILTERS); }; From ac64d25e7f65fcf637313bc57a4045fdf205d79e Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Thu, 10 Oct 2024 18:35:43 +0200 Subject: [PATCH 13/14] add validation for all filters --- .../Search/SearchFiltersChatsSelector.tsx | 12 ++- src/components/Search/SearchPageHeader.tsx | 2 +- src/libs/SearchUtils.ts | 74 +++++++++++-------- .../SearchFiltersDatePage.tsx | 6 +- src/pages/Search/SearchTypeMenuNarrow.tsx | 8 +- 5 files changed, 59 insertions(+), 43 deletions(-) diff --git a/src/components/Search/SearchFiltersChatsSelector.tsx b/src/components/Search/SearchFiltersChatsSelector.tsx index e6e8e0085f17..36b56867b99f 100644 --- a/src/components/Search/SearchFiltersChatsSelector.tsx +++ b/src/components/Search/SearchFiltersChatsSelector.tsx @@ -54,13 +54,11 @@ function SearchFiltersChatsSelector({initialReportIDs, onFiltersUpdate, isScreen const cleanSearchTerm = useMemo(() => searchTerm.trim().toLowerCase(), [searchTerm]); const selectedOptions = useMemo(() => { - return selectedReportIDs - .filter((id) => reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`]) - .map((id) => { - const report = getSelectedOptionData(OptionsListUtils.createOptionFromReport({...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, personalDetails)); - const alternateText = OptionsListUtils.getAlternateText(report, {}); - return {...report, alternateText}; - }); + return selectedReportIDs.map((id) => { + const report = getSelectedOptionData(OptionsListUtils.createOptionFromReport({...reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`], reportID: id}, personalDetails)); + const alternateText = OptionsListUtils.getAlternateText(report, {}); + return {...report, alternateText}; + }); }, [personalDetails, reports, selectedReportIDs]); const defaultOptions = useMemo(() => { diff --git a/src/components/Search/SearchPageHeader.tsx b/src/components/Search/SearchPageHeader.tsx index 03aac7f4327e..ec43c9762239 100644 --- a/src/components/Search/SearchPageHeader.tsx +++ b/src/components/Search/SearchPageHeader.tsx @@ -327,7 +327,7 @@ function SearchPageHeader({queryJSON, hash}: SearchPageHeaderProps) { } const onPress = () => { - const filterFormValues = SearchUtils.buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList); + const filterFormValues = SearchUtils.buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList, personalDetails, cardList, reports, taxRates); SearchActions.updateAdvancedFilters(filterFormValues); Navigation.navigate(ROUTES.SEARCH_ADVANCED_FILTERS); diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index e94c4c441c8d..313ade0aa306 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -28,6 +28,7 @@ import * as ReportUtils from './ReportUtils'; import * as searchParser from './SearchParser/searchParser'; import * as TransactionUtils from './TransactionUtils'; import * as UserUtils from './UserUtils'; +import * as ValidationUtils from './ValidationUtils'; type FilterKeys = keyof typeof CONST.SEARCH.SYNTAX_FILTER_KEYS; @@ -663,47 +664,55 @@ function buildFilterFormValuesFromQuery( policyCategories: OnyxCollection, policyTags: OnyxCollection, currencyList: OnyxTypes.CurrencyList, + personalDetails: OnyxTypes.PersonalDetailsList, + cardList: OnyxTypes.CardList, + reports: OnyxCollection, + taxRates: Record, ) { - const filters = getFilters(queryJSON); + const filters = queryJSON.flatFilters; const filterKeys = Object.keys(filters); const filtersForm = {} as Partial; + const policyID = queryJSON.policyID; for (const filterKey of filterKeys) { if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_ID || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.DESCRIPTION) { filtersForm[filterKey] = filters[filterKey]?.[0]?.value.toString(); } - if ( - filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID || - filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE || - filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPENSE_TYPE || - filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || - filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO || - filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN - ) { - filtersForm[filterKey] = filters[filterKey]?.map((filter) => filter.value.toString()); + if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPENSE_TYPE) { + filtersForm[filterKey] = filters[filterKey] + ?.map((expenseType) => expenseType.value.toString()) + .filter((expenseType) => Object.values(CONST.SEARCH.TRANSACTION_TYPE).includes(expenseType as ValueOf)); + } + if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID) { + filtersForm[filterKey] = filters[filterKey]?.map((card) => card.value.toString()).filter((card) => Object.keys(cardList).includes(card)); + } + if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE) { + filtersForm[filterKey] = filters[filterKey]?.map((tax) => tax.value.toString()).filter((tax) => [...Object.values(taxRates)].flat().includes(tax)); + } + if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { + filtersForm[filterKey] = filters[filterKey]?.map((report) => report.value.toString()).filter((id) => reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`]); + } + if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO) { + filtersForm[filterKey] = filters[filterKey]?.map((id) => id.value.toString()).filter((id) => Object.keys(personalDetails).includes(id)); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY) { filtersForm[filterKey] = filters[filterKey]?.filter((currency) => Object.keys(currencyList).includes(currency.value.toString())).map((currency) => currency.value.toString()); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG) { - filtersForm[filterKey] = filters[filterKey] - ?.map((tag) => tag.value.toString()) - .filter((name) => - Object.values(policyTags ?? {}) - .map((tagList = {}) => getTagNamesFromTagsLists(tagList)) - .flat() - .includes(name), - ); + const tags = policyID + ? getTagNamesFromTagsLists(policyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {}) + : Object.values(policyTags ?? {}) + .filter((item) => !!item) + .map((tagList) => getTagNamesFromTagsLists(tagList ?? {})) + .flat(); + filtersForm[filterKey] = filters[filterKey]?.map((tag) => tag.value.toString()).filter((name) => tags.includes(name)); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY) { - filtersForm[filterKey] = - filters[filterKey] - ?.map((category) => category.value.toString()) - .filter((name) => - Object.values(policyCategories ?? {}) - .map((xd) => Object.values(xd ?? {}).map((category) => category.name)) - .flat() - .includes(name), - ) ?? []; + const categories = policyID + ? Object.values(policyCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`] ?? {}).map((category) => category.name) + : Object.values(policyCategories ?? {}) + .map((xd) => Object.values(xd ?? {}).map((category) => category.name)) + .flat(); + filtersForm[filterKey] = filters[filterKey]?.map((category) => category.value.toString()).filter((name) => categories.includes(name)); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD) { filtersForm[filterKey] = filters[filterKey] @@ -717,8 +726,8 @@ function buildFilterFormValuesFromQuery( .join(' '); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE) { - filtersForm[FILTER_KEYS.DATE_BEFORE] = filters[filterKey]?.find((filter) => filter.operator === 'lt' && DateUtils.isDate(filter.value))?.value.toString(); - filtersForm[FILTER_KEYS.DATE_AFTER] = filters[filterKey]?.find((filter) => filter.operator === 'gt' && DateUtils.isDate(filter.value))?.value.toString(); + filtersForm[FILTER_KEYS.DATE_BEFORE] = filters[filterKey]?.find((filter) => filter.operator === 'lt' && ValidationUtils.isValidDate(filter.value.toString()))?.value.toString(); + filtersForm[FILTER_KEYS.DATE_AFTER] = filters[filterKey]?.find((filter) => filter.operator === 'gt' && ValidationUtils.isValidDate(filter.value.toString()))?.value.toString(); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT) { filtersForm[FILTER_KEYS.LESS_THAN] = filters[filterKey]?.find((filter) => filter.operator === 'lt' && validateAmount(filter.value.toString(), 2))?.value.toString(); @@ -726,8 +735,11 @@ function buildFilterFormValuesFromQuery( } } - filtersForm[FILTER_KEYS.TYPE] = queryJSON.type; - filtersForm[FILTER_KEYS.STATUS] = queryJSON.status; + const [typeKey = '', typeValue] = Object.entries(CONST.SEARCH.DATA_TYPES).find(([, value]) => value === queryJSON.type) ?? []; + filtersForm[FILTER_KEYS.TYPE] = typeValue ? queryJSON.type : CONST.SEARCH.DATA_TYPES.EXPENSE; + const [statusKey] = Object.entries(CONST.SEARCH.STATUS).find(([, value]) => Object.values(value).includes(queryJSON.status)) ?? []; + filtersForm[FILTER_KEYS.STATUS] = typeKey === statusKey ? queryJSON.status : CONST.SEARCH.STATUS.EXPENSE.ALL; + if (queryJSON.policyID) { filtersForm[FILTER_KEYS.POLICY_ID] = queryJSON.policyID; } diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersDatePage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersDatePage.tsx index f50417c325e3..d4d068d4ba5f 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersDatePage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersDatePage.tsx @@ -1,3 +1,4 @@ +import {format} from 'date-fns'; import React from 'react'; import {useOnyx} from 'react-native-onyx'; import DatePicker from '@components/DatePicker'; @@ -9,7 +10,6 @@ import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import {updateAdvancedFilters} from '@libs/actions/Search'; -import DateUtils from '@libs/DateUtils'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -22,8 +22,8 @@ function SearchFiltersDatePage() { const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); - const dateAfter = DateUtils.isDate(searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_AFTER]) ? searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_AFTER] : undefined; - const dateBefore = DateUtils.isDate(searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_BEFORE]) ? searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_BEFORE] : undefined; + const dateAfter = searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_AFTER] ? format(searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_AFTER], 'yyyy-MM-dd') : undefined; + const dateBefore = searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_BEFORE] ? format(searchAdvancedFiltersForm?.[FILTER_KEYS.DATE_BEFORE], 'yyyy-MM-dd') : undefined; const updateDateFilter = (values: FormOnyxValues) => { updateAdvancedFilters(values); diff --git a/src/pages/Search/SearchTypeMenuNarrow.tsx b/src/pages/Search/SearchTypeMenuNarrow.tsx index 0f0047a9e7d2..0473c12c8482 100644 --- a/src/pages/Search/SearchTypeMenuNarrow.tsx +++ b/src/pages/Search/SearchTypeMenuNarrow.tsx @@ -5,6 +5,7 @@ import {useOnyx} from 'react-native-onyx'; import Button from '@components/Button'; import Icon from '@components/Icon'; import type {MenuItemWithLink} from '@components/MenuItemList'; +import {usePersonalDetails} from '@components/OnyxProvider'; import PopoverMenu from '@components/PopoverMenu'; import type {PopoverMenuItem} from '@components/PopoverMenu'; import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; @@ -20,6 +21,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import * as SearchActions from '@libs/actions/Search'; import Navigation from '@libs/Navigation/Navigation'; +import {getAllTaxRates} from '@libs/PolicyUtils'; import * as SearchUtils from '@libs/SearchUtils'; import variables from '@styles/variables'; import * as Expensicons from '@src/components/Icon/Expensicons'; @@ -55,6 +57,10 @@ function SearchTypeMenuNarrow({typeMenuItems, activeItemIndex, queryJSON, title, const [currencyList = {}] = useOnyx(ONYXKEYS.CURRENCY_LIST); const [policyCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES); const [policyTagsLists] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS); + const personalDetails = usePersonalDetails(); + const [reports = {}] = useOnyx(ONYXKEYS.COLLECTION.REPORT); + const taxRates = getAllTaxRates(); + const [cardList = {}] = useOnyx(ONYXKEYS.CARD_LIST); const [isPopoverVisible, setIsPopoverVisible] = useState(false); const buttonRef = useRef(null); @@ -62,7 +68,7 @@ function SearchTypeMenuNarrow({typeMenuItems, activeItemIndex, queryJSON, title, const openMenu = useCallback(() => setIsPopoverVisible(true), []); const closeMenu = useCallback(() => setIsPopoverVisible(false), []); const onPress = () => { - const values = SearchUtils.buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList); + const values = SearchUtils.buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList, personalDetails, cardList, reports, taxRates); SearchActions.updateAdvancedFilters(values); Navigation.navigate(ROUTES.SEARCH_ADVANCED_FILTERS); }; From 5201fce63c5be3dd3ea1168edf42d0eab81f6b1b Mon Sep 17 00:00:00 2001 From: 289Adam289 Date: Fri, 11 Oct 2024 09:31:32 +0200 Subject: [PATCH 14/14] fix display value --- src/libs/SearchUtils.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 313ade0aa306..ef9f237bd551 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -769,10 +769,12 @@ function getPolicyIDFromSearchQuery(queryJSON: SearchQueryJSON) { function getDisplayValue(filterName: string, filter: string, personalDetails: OnyxTypes.PersonalDetailsList, cardList: OnyxTypes.CardList, reports: OnyxCollection) { if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO) { - return personalDetails?.[filter]?.login ?? filter; + // login can be an empty string + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + return personalDetails?.[filter]?.login || filter; } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID) { - return cardList[filter]?.bank ?? filter; + return cardList[filter]?.bank || filter; } if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { return ReportUtils.getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filter}`]) || filter;