From 9fc08a5736fb423b6c78dbd8f462cedbe1322f20 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 2 Oct 2024 17:58:36 -0600 Subject: [PATCH 01/18] add no operator --- src/libs/SearchParser/searchParser.js | 107 +++++++++++++---------- src/libs/SearchParser/searchParser.peggy | 1 + 2 files changed, 60 insertions(+), 48 deletions(-) diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js index 622c3f5f3c4a..f461394076b9 100644 --- a/src/libs/SearchParser/searchParser.js +++ b/src/libs/SearchParser/searchParser.js @@ -200,12 +200,13 @@ function peg$parse(input, options) { var peg$c17 = "cardID"; var peg$c18 = "from"; var peg$c19 = "expenseType"; - var peg$c20 = "type"; - var peg$c21 = "status"; - var peg$c22 = "sortBy"; - var peg$c23 = "sortOrder"; - var peg$c24 = "policyID"; - var peg$c25 = "\""; + var peg$c20 = "no"; + var peg$c21 = "type"; + var peg$c22 = "status"; + var peg$c23 = "sortBy"; + var peg$c24 = "sortOrder"; + var peg$c25 = "policyID"; + var peg$c26 = "\""; var peg$r0 = /^[:=]/; var peg$r1 = /^[^"\r\n]/; @@ -235,19 +236,20 @@ function peg$parse(input, options) { var peg$e20 = peg$literalExpectation("cardID", false); var peg$e21 = peg$literalExpectation("from", false); var peg$e22 = peg$literalExpectation("expenseType", false); - var peg$e23 = peg$otherExpectation("default key"); - var peg$e24 = peg$literalExpectation("type", false); - var peg$e25 = peg$literalExpectation("status", false); - var peg$e26 = peg$literalExpectation("sortBy", false); - var peg$e27 = peg$literalExpectation("sortOrder", false); - var peg$e28 = peg$literalExpectation("policyID", false); - var peg$e29 = peg$otherExpectation("quote"); - var peg$e30 = peg$literalExpectation("\"", false); - var peg$e31 = peg$classExpectation(["\"", "\r", "\n"], true, false); - var peg$e32 = peg$otherExpectation("word"); - var peg$e33 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_", "@", ".", "/", "#", "&", "+", "-", "\\", "'", ",", ";"], false, false); - var peg$e34 = peg$otherExpectation("whitespace"); - var peg$e35 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); + var peg$e23 = peg$literalExpectation("no", false); + var peg$e24 = peg$otherExpectation("default key"); + var peg$e25 = peg$literalExpectation("type", false); + var peg$e26 = peg$literalExpectation("status", false); + var peg$e27 = peg$literalExpectation("sortBy", false); + var peg$e28 = peg$literalExpectation("sortOrder", false); + var peg$e29 = peg$literalExpectation("policyID", false); + var peg$e30 = peg$otherExpectation("quote"); + var peg$e31 = peg$literalExpectation("\"", false); + var peg$e32 = peg$classExpectation(["\"", "\r", "\n"], true, false); + var peg$e33 = peg$otherExpectation("word"); + var peg$e34 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_", "@", ".", "/", "#", "&", "+", "-", "\\", "'", ",", ";"], false, false); + var peg$e35 = peg$otherExpectation("whitespace"); + var peg$e36 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); var peg$f0 = function(filters) { return applyDefaults(filters); }; var peg$f1 = function(head, tail) { @@ -856,6 +858,15 @@ function peg$parse(input, options) { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e14); } } + if (s1 === peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c20) { + s1 = peg$c20; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e23); } + } + } } } } @@ -891,44 +902,44 @@ function peg$parse(input, options) { peg$silentFails++; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c20) { - s1 = peg$c20; + if (input.substr(peg$currPos, 4) === peg$c21) { + s1 = peg$c21; peg$currPos += 4; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e24); } + if (peg$silentFails === 0) { peg$fail(peg$e25); } } if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 6) === peg$c21) { - s1 = peg$c21; + if (input.substr(peg$currPos, 6) === peg$c22) { + s1 = peg$c22; peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e25); } + if (peg$silentFails === 0) { peg$fail(peg$e26); } } if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 6) === peg$c22) { - s1 = peg$c22; + if (input.substr(peg$currPos, 6) === peg$c23) { + s1 = peg$c23; peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e26); } + if (peg$silentFails === 0) { peg$fail(peg$e27); } } if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 9) === peg$c23) { - s1 = peg$c23; + if (input.substr(peg$currPos, 9) === peg$c24) { + s1 = peg$c24; peg$currPos += 9; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e27); } + if (peg$silentFails === 0) { peg$fail(peg$e28); } } if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 8) === peg$c24) { - s1 = peg$c24; + if (input.substr(peg$currPos, 8) === peg$c25) { + s1 = peg$c25; peg$currPos += 8; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e28); } + if (peg$silentFails === 0) { peg$fail(peg$e29); } } } } @@ -943,7 +954,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e23); } + if (peg$silentFails === 0) { peg$fail(peg$e24); } } return s0; @@ -984,11 +995,11 @@ function peg$parse(input, options) { peg$silentFails++; s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c25; + s1 = peg$c26; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e30); } + if (peg$silentFails === 0) { peg$fail(peg$e31); } } if (s1 !== peg$FAILED) { s2 = []; @@ -997,7 +1008,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e31); } + if (peg$silentFails === 0) { peg$fail(peg$e32); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -1006,15 +1017,15 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e31); } + if (peg$silentFails === 0) { peg$fail(peg$e32); } } } if (input.charCodeAt(peg$currPos) === 34) { - s3 = peg$c25; + s3 = peg$c26; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e30); } + if (peg$silentFails === 0) { peg$fail(peg$e31); } } if (s3 !== peg$FAILED) { peg$savedPos = s0; @@ -1030,7 +1041,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e29); } + if (peg$silentFails === 0) { peg$fail(peg$e30); } } return s0; @@ -1047,7 +1058,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e33); } + if (peg$silentFails === 0) { peg$fail(peg$e34); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { @@ -1057,7 +1068,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e33); } + if (peg$silentFails === 0) { peg$fail(peg$e34); } } } } else { @@ -1071,7 +1082,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e32); } + if (peg$silentFails === 0) { peg$fail(peg$e33); } } return s0; @@ -1099,7 +1110,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e35); } + if (peg$silentFails === 0) { peg$fail(peg$e36); } } while (s1 !== peg$FAILED) { s0.push(s1); @@ -1108,12 +1119,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e35); } + if (peg$silentFails === 0) { peg$fail(peg$e36); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e34); } + if (peg$silentFails === 0) { peg$fail(peg$e35); } return s0; } diff --git a/src/libs/SearchParser/searchParser.peggy b/src/libs/SearchParser/searchParser.peggy index f9f681736c61..028f2aad8bd0 100644 --- a/src/libs/SearchParser/searchParser.peggy +++ b/src/libs/SearchParser/searchParser.peggy @@ -120,6 +120,7 @@ key "key" / "from" / "expenseType" / "in" + / "no" ) defaultKey "default key" From be73b227389e18af0cedb69a336ce553889c3567 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 3 Oct 2024 10:15:30 -0600 Subject: [PATCH 02/18] add no operator --- src/libs/SearchUtils.ts | 3 ++- .../SearchFiltersCategoryPage.tsx | 12 +++++++++--- src/types/form/SearchAdvancedFiltersForm.ts | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 47cee2c7c2b4..6523423cff28 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -602,7 +602,7 @@ function buildQueryStringFromFilterFormValues(filterValues: Partial { if ((filterKey === FILTER_KEYS.MERCHANT || filterKey === FILTER_KEYS.DESCRIPTION || filterKey === FILTER_KEYS.REPORT_ID) && filterValue) { @@ -626,6 +626,7 @@ function buildQueryStringFromFilterFormValues(filterValues: Partial 0 diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx index 1e37cdc60296..315e336be743 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx @@ -26,12 +26,18 @@ function SearchFiltersCategoryPage() { if (!singlePolicyCategories) { const uniqueCategoryNames = new Set(); Object.values(allPolicyIDCategories ?? {}).map((policyCategories) => Object.values(policyCategories ?? {}).forEach((category) => uniqueCategoryNames.add(category.name))); - return Array.from(uniqueCategoryNames).map((categoryName) => ({name: categoryName, value: categoryName})); + return [{name: 'No category', value: 'no:category'}, ...Array.from(uniqueCategoryNames).map((categoryName) => ({name: categoryName, value: categoryName}))]; } - return Object.values(singlePolicyCategories ?? {}).map((category) => ({name: category.name, value: category.name})); + return [{name: 'No category', value: 'no:category'}, ...Object.values(singlePolicyCategories ?? {}).map((category) => ({name: category.name, value: category.name}))]; }, [allPolicyIDCategories, singlePolicyCategories]); - const onSaveSelection = useCallback((values: string[]) => SearchActions.updateAdvancedFilters({category: values}), []); + const onSaveSelection = useCallback((values: string[]) => { + if (values.at(0) === 'no:category') { + SearchActions.updateAdvancedFilters({no: ['category']}); + return; + } + SearchActions.updateAdvancedFilters({category: values}); + }, []); const safePaddingBottomStyle = useSafePaddingBottomStyle(); return ( diff --git a/src/types/form/SearchAdvancedFiltersForm.ts b/src/types/form/SearchAdvancedFiltersForm.ts index a70e58d48a19..c5c55fd4c407 100644 --- a/src/types/form/SearchAdvancedFiltersForm.ts +++ b/src/types/form/SearchAdvancedFiltersForm.ts @@ -22,6 +22,7 @@ const FILTER_KEYS = { FROM: 'from', TO: 'to', IN: 'in', + NO: 'no', } as const; type InputID = ValueOf; @@ -49,6 +50,7 @@ type SearchAdvancedFiltersForm = Form< [FILTER_KEYS.FROM]: string[]; [FILTER_KEYS.TO]: string[]; [FILTER_KEYS.IN]: string[]; + [FILTER_KEYS.NO]: string[]; } >; From d1a83388fa4259497e15f08c201b55c3f39dc54b Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 3 Oct 2024 10:57:41 -0600 Subject: [PATCH 03/18] add no as a valid filter --- src/CONST.ts | 1 + src/libs/SearchUtils.ts | 2 +- src/pages/Search/AdvancedSearchFilters.tsx | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 2af183d9d751..1d8e3382643e 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -5586,6 +5586,7 @@ const CONST = { REPORT_ID: 'reportID', KEYWORD: 'keyword', IN: 'in', + NO: 'no', }, }, diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index 6523423cff28..f372ae71c814 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -602,7 +602,7 @@ function buildQueryStringFromFilterFormValues(filterValues: Partial { if ((filterKey === FILTER_KEYS.MERCHANT || filterKey === FILTER_KEYS.DESCRIPTION || filterKey === FILTER_KEYS.REPORT_ID) && filterValue) { diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 7009764629ba..b3e43a050d91 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -235,7 +235,6 @@ function AdvancedSearchFilters() { const queryString = useMemo(() => SearchUtils.buildQueryStringFromFilterFormValues(searchAdvancedFilters), [searchAdvancedFilters]); const queryJSON = useMemo(() => SearchUtils.buildSearchQueryJSON(queryString || SearchUtils.buildCannedSearchQuery()), [queryString]); - const applyFiltersAndNavigate = () => { SearchActions.clearAllFilters(); Navigation.dismissModal(); From f353d36450b6c5ee8005b25496afa158f03ee322 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 3 Oct 2024 11:05:41 -0600 Subject: [PATCH 04/18] add comments --- src/ROUTES.ts | 3 +++ src/pages/Search/AdvancedSearchFilters.tsx | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 9c429dd3e909..56815acd0b88 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -57,6 +57,9 @@ const ROUTES = { SEARCH_ADVANCED_FILTERS_FROM: 'search/filters/from', SEARCH_ADVANCED_FILTERS_TO: 'search/filters/to', SEARCH_ADVANCED_FILTERS_IN: 'search/filters/in', + + // The 'no' filter is a special case because it's a modifier built into other filters, e.g. categories and tags so it doesn't have it's own page + SEARCH_ADVANCED_FILTERS_NO: 'search/filters/', SEARCH_REPORT: { route: 'search/view/:reportID/:reportActionID?', getRoute: ({reportID, reportActionID, backTo}: {reportID: string; reportActionID?: string; backTo?: string}) => { diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index b3e43a050d91..fb8f73645985 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -105,6 +105,13 @@ const baseFilterConfig = { description: 'common.in' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_IN, }, + + // The no filter is just a modifier for other filters, e.g. categories and tags so it does't have its own page + no: { + getTitle: () => {}, + description: 'common.no' as const, + route: ROUTES.SEARCH_ADVANCED_FILTERS_NO, + }, }; const typeFiltersKeys: Record>> = { From 524a0ee2a337eff66b6e4e60ea4c5ee9fabf4b17 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 3 Oct 2024 11:28:09 -0600 Subject: [PATCH 05/18] display selection on filters page --- src/pages/Search/AdvancedSearchFilters.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index fb8f73645985..569987ddec10 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -108,7 +108,6 @@ const baseFilterConfig = { // The no filter is just a modifier for other filters, e.g. categories and tags so it does't have its own page no: { - getTitle: () => {}, description: 'common.no' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_NO, }, @@ -181,6 +180,12 @@ function getFilterDisplayTitle(filters: Partial, fiel return; } + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY && filters['no']) { + return 'No category'; + } + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG && filters['no']) { + return 'No tag'; + } if ( (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY || fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY || fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG) && filters[fieldName] From c9a845173d0c57d93539acc83cc2c24352a35681 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 3 Oct 2024 11:39:48 -0600 Subject: [PATCH 06/18] use consts --- src/CONST.ts | 4 ++++ src/languages/en.ts | 2 ++ src/languages/es.ts | 2 ++ src/pages/Search/AdvancedSearchFilters.tsx | 10 ++++++---- .../SearchFiltersCategoryPage.tsx | 17 ++++++++++++----- 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 1d8e3382643e..db6e03910944 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -5588,6 +5588,10 @@ const CONST = { IN: 'in', NO: 'no', }, + FILTER_NO: { + CATEGORY: 'no:category', + TAG: 'no:tag', + }, }, REFERRER: { diff --git a/src/languages/en.ts b/src/languages/en.ts index f15e5c97d037..58ab6a4e9e4c 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4146,6 +4146,8 @@ const translations = { }, current: 'Current', past: 'Past', + noCategory: 'No category', + noTag: 'No tag', }, expenseType: 'Expense type', recentSearches: 'Recent searches', diff --git a/src/languages/es.ts b/src/languages/es.ts index 413084aa8286..16af936180dc 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4190,6 +4190,8 @@ const translations = { }, current: 'Actual', past: 'Anterior', + noCategory: 'Sin categoría', + noTag: 'Sin etiqueta', }, expenseType: 'Tipo de gasto', recentSearches: 'Búsquedas recientes', diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 569987ddec10..b1e3e389b797 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -180,12 +180,14 @@ function getFilterDisplayTitle(filters: Partial, fiel return; } - if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY && filters['no']) { - return 'No category'; + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY && filters[CONST.SEARCH.SYNTAX_FILTER_KEYS.NO]) { + return translate('search.filters.noCategory'); } - if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG && filters['no']) { - return 'No tag'; + + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG && filters[CONST.SEARCH.SYNTAX_FILTER_KEYS.NO]) { + return translate('search.filters.noTag'); } + if ( (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY || fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY || fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG) && filters[fieldName] diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx index 315e336be743..ae22990f36a0 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx @@ -9,6 +9,7 @@ import useSafePaddingBottomStyle from '@hooks/useSafePaddingBottomStyle'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as SearchActions from '@userActions/Search'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -26,14 +27,20 @@ function SearchFiltersCategoryPage() { if (!singlePolicyCategories) { const uniqueCategoryNames = new Set(); Object.values(allPolicyIDCategories ?? {}).map((policyCategories) => Object.values(policyCategories ?? {}).forEach((category) => uniqueCategoryNames.add(category.name))); - return [{name: 'No category', value: 'no:category'}, ...Array.from(uniqueCategoryNames).map((categoryName) => ({name: categoryName, value: categoryName}))]; + return [ + {name: translate('search.filters.noCategory'), value: CONST.SEARCH.FILTER_NO.CATEGORY}, + ...Array.from(uniqueCategoryNames).map((categoryName) => ({name: categoryName, value: categoryName})), + ]; } - return [{name: 'No category', value: 'no:category'}, ...Object.values(singlePolicyCategories ?? {}).map((category) => ({name: category.name, value: category.name}))]; - }, [allPolicyIDCategories, singlePolicyCategories]); + return [ + {name: translate('search.filters.noCategory'), value: CONST.SEARCH.FILTER_NO.CATEGORY}, + ...Object.values(singlePolicyCategories ?? {}).map((category) => ({name: category.name, value: category.name})), + ]; + }, [allPolicyIDCategories, singlePolicyCategories, translate]); const onSaveSelection = useCallback((values: string[]) => { - if (values.at(0) === 'no:category') { - SearchActions.updateAdvancedFilters({no: ['category']}); + if (values.at(0) === CONST.SEARCH.FILTER_NO.CATEGORY) { + SearchActions.updateAdvancedFilters({no: [CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY]}); return; } SearchActions.updateAdvancedFilters({category: values}); From 8bf7a494d455afc06c328c060835e38b629aaf36 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 3 Oct 2024 12:20:07 -0600 Subject: [PATCH 07/18] add new section --- .../Search/SearchMultipleSelectionPicker.tsx | 6 ++++++ .../SearchFiltersCategoryPage.tsx | 12 +++--------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/Search/SearchMultipleSelectionPicker.tsx b/src/components/Search/SearchMultipleSelectionPicker.tsx index 558b89715b61..a363a90591ec 100644 --- a/src/components/Search/SearchMultipleSelectionPicker.tsx +++ b/src/components/Search/SearchMultipleSelectionPicker.tsx @@ -52,10 +52,16 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit value: item.value, })); const isEmpty = !selectedItemsSection.length && !remainingItemsSection.length; + console.log('over here', selectedItemsSection) return { sections: isEmpty ? [] : [ + { + title: undefined, + data: [{text: 'No category', keyForList: 'No category', value: 'no:category', isSelected: false}], + shouldShow: selectedItemsSection.length === 0, + }, { title: undefined, data: selectedItemsSection, diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx index ae22990f36a0..0bf0f83d4df7 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx @@ -27,16 +27,10 @@ function SearchFiltersCategoryPage() { if (!singlePolicyCategories) { const uniqueCategoryNames = new Set(); Object.values(allPolicyIDCategories ?? {}).map((policyCategories) => Object.values(policyCategories ?? {}).forEach((category) => uniqueCategoryNames.add(category.name))); - return [ - {name: translate('search.filters.noCategory'), value: CONST.SEARCH.FILTER_NO.CATEGORY}, - ...Array.from(uniqueCategoryNames).map((categoryName) => ({name: categoryName, value: categoryName})), - ]; + return Array.from(uniqueCategoryNames).map((categoryName) => ({name: categoryName, value: categoryName})); } - return [ - {name: translate('search.filters.noCategory'), value: CONST.SEARCH.FILTER_NO.CATEGORY}, - ...Object.values(singlePolicyCategories ?? {}).map((category) => ({name: category.name, value: category.name})), - ]; - }, [allPolicyIDCategories, singlePolicyCategories, translate]); + return Object.values(singlePolicyCategories ?? {}).map((category) => ({name: category.name, value: category.name})); + }, [allPolicyIDCategories, singlePolicyCategories]); const onSaveSelection = useCallback((values: string[]) => { if (values.at(0) === CONST.SEARCH.FILTER_NO.CATEGORY) { From bf6fe38559f96e7c52fe5f86ff449ae70d4bbae9 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 10 Oct 2024 12:21:21 -0600 Subject: [PATCH 08/18] move option to list --- .../Search/SearchMultipleSelectionPicker.tsx | 19 +++++++++++-------- .../SearchFiltersCategoryPage.tsx | 7 +++++-- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/components/Search/SearchMultipleSelectionPicker.tsx b/src/components/Search/SearchMultipleSelectionPicker.tsx index a363a90591ec..68fa0b72ed09 100644 --- a/src/components/Search/SearchMultipleSelectionPicker.tsx +++ b/src/components/Search/SearchMultipleSelectionPicker.tsx @@ -7,6 +7,7 @@ import useLocalize from '@hooks/useLocalize'; import localeCompare from '@libs/LocaleCompare'; import Navigation from '@libs/Navigation/Navigation'; import type {OptionData} from '@libs/ReportUtils'; +import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; type SearchMultipleSelectionPickerItem = { @@ -28,6 +29,14 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const [selectedItems, setSelectedItems] = useState(initiallySelectedItems ?? []); + const sortOptions = (a: SearchMultipleSelectionPickerItem, b: SearchMultipleSelectionPickerItem) => { + const filterNoValues = Object.values(CONST.SEARCH.FILTER_NO) as string[]; + if (filterNoValues.includes(a.value) || filterNoValues.includes(b.value)) { + return 1; + } + return localeCompare(a.name, b.name); + }; + useEffect(() => { setSelectedItems(initiallySelectedItems ?? []); }, [initiallySelectedItems]); @@ -35,7 +44,7 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit const {sections, noResultsFound} = useMemo(() => { const selectedItemsSection = selectedItems .filter((item) => item?.name.toLowerCase().includes(debouncedSearchTerm?.toLowerCase())) - .sort((a, b) => localeCompare(a.name, b.name)) + .sort((a, b) => sortOptions(a, b)) .map((item) => ({ text: item.name, keyForList: item.name, @@ -44,7 +53,7 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit })); const remainingItemsSection = items .filter((item) => selectedItems.some((selectedItem) => selectedItem.value === item.value) === false && item?.name.toLowerCase().includes(debouncedSearchTerm?.toLowerCase())) - .sort((a, b) => localeCompare(a.name, b.name)) + .sort((a, b) => sortOptions(a, b)) .map((item) => ({ text: item.name, keyForList: item.name, @@ -52,16 +61,10 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit value: item.value, })); const isEmpty = !selectedItemsSection.length && !remainingItemsSection.length; - console.log('over here', selectedItemsSection) return { sections: isEmpty ? [] : [ - { - title: undefined, - data: [{text: 'No category', keyForList: 'No category', value: 'no:category', isSelected: false}], - shouldShow: selectedItemsSection.length === 0, - }, { title: undefined, data: selectedItemsSection, diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx index 0bf0f83d4df7..2a0139934448 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx @@ -24,12 +24,15 @@ function SearchFiltersCategoryPage() { const singlePolicyCategories = allPolicyIDCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]; const categoryItems = useMemo(() => { + const items = [{name: 'No category', value: 'no:category'}]; if (!singlePolicyCategories) { const uniqueCategoryNames = new Set(); Object.values(allPolicyIDCategories ?? {}).map((policyCategories) => Object.values(policyCategories ?? {}).forEach((category) => uniqueCategoryNames.add(category.name))); - return Array.from(uniqueCategoryNames).map((categoryName) => ({name: categoryName, value: categoryName})); + items.push(...Array.from(uniqueCategoryNames).map((categoryName) => ({name: categoryName, value: categoryName}))); + } else { + items.push(...Object.values(singlePolicyCategories ?? {}).map((category) => ({name: category.name, value: category.name}))); } - return Object.values(singlePolicyCategories ?? {}).map((category) => ({name: category.name, value: category.name})); + return items; }, [allPolicyIDCategories, singlePolicyCategories]); const onSaveSelection = useCallback((values: string[]) => { From 4c1bffca8238b5c8861d699de4e7d2802a3a895f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 10 Oct 2024 12:27:08 -0600 Subject: [PATCH 09/18] fix ts --- src/components/Search/SearchMultipleSelectionPicker.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Search/SearchMultipleSelectionPicker.tsx b/src/components/Search/SearchMultipleSelectionPicker.tsx index 68fa0b72ed09..da2e2dfc2cc6 100644 --- a/src/components/Search/SearchMultipleSelectionPicker.tsx +++ b/src/components/Search/SearchMultipleSelectionPicker.tsx @@ -12,7 +12,7 @@ import ROUTES from '@src/ROUTES'; type SearchMultipleSelectionPickerItem = { name: string; - value: string | string[]; + value: string; }; type SearchMultipleSelectionPickerProps = { From 7b08ff4f36584f2b88e1934c09d15ef248b004f2 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 10 Oct 2024 12:38:52 -0600 Subject: [PATCH 10/18] use const, apply logic to tags --- .../SearchFiltersCategoryPage.tsx | 4 ++-- .../SearchFiltersTagPage.tsx | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx index 2a0139934448..b9b74605a744 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx @@ -24,7 +24,7 @@ function SearchFiltersCategoryPage() { const singlePolicyCategories = allPolicyIDCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]; const categoryItems = useMemo(() => { - const items = [{name: 'No category', value: 'no:category'}]; + const items = [{name: translate('search.filters.noCategory'), value: CONST.SEARCH.FILTER_NO.CATEGORY as string}]; if (!singlePolicyCategories) { const uniqueCategoryNames = new Set(); Object.values(allPolicyIDCategories ?? {}).map((policyCategories) => Object.values(policyCategories ?? {}).forEach((category) => uniqueCategoryNames.add(category.name))); @@ -33,7 +33,7 @@ function SearchFiltersCategoryPage() { items.push(...Object.values(singlePolicyCategories ?? {}).map((category) => ({name: category.name, value: category.name}))); } return items; - }, [allPolicyIDCategories, singlePolicyCategories]); + }, [allPolicyIDCategories, singlePolicyCategories, translate]); const onSaveSelection = useCallback((values: string[]) => { if (values.at(0) === CONST.SEARCH.FILTER_NO.CATEGORY) { diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx index d0b0b2e234f7..971b233e87eb 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx @@ -9,6 +9,7 @@ import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import {getTagNamesFromTagsLists} from '@libs/PolicyUtils'; import * as SearchActions from '@userActions/Search'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type {PolicyTagLists} from '@src/types/onyx'; @@ -24,6 +25,7 @@ function SearchFiltersTagPage() { const singlePolicyTagsList: PolicyTagLists | undefined = allPoliciesTagsLists?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`]; const tagItems = useMemo(() => { + const items = [{name: translate('search.filters.noTag'), value: CONST.SEARCH.FILTER_NO.TAG as string}]; if (!singlePolicyTagsList) { const uniqueTagNames = new Set(); const tagListsUnpacked = Object.values(allPoliciesTagsLists ?? {}).filter((item) => !!item) as PolicyTagLists[]; @@ -33,12 +35,19 @@ function SearchFiltersTagPage() { }) .flat() .forEach((tag) => uniqueTagNames.add(tag)); - return Array.from(uniqueTagNames).map((tagName) => ({name: tagName, value: tagName})); + items.push(...Array.from(uniqueTagNames).map((tagName) => ({name: tagName, value: tagName}))); + } else { + items.push(...getTagNamesFromTagsLists(singlePolicyTagsList).map((name) => ({name, value: name}))); } - return getTagNamesFromTagsLists(singlePolicyTagsList).map((name) => ({name, value: name})); - }, [allPoliciesTagsLists, singlePolicyTagsList]); + return items; + }, [allPoliciesTagsLists, singlePolicyTagsList, translate]); - const updateTagFilter = useCallback((values: string[]) => SearchActions.updateAdvancedFilters({tag: values}), []); + const updateTagFilter = useCallback((values: string[]) => { + if (values.at(0) === CONST.SEARCH.FILTER_NO.TAG) { + SearchActions.updateAdvancedFilters({no: [CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG]}); + } + SearchActions.updateAdvancedFilters({tag: values}); + }, []); return ( Date: Thu, 10 Oct 2024 12:46:39 -0600 Subject: [PATCH 11/18] fix route, types --- src/ROUTES.ts | 4 +--- src/pages/Search/AdvancedSearchFilters.tsx | 7 +++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 795ca3d96ac9..371fb2b96529 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -57,9 +57,7 @@ const ROUTES = { SEARCH_ADVANCED_FILTERS_FROM: 'search/filters/from', SEARCH_ADVANCED_FILTERS_TO: 'search/filters/to', SEARCH_ADVANCED_FILTERS_IN: 'search/filters/in', - - // The 'no' filter is a special case because it's a modifier built into other filters, e.g. categories and tags so it doesn't have it's own page - SEARCH_ADVANCED_FILTERS_NO: 'search/filters/', + SEARCH_ADVANCED_FILTERS_NO: 'search/filters/no', SEARCH_REPORT: { route: 'search/view/:reportID/:reportActionID?', getRoute: ({reportID, reportActionID, backTo}: {reportID: string; reportActionID?: string; backTo?: string}) => { diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index b1e3e389b797..b7a3fe3ab66f 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -105,9 +105,8 @@ const baseFilterConfig = { description: 'common.in' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_IN, }, - - // The no filter is just a modifier for other filters, e.g. categories and tags so it does't have its own page no: { + getTitle: getFilterInDisplayTitle, description: 'common.no' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_NO, }, @@ -145,6 +144,10 @@ function getFilterParticipantDisplayTitle(accountIDs: string[], personalDetails: } function getFilterDisplayTitle(filters: Partial, fieldName: AdvancedFiltersKeys, translate: LocaleContextProps['translate']) { + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.NO) { + return ''; + } + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE) { // the value of date filter is a combination of dateBefore + dateAfter values const {dateAfter, dateBefore} = filters; From 29e01cd088958d66b6c9acbf787d928dcd4886aa Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 10 Oct 2024 14:40:26 -0600 Subject: [PATCH 12/18] revert changes, add entry to list --- src/CONST.ts | 6 +- src/ROUTES.ts | 1 - .../Search/SearchMultipleSelectionPicker.tsx | 6 +- src/libs/SearchParser/searchParser.js | 107 ++++++++---------- src/libs/SearchParser/searchParser.peggy | 1 - src/libs/SearchUtils.ts | 1 - src/pages/Search/AdvancedSearchFilters.tsx | 18 +-- .../SearchFiltersCategoryPage.tsx | 10 +- .../SearchFiltersTagPage.tsx | 9 +- src/types/form/SearchAdvancedFiltersForm.ts | 2 - 10 files changed, 57 insertions(+), 104 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index 4008067b55f7..d058fda641b3 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -5609,12 +5609,8 @@ const CONST = { REPORT_ID: 'reportID', KEYWORD: 'keyword', IN: 'in', - NO: 'no', - }, - FILTER_NO: { - CATEGORY: 'no:category', - TAG: 'no:tag', }, + VALUE_NONE: 'none', }, REFERRER: { diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 371fb2b96529..47fabe3c421c 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -57,7 +57,6 @@ const ROUTES = { SEARCH_ADVANCED_FILTERS_FROM: 'search/filters/from', SEARCH_ADVANCED_FILTERS_TO: 'search/filters/to', SEARCH_ADVANCED_FILTERS_IN: 'search/filters/in', - SEARCH_ADVANCED_FILTERS_NO: 'search/filters/no', SEARCH_REPORT: { route: 'search/view/:reportID/:reportActionID?', getRoute: ({reportID, reportActionID, backTo}: {reportID: string; reportActionID?: string; backTo?: string}) => { diff --git a/src/components/Search/SearchMultipleSelectionPicker.tsx b/src/components/Search/SearchMultipleSelectionPicker.tsx index da2e2dfc2cc6..8e733da24b0f 100644 --- a/src/components/Search/SearchMultipleSelectionPicker.tsx +++ b/src/components/Search/SearchMultipleSelectionPicker.tsx @@ -12,7 +12,7 @@ import ROUTES from '@src/ROUTES'; type SearchMultipleSelectionPickerItem = { name: string; - value: string; + value: string | string[]; }; type SearchMultipleSelectionPickerProps = { @@ -30,8 +30,8 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit const [selectedItems, setSelectedItems] = useState(initiallySelectedItems ?? []); const sortOptions = (a: SearchMultipleSelectionPickerItem, b: SearchMultipleSelectionPickerItem) => { - const filterNoValues = Object.values(CONST.SEARCH.FILTER_NO) as string[]; - if (filterNoValues.includes(a.value) || filterNoValues.includes(b.value)) { + // Always show `No category` and `No tag` as the first option + if (a.value === CONST.SEARCH.VALUE_NONE || b.value === CONST.SEARCH.VALUE_NONE) { return 1; } return localeCompare(a.name, b.name); diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js index e8f0dc388eb9..713996d0cf09 100644 --- a/src/libs/SearchParser/searchParser.js +++ b/src/libs/SearchParser/searchParser.js @@ -200,13 +200,12 @@ function peg$parse(input, options) { var peg$c17 = "cardID"; var peg$c18 = "from"; var peg$c19 = "expenseType"; - var peg$c20 = "no"; - var peg$c21 = "type"; - var peg$c22 = "status"; - var peg$c23 = "sortBy"; - var peg$c24 = "sortOrder"; - var peg$c25 = "policyID"; - var peg$c26 = "\""; + var peg$c20 = "type"; + var peg$c21 = "status"; + var peg$c22 = "sortBy"; + var peg$c23 = "sortOrder"; + var peg$c24 = "policyID"; + var peg$c25 = "\""; var peg$r0 = /^[:=]/; var peg$r1 = /^[^"\r\n]/; @@ -236,20 +235,19 @@ function peg$parse(input, options) { var peg$e20 = peg$literalExpectation("cardID", false); var peg$e21 = peg$literalExpectation("from", false); var peg$e22 = peg$literalExpectation("expenseType", false); - var peg$e23 = peg$literalExpectation("no", false); - var peg$e24 = peg$otherExpectation("default key"); - var peg$e25 = peg$literalExpectation("type", false); - var peg$e26 = peg$literalExpectation("status", false); - var peg$e27 = peg$literalExpectation("sortBy", false); - var peg$e28 = peg$literalExpectation("sortOrder", false); - var peg$e29 = peg$literalExpectation("policyID", false); - var peg$e30 = peg$otherExpectation("quote"); - var peg$e31 = peg$literalExpectation("\"", false); - var peg$e32 = peg$classExpectation(["\"", "\r", "\n"], true, false); - var peg$e33 = peg$otherExpectation("word"); - var peg$e34 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_", "@", ".", "/", "#", "&", "+", "-", "\\", "'", ",", ";", "%"], false, false); - var peg$e35 = peg$otherExpectation("whitespace"); - var peg$e36 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); + var peg$e23 = peg$otherExpectation("default key"); + var peg$e24 = peg$literalExpectation("type", false); + var peg$e25 = peg$literalExpectation("status", false); + var peg$e26 = peg$literalExpectation("sortBy", false); + var peg$e27 = peg$literalExpectation("sortOrder", false); + var peg$e28 = peg$literalExpectation("policyID", false); + var peg$e29 = peg$otherExpectation("quote"); + var peg$e30 = peg$literalExpectation("\"", false); + var peg$e31 = peg$classExpectation(["\"", "\r", "\n"], true, false); + var peg$e32 = peg$otherExpectation("word"); + var peg$e33 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_", "@", ".", "/", "#", "&", "+", "-", "\\", "'", ",", ";", "%"], false, false); + var peg$e34 = peg$otherExpectation("whitespace"); + var peg$e35 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); var peg$f0 = function(filters) { return applyDefaults(filters); }; var peg$f1 = function(head, tail) { @@ -858,15 +856,6 @@ function peg$parse(input, options) { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e14); } } - if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 2) === peg$c20) { - s1 = peg$c20; - peg$currPos += 2; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e23); } - } - } } } } @@ -902,44 +891,44 @@ function peg$parse(input, options) { peg$silentFails++; s0 = peg$currPos; - if (input.substr(peg$currPos, 4) === peg$c21) { - s1 = peg$c21; + if (input.substr(peg$currPos, 4) === peg$c20) { + s1 = peg$c20; peg$currPos += 4; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e25); } + if (peg$silentFails === 0) { peg$fail(peg$e24); } } if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 6) === peg$c22) { - s1 = peg$c22; + if (input.substr(peg$currPos, 6) === peg$c21) { + s1 = peg$c21; peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e26); } + if (peg$silentFails === 0) { peg$fail(peg$e25); } } if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 6) === peg$c23) { - s1 = peg$c23; + if (input.substr(peg$currPos, 6) === peg$c22) { + s1 = peg$c22; peg$currPos += 6; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e27); } + if (peg$silentFails === 0) { peg$fail(peg$e26); } } if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 9) === peg$c24) { - s1 = peg$c24; + if (input.substr(peg$currPos, 9) === peg$c23) { + s1 = peg$c23; peg$currPos += 9; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e28); } + if (peg$silentFails === 0) { peg$fail(peg$e27); } } if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 8) === peg$c25) { - s1 = peg$c25; + if (input.substr(peg$currPos, 8) === peg$c24) { + s1 = peg$c24; peg$currPos += 8; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e29); } + if (peg$silentFails === 0) { peg$fail(peg$e28); } } } } @@ -954,7 +943,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e24); } + if (peg$silentFails === 0) { peg$fail(peg$e23); } } return s0; @@ -995,11 +984,11 @@ function peg$parse(input, options) { peg$silentFails++; s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c26; + s1 = peg$c25; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e31); } + if (peg$silentFails === 0) { peg$fail(peg$e30); } } if (s1 !== peg$FAILED) { s2 = []; @@ -1008,7 +997,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e32); } + if (peg$silentFails === 0) { peg$fail(peg$e31); } } while (s3 !== peg$FAILED) { s2.push(s3); @@ -1017,15 +1006,15 @@ function peg$parse(input, options) { peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e32); } + if (peg$silentFails === 0) { peg$fail(peg$e31); } } } if (input.charCodeAt(peg$currPos) === 34) { - s3 = peg$c26; + s3 = peg$c25; peg$currPos++; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e31); } + if (peg$silentFails === 0) { peg$fail(peg$e30); } } if (s3 !== peg$FAILED) { peg$savedPos = s0; @@ -1041,7 +1030,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e30); } + if (peg$silentFails === 0) { peg$fail(peg$e29); } } return s0; @@ -1058,7 +1047,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e34); } + if (peg$silentFails === 0) { peg$fail(peg$e33); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { @@ -1068,7 +1057,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e34); } + if (peg$silentFails === 0) { peg$fail(peg$e33); } } } } else { @@ -1082,7 +1071,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e33); } + if (peg$silentFails === 0) { peg$fail(peg$e32); } } return s0; @@ -1110,7 +1099,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e36); } + if (peg$silentFails === 0) { peg$fail(peg$e35); } } while (s1 !== peg$FAILED) { s0.push(s1); @@ -1119,12 +1108,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e36); } + if (peg$silentFails === 0) { peg$fail(peg$e35); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e35); } + if (peg$silentFails === 0) { peg$fail(peg$e34); } return s0; } diff --git a/src/libs/SearchParser/searchParser.peggy b/src/libs/SearchParser/searchParser.peggy index b2c6a0940bd3..32d44f24d0d6 100644 --- a/src/libs/SearchParser/searchParser.peggy +++ b/src/libs/SearchParser/searchParser.peggy @@ -120,7 +120,6 @@ key "key" / "from" / "expenseType" / "in" - / "no" ) defaultKey "default key" diff --git a/src/libs/SearchUtils.ts b/src/libs/SearchUtils.ts index f372ae71c814..47cee2c7c2b4 100644 --- a/src/libs/SearchUtils.ts +++ b/src/libs/SearchUtils.ts @@ -626,7 +626,6 @@ function buildQueryStringFromFilterFormValues(filterValues: Partial 0 diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index b7a3fe3ab66f..7009764629ba 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -105,11 +105,6 @@ const baseFilterConfig = { description: 'common.in' as const, route: ROUTES.SEARCH_ADVANCED_FILTERS_IN, }, - no: { - getTitle: getFilterInDisplayTitle, - description: 'common.no' as const, - route: ROUTES.SEARCH_ADVANCED_FILTERS_NO, - }, }; const typeFiltersKeys: Record>> = { @@ -144,10 +139,6 @@ function getFilterParticipantDisplayTitle(accountIDs: string[], personalDetails: } function getFilterDisplayTitle(filters: Partial, fieldName: AdvancedFiltersKeys, translate: LocaleContextProps['translate']) { - if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.NO) { - return ''; - } - if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE) { // the value of date filter is a combination of dateBefore + dateAfter values const {dateAfter, dateBefore} = filters; @@ -183,14 +174,6 @@ function getFilterDisplayTitle(filters: Partial, fiel return; } - if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY && filters[CONST.SEARCH.SYNTAX_FILTER_KEYS.NO]) { - return translate('search.filters.noCategory'); - } - - if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG && filters[CONST.SEARCH.SYNTAX_FILTER_KEYS.NO]) { - return translate('search.filters.noTag'); - } - if ( (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY || fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY || fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG) && filters[fieldName] @@ -252,6 +235,7 @@ function AdvancedSearchFilters() { const queryString = useMemo(() => SearchUtils.buildQueryStringFromFilterFormValues(searchAdvancedFilters), [searchAdvancedFilters]); const queryJSON = useMemo(() => SearchUtils.buildSearchQueryJSON(queryString || SearchUtils.buildCannedSearchQuery()), [queryString]); + const applyFiltersAndNavigate = () => { SearchActions.clearAllFilters(); Navigation.dismissModal(); diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx index b9b74605a744..58cdfb4b2679 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx @@ -24,7 +24,7 @@ function SearchFiltersCategoryPage() { const singlePolicyCategories = allPolicyIDCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]; const categoryItems = useMemo(() => { - const items = [{name: translate('search.filters.noCategory'), value: CONST.SEARCH.FILTER_NO.CATEGORY as string}]; + const items = [{name: translate('search.filters.noCategory'), value: CONST.SEARCH.VALUE_NONE as string}]; if (!singlePolicyCategories) { const uniqueCategoryNames = new Set(); Object.values(allPolicyIDCategories ?? {}).map((policyCategories) => Object.values(policyCategories ?? {}).forEach((category) => uniqueCategoryNames.add(category.name))); @@ -35,13 +35,7 @@ function SearchFiltersCategoryPage() { return items; }, [allPolicyIDCategories, singlePolicyCategories, translate]); - const onSaveSelection = useCallback((values: string[]) => { - if (values.at(0) === CONST.SEARCH.FILTER_NO.CATEGORY) { - SearchActions.updateAdvancedFilters({no: [CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY]}); - return; - } - SearchActions.updateAdvancedFilters({category: values}); - }, []); + const onSaveSelection = useCallback((values: string[]) => SearchActions.updateAdvancedFilters({category: values}), []); const safePaddingBottomStyle = useSafePaddingBottomStyle(); return ( diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx index 971b233e87eb..f43ed0586f79 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx @@ -25,7 +25,7 @@ function SearchFiltersTagPage() { const singlePolicyTagsList: PolicyTagLists | undefined = allPoliciesTagsLists?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`]; const tagItems = useMemo(() => { - const items = [{name: translate('search.filters.noTag'), value: CONST.SEARCH.FILTER_NO.TAG as string}]; + const items = [{name: translate('search.filters.noTag'), value: CONST.SEARCH.VALUE_NONE as string}]; if (!singlePolicyTagsList) { const uniqueTagNames = new Set(); const tagListsUnpacked = Object.values(allPoliciesTagsLists ?? {}).filter((item) => !!item) as PolicyTagLists[]; @@ -42,12 +42,7 @@ function SearchFiltersTagPage() { return items; }, [allPoliciesTagsLists, singlePolicyTagsList, translate]); - const updateTagFilter = useCallback((values: string[]) => { - if (values.at(0) === CONST.SEARCH.FILTER_NO.TAG) { - SearchActions.updateAdvancedFilters({no: [CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG]}); - } - SearchActions.updateAdvancedFilters({tag: values}); - }, []); + const updateTagFilter = useCallback((values: string[]) => SearchActions.updateAdvancedFilters({tag: values}), []); return ( ; @@ -50,7 +49,6 @@ type SearchAdvancedFiltersForm = Form< [FILTER_KEYS.FROM]: string[]; [FILTER_KEYS.TO]: string[]; [FILTER_KEYS.IN]: string[]; - [FILTER_KEYS.NO]: string[]; } >; From 8b165dbd2239dc56dfed956eae62d677299b1b6f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 10 Oct 2024 16:05:29 -0600 Subject: [PATCH 13/18] update sort logic --- src/languages/en.ts | 4 +-- src/languages/es.ts | 4 +-- src/pages/Search/AdvancedSearchFilters.tsx | 30 ++++++++++++++++--- .../SearchFiltersCategoryPage.tsx | 2 +- .../SearchFiltersTagPage.tsx | 2 +- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index f6180c9be4d7..7fcfc2ce855e 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -4182,9 +4182,9 @@ const translations = { }, current: 'Current', past: 'Past', - noCategory: 'No category', - noTag: 'No tag', }, + noCategory: 'No category', + noTag: 'No tag', expenseType: 'Expense type', recentSearches: 'Recent searches', recentChats: 'Recent chats', diff --git a/src/languages/es.ts b/src/languages/es.ts index 24cf017018cd..cd3044cb6117 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4227,9 +4227,9 @@ const translations = { }, current: 'Actual', past: 'Anterior', - noCategory: 'Sin categoría', - noTag: 'Sin etiqueta', }, + noCategory: 'Sin categoría', + noTag: 'Sin etiqueta', expenseType: 'Tipo de gasto', recentSearches: 'Búsquedas recientes', recentChats: 'Chats recientes', diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 7009764629ba..037c7d57de0f 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -138,6 +138,15 @@ function getFilterParticipantDisplayTitle(accountIDs: string[], personalDetails: .join(', '); } +function sortOptions(a: string, b: string) { + console.log('over here', {a,b}) + // Always show `No category` and `No tag` as the first option + if (a === CONST.SEARCH.VALUE_NONE || b === CONST.SEARCH.VALUE_NONE) { + return 1; + } + return localeCompare(a, b); +} + function getFilterDisplayTitle(filters: Partial, fieldName: AdvancedFiltersKeys, translate: LocaleContextProps['translate']) { if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE) { // the value of date filter is a combination of dateBefore + dateAfter values @@ -174,14 +183,27 @@ function getFilterDisplayTitle(filters: Partial, fiel return; } - if ( - (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY || fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY || fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG) && - filters[fieldName] - ) { + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY && filters[fieldName]) { const filterArray = filters[fieldName] ?? []; return filterArray.sort(localeCompare).join(', '); } + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY && filters[fieldName]) { + const filterArray = filters[fieldName] ?? []; + return filterArray + .sort(sortOptions) + .map((value) => (value === CONST.SEARCH.VALUE_NONE ? translate('search.noCategory') : value)) + .join(', '); + } + + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG && filters[fieldName]) { + const filterArray = filters[fieldName] ?? []; + return filterArray + .sort(sortOptions) + .map((value) => (value === CONST.SEARCH.VALUE_NONE ? translate('search.noTag') : value)) + .join(', '); + } + if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.DESCRIPTION) { return filters[fieldName]; } diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx index 58cdfb4b2679..d76dd7856c07 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx @@ -24,7 +24,7 @@ function SearchFiltersCategoryPage() { const singlePolicyCategories = allPolicyIDCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]; const categoryItems = useMemo(() => { - const items = [{name: translate('search.filters.noCategory'), value: CONST.SEARCH.VALUE_NONE as string}]; + const items = [{name: translate('search.noCategory'), value: CONST.SEARCH.VALUE_NONE as string}]; if (!singlePolicyCategories) { const uniqueCategoryNames = new Set(); Object.values(allPolicyIDCategories ?? {}).map((policyCategories) => Object.values(policyCategories ?? {}).forEach((category) => uniqueCategoryNames.add(category.name))); diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx index f43ed0586f79..aadb69afdb33 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx @@ -25,7 +25,7 @@ function SearchFiltersTagPage() { const singlePolicyTagsList: PolicyTagLists | undefined = allPoliciesTagsLists?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`]; const tagItems = useMemo(() => { - const items = [{name: translate('search.filters.noTag'), value: CONST.SEARCH.VALUE_NONE as string}]; + const items = [{name: translate('search.noTag'), value: CONST.SEARCH.VALUE_NONE as string}]; if (!singlePolicyTagsList) { const uniqueTagNames = new Set(); const tagListsUnpacked = Object.values(allPoliciesTagsLists ?? {}).filter((item) => !!item) as PolicyTagLists[]; From 223ad3de29935a17309f6250b4e0a14e660c8bf0 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 10 Oct 2024 16:09:03 -0600 Subject: [PATCH 14/18] update display value in filter list --- .../SearchFiltersCategoryPage.tsx | 7 ++++++- .../SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx index d76dd7856c07..87d300487d97 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx @@ -18,7 +18,12 @@ function SearchFiltersCategoryPage() { const {translate} = useLocalize(); const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); - const selectedCategoriesItems = searchAdvancedFiltersForm?.category?.map((category) => ({name: category, value: category})); + const selectedCategoriesItems = searchAdvancedFiltersForm?.category?.map((category) => { + if (category === CONST.SEARCH.VALUE_NONE) { + return {name: translate('search.noCategory'), value: category}; + } + return {name: category, value: category}; + }); const policyID = searchAdvancedFiltersForm?.policyID ?? '-1'; const [allPolicyIDCategories] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES); const singlePolicyCategories = allPolicyIDCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]; diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx index aadb69afdb33..9c808030b3aa 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx @@ -19,7 +19,12 @@ function SearchFiltersTagPage() { const {translate} = useLocalize(); const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); - const selectedTagsItems = searchAdvancedFiltersForm?.tag?.map((tag) => ({name: tag, value: tag})); + const selectedTagsItems = searchAdvancedFiltersForm?.tag?.map((tag) => { + if (tag === CONST.SEARCH.VALUE_NONE) { + return {name: translate('search.noTag'), value: tag}; + } + return {name: tag, value: tag}; + }); const policyID = searchAdvancedFiltersForm?.policyID ?? '-1'; const [allPoliciesTagsLists] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS); const singlePolicyTagsList: PolicyTagLists | undefined = allPoliciesTagsLists?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`]; From 84882b8a4f30adf9f9ade6b5e62449ee0404aa82 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 10 Oct 2024 16:16:14 -0600 Subject: [PATCH 15/18] update sorting function --- .../Search/SearchMultipleSelectionPicker.tsx | 11 +++++++---- src/pages/Search/AdvancedSearchFilters.tsx | 14 ++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/components/Search/SearchMultipleSelectionPicker.tsx b/src/components/Search/SearchMultipleSelectionPicker.tsx index 8e733da24b0f..b401effc8140 100644 --- a/src/components/Search/SearchMultipleSelectionPicker.tsx +++ b/src/components/Search/SearchMultipleSelectionPicker.tsx @@ -29,9 +29,12 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const [selectedItems, setSelectedItems] = useState(initiallySelectedItems ?? []); - const sortOptions = (a: SearchMultipleSelectionPickerItem, b: SearchMultipleSelectionPickerItem) => { + const sortOptionsWithNoneValue = (a: SearchMultipleSelectionPickerItem, b: SearchMultipleSelectionPickerItem) => { // Always show `No category` and `No tag` as the first option - if (a.value === CONST.SEARCH.VALUE_NONE || b.value === CONST.SEARCH.VALUE_NONE) { + if (a.value === CONST.SEARCH.VALUE_NONE) { + return -1; + } + if (b.value === CONST.SEARCH.VALUE_NONE) { return 1; } return localeCompare(a.name, b.name); @@ -44,7 +47,7 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit const {sections, noResultsFound} = useMemo(() => { const selectedItemsSection = selectedItems .filter((item) => item?.name.toLowerCase().includes(debouncedSearchTerm?.toLowerCase())) - .sort((a, b) => sortOptions(a, b)) + .sort((a, b) => sortOptionsWithNoneValue(a, b)) .map((item) => ({ text: item.name, keyForList: item.name, @@ -53,7 +56,7 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit })); const remainingItemsSection = items .filter((item) => selectedItems.some((selectedItem) => selectedItem.value === item.value) === false && item?.name.toLowerCase().includes(debouncedSearchTerm?.toLowerCase())) - .sort((a, b) => sortOptions(a, b)) + .sort((a, b) => sortOptionsWithNoneValue(a, b)) .map((item) => ({ text: item.name, keyForList: item.name, diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 037c7d57de0f..309030e9edd1 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -138,14 +138,16 @@ function getFilterParticipantDisplayTitle(accountIDs: string[], personalDetails: .join(', '); } -function sortOptions(a: string, b: string) { - console.log('over here', {a,b}) +const sortOptionsWithNoneValue = (a, b) => { // Always show `No category` and `No tag` as the first option - if (a === CONST.SEARCH.VALUE_NONE || b === CONST.SEARCH.VALUE_NONE) { + if (a === CONST.SEARCH.VALUE_NONE) { + return -1; + } + if (b === CONST.SEARCH.VALUE_NONE) { return 1; } return localeCompare(a, b); -} +}; function getFilterDisplayTitle(filters: Partial, fieldName: AdvancedFiltersKeys, translate: LocaleContextProps['translate']) { if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE) { @@ -191,7 +193,7 @@ function getFilterDisplayTitle(filters: Partial, fiel if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY && filters[fieldName]) { const filterArray = filters[fieldName] ?? []; return filterArray - .sort(sortOptions) + .sort(sortOptionsWithNoneValue) .map((value) => (value === CONST.SEARCH.VALUE_NONE ? translate('search.noCategory') : value)) .join(', '); } @@ -199,7 +201,7 @@ function getFilterDisplayTitle(filters: Partial, fiel if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG && filters[fieldName]) { const filterArray = filters[fieldName] ?? []; return filterArray - .sort(sortOptions) + .sort(sortOptionsWithNoneValue) .map((value) => (value === CONST.SEARCH.VALUE_NONE ? translate('search.noTag') : value)) .join(', '); } From 7169928819d864d137b38da2492886b14a2a748a Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 10 Oct 2024 16:22:57 -0600 Subject: [PATCH 16/18] rename const --- src/CONST.ts | 2 +- src/components/Search/SearchMultipleSelectionPicker.tsx | 4 ++-- src/pages/Search/AdvancedSearchFilters.tsx | 8 ++++---- .../SearchFiltersCategoryPage.tsx | 4 ++-- .../SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/CONST.ts b/src/CONST.ts index d058fda641b3..823bae5d0b9c 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -5610,7 +5610,7 @@ const CONST = { KEYWORD: 'keyword', IN: 'in', }, - VALUE_NONE: 'none', + EMPTY_VALUE: 'none', }, REFERRER: { diff --git a/src/components/Search/SearchMultipleSelectionPicker.tsx b/src/components/Search/SearchMultipleSelectionPicker.tsx index b401effc8140..a6c7b2504f2c 100644 --- a/src/components/Search/SearchMultipleSelectionPicker.tsx +++ b/src/components/Search/SearchMultipleSelectionPicker.tsx @@ -31,10 +31,10 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit const sortOptionsWithNoneValue = (a: SearchMultipleSelectionPickerItem, b: SearchMultipleSelectionPickerItem) => { // Always show `No category` and `No tag` as the first option - if (a.value === CONST.SEARCH.VALUE_NONE) { + if (a.value === CONST.SEARCH.EMPTY_VALUE) { return -1; } - if (b.value === CONST.SEARCH.VALUE_NONE) { + if (b.value === CONST.SEARCH.EMPTY_VALUE) { return 1; } return localeCompare(a.name, b.name); diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 309030e9edd1..0bd6207cfbe7 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -140,10 +140,10 @@ function getFilterParticipantDisplayTitle(accountIDs: string[], personalDetails: const sortOptionsWithNoneValue = (a, b) => { // Always show `No category` and `No tag` as the first option - if (a === CONST.SEARCH.VALUE_NONE) { + if (a === CONST.SEARCH.EMPTY_VALUE) { return -1; } - if (b === CONST.SEARCH.VALUE_NONE) { + if (b === CONST.SEARCH.EMPTY_VALUE) { return 1; } return localeCompare(a, b); @@ -194,7 +194,7 @@ function getFilterDisplayTitle(filters: Partial, fiel const filterArray = filters[fieldName] ?? []; return filterArray .sort(sortOptionsWithNoneValue) - .map((value) => (value === CONST.SEARCH.VALUE_NONE ? translate('search.noCategory') : value)) + .map((value) => (value === CONST.SEARCH.EMPTY_VALUE ? translate('search.noCategory') : value)) .join(', '); } @@ -202,7 +202,7 @@ function getFilterDisplayTitle(filters: Partial, fiel const filterArray = filters[fieldName] ?? []; return filterArray .sort(sortOptionsWithNoneValue) - .map((value) => (value === CONST.SEARCH.VALUE_NONE ? translate('search.noTag') : value)) + .map((value) => (value === CONST.SEARCH.EMPTY_VALUE ? translate('search.noTag') : value)) .join(', '); } diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx index 87d300487d97..b8f4163f3d44 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCategoryPage.tsx @@ -19,7 +19,7 @@ function SearchFiltersCategoryPage() { const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); const selectedCategoriesItems = searchAdvancedFiltersForm?.category?.map((category) => { - if (category === CONST.SEARCH.VALUE_NONE) { + if (category === CONST.SEARCH.EMPTY_VALUE) { return {name: translate('search.noCategory'), value: category}; } return {name: category, value: category}; @@ -29,7 +29,7 @@ function SearchFiltersCategoryPage() { const singlePolicyCategories = allPolicyIDCategories?.[`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policyID}`]; const categoryItems = useMemo(() => { - const items = [{name: translate('search.noCategory'), value: CONST.SEARCH.VALUE_NONE as string}]; + const items = [{name: translate('search.noCategory'), value: CONST.SEARCH.EMPTY_VALUE as string}]; if (!singlePolicyCategories) { const uniqueCategoryNames = new Set(); Object.values(allPolicyIDCategories ?? {}).map((policyCategories) => Object.values(policyCategories ?? {}).forEach((category) => uniqueCategoryNames.add(category.name))); diff --git a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx index 9c808030b3aa..85ed0da43309 100644 --- a/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx +++ b/src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersTagPage.tsx @@ -20,7 +20,7 @@ function SearchFiltersTagPage() { const [searchAdvancedFiltersForm] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); const selectedTagsItems = searchAdvancedFiltersForm?.tag?.map((tag) => { - if (tag === CONST.SEARCH.VALUE_NONE) { + if (tag === CONST.SEARCH.EMPTY_VALUE) { return {name: translate('search.noTag'), value: tag}; } return {name: tag, value: tag}; @@ -30,7 +30,7 @@ function SearchFiltersTagPage() { const singlePolicyTagsList: PolicyTagLists | undefined = allPoliciesTagsLists?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`]; const tagItems = useMemo(() => { - const items = [{name: translate('search.noTag'), value: CONST.SEARCH.VALUE_NONE as string}]; + const items = [{name: translate('search.noTag'), value: CONST.SEARCH.EMPTY_VALUE as string}]; if (!singlePolicyTagsList) { const uniqueTagNames = new Set(); const tagListsUnpacked = Object.values(allPoliciesTagsLists ?? {}).filter((item) => !!item) as PolicyTagLists[]; From bfc0cda69642cb2ce3d6a0f7a15290b97aeb2e26 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 10 Oct 2024 17:31:34 -0600 Subject: [PATCH 17/18] fix ts --- src/pages/Search/AdvancedSearchFilters.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 0bd6207cfbe7..41e4cd485bc7 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -138,7 +138,7 @@ function getFilterParticipantDisplayTitle(accountIDs: string[], personalDetails: .join(', '); } -const sortOptionsWithNoneValue = (a, b) => { +const sortOptionsWithNoneValue = (a: string, b: string) => { // Always show `No category` and `No tag` as the first option if (a === CONST.SEARCH.EMPTY_VALUE) { return -1; From 345a8abb1b9a64f1e9b3720c9c04dd62d36945db Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 10 Oct 2024 17:32:53 -0600 Subject: [PATCH 18/18] rename function --- src/components/Search/SearchMultipleSelectionPicker.tsx | 6 +++--- src/pages/Search/AdvancedSearchFilters.tsx | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/Search/SearchMultipleSelectionPicker.tsx b/src/components/Search/SearchMultipleSelectionPicker.tsx index a6c7b2504f2c..d76f2e76ab02 100644 --- a/src/components/Search/SearchMultipleSelectionPicker.tsx +++ b/src/components/Search/SearchMultipleSelectionPicker.tsx @@ -29,7 +29,7 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); const [selectedItems, setSelectedItems] = useState(initiallySelectedItems ?? []); - const sortOptionsWithNoneValue = (a: SearchMultipleSelectionPickerItem, b: SearchMultipleSelectionPickerItem) => { + const sortOptionsWithEmptyValue = (a: SearchMultipleSelectionPickerItem, b: SearchMultipleSelectionPickerItem) => { // Always show `No category` and `No tag` as the first option if (a.value === CONST.SEARCH.EMPTY_VALUE) { return -1; @@ -47,7 +47,7 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit const {sections, noResultsFound} = useMemo(() => { const selectedItemsSection = selectedItems .filter((item) => item?.name.toLowerCase().includes(debouncedSearchTerm?.toLowerCase())) - .sort((a, b) => sortOptionsWithNoneValue(a, b)) + .sort((a, b) => sortOptionsWithEmptyValue(a, b)) .map((item) => ({ text: item.name, keyForList: item.name, @@ -56,7 +56,7 @@ function SearchMultipleSelectionPicker({items, initiallySelectedItems, pickerTit })); const remainingItemsSection = items .filter((item) => selectedItems.some((selectedItem) => selectedItem.value === item.value) === false && item?.name.toLowerCase().includes(debouncedSearchTerm?.toLowerCase())) - .sort((a, b) => sortOptionsWithNoneValue(a, b)) + .sort((a, b) => sortOptionsWithEmptyValue(a, b)) .map((item) => ({ text: item.name, keyForList: item.name, diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 41e4cd485bc7..c5dc2cf85a56 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -138,7 +138,7 @@ function getFilterParticipantDisplayTitle(accountIDs: string[], personalDetails: .join(', '); } -const sortOptionsWithNoneValue = (a: string, b: string) => { +const sortOptionsWithEmptyValue = (a: string, b: string) => { // Always show `No category` and `No tag` as the first option if (a === CONST.SEARCH.EMPTY_VALUE) { return -1; @@ -193,7 +193,7 @@ function getFilterDisplayTitle(filters: Partial, fiel if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY && filters[fieldName]) { const filterArray = filters[fieldName] ?? []; return filterArray - .sort(sortOptionsWithNoneValue) + .sort(sortOptionsWithEmptyValue) .map((value) => (value === CONST.SEARCH.EMPTY_VALUE ? translate('search.noCategory') : value)) .join(', '); } @@ -201,7 +201,7 @@ function getFilterDisplayTitle(filters: Partial, fiel if (fieldName === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG && filters[fieldName]) { const filterArray = filters[fieldName] ?? []; return filterArray - .sort(sortOptionsWithNoneValue) + .sort(sortOptionsWithEmptyValue) .map((value) => (value === CONST.SEARCH.EMPTY_VALUE ? translate('search.noTag') : value)) .join(', '); }