diff --git a/src/components/Search/FilterComponents/CategorySelector.tsx b/src/components/Search/FilterComponents/CategorySelector.tsx index 27ce0a2626fb..e3a047b01324 100644 --- a/src/components/Search/FilterComponents/CategorySelector.tsx +++ b/src/components/Search/FilterComponents/CategorySelector.tsx @@ -6,20 +6,18 @@ import useOnyx from '@hooks/useOnyx'; import {getDecodedCategoryName} from '@libs/CategoryUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {filterPolicyIDSelector} from '@src/selectors/Search'; import type {PolicyCategories, PolicyCategory} from '@src/types/onyx'; import {getEmptyObject} from '@src/types/utils/EmptyObject'; -import getEmptyArray from '@src/types/utils/getEmptyArray'; import MultiSelect from './MultiSelect'; type CategorySelectorProps = SearchFilterSelectionListProps & { value: string[] | undefined; + policyIDs: string[] | undefined; onChange: (categories: string[]) => void; }; -function CategorySelector({value = [], selectionListTextInputStyle, selectionListStyle, autoFocus, footer, onChange}: CategorySelectorProps) { +function CategorySelector({value = [], policyIDs = [], selectionListTextInputStyle, selectionListStyle, autoFocus, footer, onChange}: CategorySelectorProps) { const {translate} = useLocalize(); - const [policyIDs = getEmptyArray()] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, {selector: filterPolicyIDSelector}); const [personalPolicyID] = useOnyx(ONYXKEYS.PERSONAL_POLICY_ID); const selectedCategoriesItems = value.map((category) => { diff --git a/src/components/Search/FilterComponents/ExportedToSelector.tsx b/src/components/Search/FilterComponents/ExportedToSelector.tsx index 07378885dca2..edc3ed0d4f69 100644 --- a/src/components/Search/FilterComponents/ExportedToSelector.tsx +++ b/src/components/Search/FilterComponents/ExportedToSelector.tsx @@ -16,13 +16,12 @@ import {getIntegrationIcon} from '@libs/ReportUtils'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {filterPolicyIDSelector} from '@src/selectors/Search'; -import getEmptyArray from '@src/types/utils/getEmptyArray'; import type IconAsset from '@src/types/utils/IconAsset'; import MultiSelect from './MultiSelect'; type ExportedToSelectorProps = SearchFilterSelectionListProps & { value: string[] | undefined; + policyIDs: string[] | undefined; onChange: (exportedTo: string[]) => void; }; @@ -31,7 +30,7 @@ const STANDARD_EXPORT_TEMPLATE_ID_TO_DISPLAY_LABEL: Record = { [CONST.REPORT.EXPORT_OPTIONS.EXPENSE_LEVEL_EXPORT]: CONST.REPORT.EXPORT_OPTION_LABELS.EXPENSE_LEVEL_EXPORT, }; -function ExportedToSelector({value = [], selectionListTextInputStyle, selectionListStyle, autoFocus, footer, onChange}: ExportedToSelectorProps) { +function ExportedToSelector({value = [], policyIDs = [], selectionListTextInputStyle, selectionListStyle, autoFocus, footer, onChange}: ExportedToSelectorProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const StyleUtils = useStyleUtils(); @@ -49,7 +48,6 @@ function ExportedToSelector({value = [], selectionListTextInputStyle, selectionL ]); const [integrationsExportTemplates] = useOnyx(ONYXKEYS.NVP_INTEGRATION_SERVER_EXPORT_TEMPLATES); const [csvExportLayouts] = useOnyx(ONYXKEYS.NVP_CSV_EXPORT_LAYOUTS); - const [policyIDs = getEmptyArray()] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, {selector: filterPolicyIDSelector}); const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); const connectedIntegrationNames = getConnectedIntegrationNamesForPolicies(policies, policyIDs.length > 0 ? policyIDs : undefined); diff --git a/src/components/Search/FilterComponents/TagSelector.tsx b/src/components/Search/FilterComponents/TagSelector.tsx index 12651370d21f..5cd575224935 100644 --- a/src/components/Search/FilterComponents/TagSelector.tsx +++ b/src/components/Search/FilterComponents/TagSelector.tsx @@ -7,20 +7,18 @@ import {getCleanedTagName, getTagNamesFromTagsLists} from '@libs/PolicyUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import passthroughPolicyTagListSelector from '@src/selectors/PolicyTagList'; -import {filterPolicyIDSelector} from '@src/selectors/Search'; import type {PolicyTagLists} from '@src/types/onyx'; import {getEmptyObject} from '@src/types/utils/EmptyObject'; -import getEmptyArray from '@src/types/utils/getEmptyArray'; import MultiSelect from './MultiSelect'; type TagSelectorProps = SearchFilterSelectionListProps & { value: string[] | undefined; + policyIDs: string[] | undefined; onChange: (tags: string[]) => void; }; -function TagSelector({value = [], selectionListTextInputStyle, selectionListStyle, autoFocus, footer, onChange}: TagSelectorProps) { +function TagSelector({value = [], policyIDs = [], selectionListTextInputStyle, selectionListStyle, autoFocus, footer, onChange}: TagSelectorProps) { const {translate} = useLocalize(); - const [policyIDs = getEmptyArray()] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, {selector: filterPolicyIDSelector}); const [allPolicyTagLists = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS, {selector: passthroughPolicyTagListSelector}); const selectedPoliciesTagLists = Object.keys(allPolicyTagLists ?? {}) diff --git a/src/components/Search/FilterComponents/TaxRateSelector.tsx b/src/components/Search/FilterComponents/TaxRateSelector.tsx index 749f9dd820c1..f9a884c70f6e 100644 --- a/src/components/Search/FilterComponents/TaxRateSelector.tsx +++ b/src/components/Search/FilterComponents/TaxRateSelector.tsx @@ -4,17 +4,16 @@ import useOnyx from '@hooks/useOnyx'; import {getAllTaxRates} from '@libs/PolicyUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {filterPolicyIDSelector} from '@src/selectors/Search'; import type {Policy} from '@src/types/onyx'; import MultiSelect from './MultiSelect'; type TaxRateSelectorProps = SearchFilterSelectionListProps & { value: string[] | undefined; + policyIDs: string[] | undefined; onChange: (taxRates: string[]) => void; }; -function TaxRateSelector({value = [], selectionListTextInputStyle, selectionListStyle, autoFocus, footer, onChange}: TaxRateSelectorProps) { - const [policyIDs] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, {selector: filterPolicyIDSelector}); +function TaxRateSelector({value = [], policyIDs = [], selectionListTextInputStyle, selectionListStyle, autoFocus, footer, onChange}: TaxRateSelectorProps) { const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY); const allTaxRates = getAllTaxRates(policies); diff --git a/src/components/Search/FilterComponents/WorkspaceSelector.tsx b/src/components/Search/FilterComponents/WorkspaceSelector.tsx index 00ddc12e2a8e..6b7423aa3223 100644 --- a/src/components/Search/FilterComponents/WorkspaceSelector.tsx +++ b/src/components/Search/FilterComponents/WorkspaceSelector.tsx @@ -1,7 +1,12 @@ import React from 'react'; +import type {OnyxCollection} from 'react-native-onyx'; import type {SearchFilterSelectionListProps} from '@components/Search/types'; -import useAdvancedSearchFilters from '@hooks/useAdvancedSearchFilters'; +import {advancedSearchPoliciesSelector, useAdvancedSearchFiltersWorkspaces} from '@hooks/useAdvancedSearchFilters'; +import useOnyx from '@hooks/useOnyx'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Policy} from '@src/types/onyx'; import type {Icon} from '@src/types/onyx/OnyxCommon'; +import {getEmptyObject} from '@src/types/utils/EmptyObject'; import type {MultiSelectItem} from './MultiSelect'; import MultiSelect from './MultiSelect'; @@ -13,7 +18,8 @@ type WorkspaceSelectorProps = SearchFilterSelectionListProps & { }; function WorkspaceSelector({policyIDQuery, value, selectionListTextInputStyle, selectionListStyle, autoFocus, footer, onChange}: WorkspaceSelectorProps) { - const {workspaces, shouldShowWorkspaceSearchInput} = useAdvancedSearchFilters(); + const [policies = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: advancedSearchPoliciesSelector}); + const {workspaces, shouldShowWorkspaceSearchInput} = useAdvancedSearchFiltersWorkspaces(policies); const workspaceOptions: Array> = workspaces .flatMap((section) => section.data) .filter((workspace): workspace is typeof workspace & {policyID: string; icons: Icon[]} => !!workspace.policyID && !!workspace.icons) diff --git a/src/components/Search/FilterComponents/index.tsx b/src/components/Search/FilterComponents/index.tsx index 90773737f3d8..8d4cc938b69e 100644 --- a/src/components/Search/FilterComponents/index.tsx +++ b/src/components/Search/FilterComponents/index.tsx @@ -1,15 +1,13 @@ import React from 'react'; -import type {OnyxEntry} from 'react-native-onyx'; import type {SearchAmountFilterKeys, SearchDateFilterKeys, SearchFilterSelectionListProps} from '@components/Search/types'; import TextInput from '@components/TextInput'; import useLocalize from '@hooks/useLocalize'; -import useOnyx from '@hooks/useOnyx'; import useThemeStyles from '@hooks/useThemeStyles'; import {FILTER_VIEW_MAP, getMultiSelectFilterOptions, getSingleSelectFilterOptions} from '@libs/SearchUIUtils'; import type {SearchFilter} from '@libs/SearchUIUtils'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import type {SearchAdvancedFiltersForm} from '@src/types/form/SearchAdvancedFiltersForm'; +import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; import CardSelector from './CardSelector'; import CategorySelector from './CategorySelector'; import CurrencySelector from './CurrencySelector'; @@ -28,6 +26,8 @@ type FilterKeys = Exclude void; @@ -63,6 +63,7 @@ type MultiSelectFilterKeys = type MultiSelectFilterComponentsProps = SearchFilterSelectionListProps & { filterKey: MultiSelectFilterKeys; value: SearchAdvancedFiltersForm[MultiSelectFilterKeys] | undefined; + type: SearchDataTypes | undefined; onChange: (values: SearchAdvancedFiltersForm[MultiSelectFilterKeys]) => void; }; @@ -101,14 +102,8 @@ function SingleSelectFilterComponents({filterKey, value, selectionListTextInputS ); } -function MultiSelectFilterComponents({filterKey, value = [], selectionListStyle, footer, onChange}: MultiSelectFilterComponentsProps) { +function MultiSelectFilterComponents({filterKey, value = [], type = CONST.SEARCH.DATA_TYPES.EXPENSE, selectionListStyle, footer, onChange}: MultiSelectFilterComponentsProps) { const {translate} = useLocalize(); - const typeSelector = (searchAdvancedFiltersForm: OnyxEntry) => { - return searchAdvancedFiltersForm?.type; - }; - const [type = CONST.SEARCH.DATA_TYPES.EXPENSE] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, { - selector: typeSelector, - }); const items = getMultiSelectFilterOptions(filterKey, type, translate); const normalizedValue = Array.isArray(value) ? value : value.split(','); const multiSelectValues = items.filter((item) => normalizedValue.includes(item.value)); @@ -133,6 +128,8 @@ function MultiSelectFilterComponents({filterKey, value = [], selectionListStyle, function FilterComponents({ filterKey, value, + type, + policyIDs, policyIDQuery, selectionListTextInputStyle, selectionListStyle, @@ -161,6 +158,7 @@ function FilterComponents({ return ( {!!selectedFilter && ( diff --git a/src/components/Search/FilterDropdowns/AdvancedFilters/AdvancedFiltersPopup.tsx b/src/components/Search/FilterDropdowns/AdvancedFilters/AdvancedFiltersPopup.tsx index 1d32efc520e6..1dc41dd3d48a 100644 --- a/src/components/Search/FilterDropdowns/AdvancedFilters/AdvancedFiltersPopup.tsx +++ b/src/components/Search/FilterDropdowns/AdvancedFilters/AdvancedFiltersPopup.tsx @@ -32,6 +32,8 @@ function AdvancedFiltersPopup({queryJSON}: AdvancedFiltersPopupProps) { ; onFilterSelected: (filter: SearchFilter['key']) => void; }; -function FilterList({selectedFilter, style, onFilterSelected}: FilterListProps) { +function FilterList({selectedFilter, type, policyID, style, onFilterSelected}: FilterListProps) { const styles = useThemeStyles(); - const {typeFiltersKeys} = useAdvancedSearchFilters(); + const typeFiltersKeys = useAdvancedSearchFilters(type, policyID); const fullscreen = useFullscreenAdvancedFilters(); return ( diff --git a/src/components/Search/FilterDropdowns/AdvancedFilters/SelectedFilterContent.tsx b/src/components/Search/FilterDropdowns/AdvancedFilters/SelectedFilterContent.tsx index c2116a8070bb..1421c713f9b9 100644 --- a/src/components/Search/FilterDropdowns/AdvancedFilters/SelectedFilterContent.tsx +++ b/src/components/Search/FilterDropdowns/AdvancedFilters/SelectedFilterContent.tsx @@ -9,6 +9,7 @@ import {isAmountFilterKey, isDateFilterKey} from '@libs/SearchUIUtils'; import type {SearchFilter} from '@libs/SearchUIUtils'; import CONST from '@src/CONST'; import type {SearchAdvancedFiltersForm} from '@src/types/form'; +import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; import AmountFilterComponent from './AmountFilterComponent'; import DateFilterComponent from './DateFilterComponent'; import ReportFieldFilterComponent from './ReportFieldFilterComponent'; @@ -36,6 +37,8 @@ type TextInputFilterContentProps = { type CommonContentProps = { filterKey: FilterComponentsProps['filterKey']; value: FilterComponentsProps['value']; + type: SearchDataTypes | undefined; + policyIDs: string[] | undefined; policyIDQuery: string[] | undefined; onChange: (values: Partial) => void; }; @@ -51,6 +54,7 @@ function TextInputFilterContent({filterKey, value: initialValue, onChange}: Text (initialValue); @@ -78,6 +82,8 @@ function CommonContent({filterKey, value: initialValue, policyIDQuery, onChange} return ( diff --git a/src/components/Search/FilterDropdowns/CommonPopup.tsx b/src/components/Search/FilterDropdowns/CommonPopup.tsx index 46d142662dc9..bd404e6687d6 100644 --- a/src/components/Search/FilterDropdowns/CommonPopup.tsx +++ b/src/components/Search/FilterDropdowns/CommonPopup.tsx @@ -8,13 +8,15 @@ import type {PopoverComponentProps} from './FilterPopupButton'; type CommonPopupProps = { filterKey: FilterComponentsProps['filterKey']; value: FilterComponentsProps['value']; + type: FilterComponentsProps['type']; + policyIDs: FilterComponentsProps['policyIDs']; label: string; policyIDQuery: string[] | undefined; closeOverlay: PopoverComponentProps['closeOverlay']; updateFilterForm: (value: Partial) => void; }; -function CommonPopup({filterKey, value: initialValue, label, policyIDQuery, updateFilterForm, closeOverlay}: CommonPopupProps) { +function CommonPopup({filterKey, value: initialValue, type, policyIDs, label, policyIDQuery, updateFilterForm, closeOverlay}: CommonPopupProps) { const [value, setValue] = useState(initialValue); const applyChanges = () => { @@ -38,6 +40,8 @@ function CommonPopup({filterKey, value: initialValue, label, policyIDQuery, upda diff --git a/src/components/Search/SearchPageHeader/useSearchFiltersBar.tsx b/src/components/Search/SearchPageHeader/useSearchFiltersBar.tsx index 8677e1f44990..5e666863e241 100644 --- a/src/components/Search/SearchPageHeader/useSearchFiltersBar.tsx +++ b/src/components/Search/SearchPageHeader/useSearchFiltersBar.tsx @@ -103,6 +103,8 @@ function FilterPopup({filterKey, searchAdvancedFiltersForm, queryJSON, closeOver value.includes(card.cardID.toString())) diff --git a/src/components/Search/hooks/useFilterTaxRateValue.tsx b/src/components/Search/hooks/useFilterTaxRateValue.tsx index 52bd2fba66d9..f115542c0f61 100644 --- a/src/components/Search/hooks/useFilterTaxRateValue.tsx +++ b/src/components/Search/hooks/useFilterTaxRateValue.tsx @@ -1,19 +1,27 @@ -import useAdvancedSearchFilters from '@hooks/useAdvancedSearchFilters'; +import type {OnyxCollection} from 'react-native-onyx'; +import useOnyx from '@hooks/useOnyx'; import {getAllTaxRates} from '@libs/PolicyUtils'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Policy} from '@src/types/onyx'; -function useFilterTaxRateValue(value: string[]): string { - const {policies} = useAdvancedSearchFilters(); - - const taxRates = getAllTaxRates(policies); - const result: string[] = []; - for (const [taxRateName, taxRateKeys] of Object.entries(taxRates)) { - if (!taxRateKeys.some((taxRateKey) => value.includes(taxRateKey)) || result.includes(taxRateName)) { - continue; +function taxRatesPoliciesSelector(value: string[]) { + return (policies: OnyxCollection) => { + const taxRates = getAllTaxRates(policies); + const result: string[] = []; + for (const [taxRateName, taxRateKeys] of Object.entries(taxRates)) { + if (!taxRateKeys.some((taxRateKey) => value.includes(taxRateKey)) || result.includes(taxRateName)) { + continue; + } + result.push(taxRateName); } - result.push(taxRateName); + + return result.join(', '); } +} - return result.join(', '); +function useFilterTaxRateValue(value: string[]): string { + const [taxRateValue = ''] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: taxRatesPoliciesSelector(value)}); + return taxRateValue; } export default useFilterTaxRateValue; diff --git a/src/hooks/useAdvancedSearchFilters.ts b/src/hooks/useAdvancedSearchFilters.ts index 72a092b9d740..ad2d9460da4a 100644 --- a/src/hooks/useAdvancedSearchFilters.ts +++ b/src/hooks/useAdvancedSearchFilters.ts @@ -1,13 +1,13 @@ import {filterCardsHiddenFromSearch} from '@selectors/Card'; import passthroughPolicyTagListSelector from '@selectors/PolicyTagList'; import {emailSelector} from '@selectors/Session'; -import type {OnyxCollection} from 'react-native-onyx'; -import {getAllTaxRates, isPolicyFeatureEnabled} from '@libs/PolicyUtils'; +import type {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import {isPolicyFeatureEnabled} from '@libs/PolicyUtils'; import {getAllPolicyValues} from '@libs/SearchQueryUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {SearchAdvancedFiltersForm} from '@src/types/form'; -import type {Policy, PolicyCategories, PolicyTagLists} from '@src/types/onyx'; +import type {CardList, Policy, PolicyCategories, PolicyTagLists} from '@src/types/onyx'; +import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; import {getEmptyObject} from '@src/types/utils/EmptyObject'; import useLocalize from './useLocalize'; import useOnyx from './useOnyx'; @@ -296,22 +296,8 @@ const hasTagsSelector = (allPolicyTagLists: OnyxCollection) => { return false; }; -function useAdvancedSearchFilters() { +function useAdvancedSearchFiltersWorkspaces(policies: OnyxCollection) { const {localeCompare} = useLocalize(); - const [searchAdvancedFilters = getEmptyObject()] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); - const policyID = searchAdvancedFilters.policyID; - const [searchCards] = useOnyx(ONYXKEYS.DERIVED.PERSONAL_AND_WORKSPACE_CARD_LIST, {selector: filterCardsHiddenFromSearch}); - const [policies = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: advancedSearchPoliciesSelector}); - const [policyDerived] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: policyDerivedSelector}); - const [allPolicyCategories = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES, { - selector: availablePolicyCategoriesSelector, - }); - const taxRates = getAllTaxRates(policies); - const selectedPolicyCategories = getAllPolicyValues(policyID, ONYXKEYS.COLLECTION.POLICY_CATEGORIES, allPolicyCategories); - const [allPolicyTagLists = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS, {selector: passthroughPolicyTagListSelector}); - const selectedPolicyTagLists = getAllPolicyValues(policyID, ONYXKEYS.COLLECTION.POLICY_TAGS, allPolicyTagLists); - const [hasTags] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS, {selector: hasTagsSelector}); - const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector}); const {sections: workspaces, shouldShowSearchInput: shouldShowWorkspaceSearchInput} = useWorkspaceList({ @@ -323,6 +309,27 @@ function useAdvancedSearchFilters() { localeCompare, }); + return {workspaces, shouldShowWorkspaceSearchInput}; +} + +function shouldDisplayCardFilterSelector(cardList: OnyxEntry) { + return shouldDisplayFilter(Object.keys(filterCardsHiddenFromSearch(cardList)).length, true); +} + +function useAdvancedSearchFilters(type: SearchDataTypes | undefined, policyID: string[] | undefined) { + const [shouldDisplayCardFilter] = useOnyx(ONYXKEYS.DERIVED.PERSONAL_AND_WORKSPACE_CARD_LIST, {selector: shouldDisplayCardFilterSelector}); + const [policies = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: advancedSearchPoliciesSelector}); + const [policyDerived] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: policyDerivedSelector}); + const [allPolicyCategories = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY_CATEGORIES, { + selector: availablePolicyCategoriesSelector, + }); + const selectedPolicyCategories = getAllPolicyValues(policyID, ONYXKEYS.COLLECTION.POLICY_CATEGORIES, allPolicyCategories); + const [allPolicyTagLists = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS, {selector: passthroughPolicyTagListSelector}); + const selectedPolicyTagLists = getAllPolicyValues(policyID, ONYXKEYS.COLLECTION.POLICY_TAGS, allPolicyTagLists); + const [hasTags] = useOnyx(ONYXKEYS.COLLECTION.POLICY_TAGS, {selector: hasTagsSelector}); + + const {workspaces} = useAdvancedSearchFiltersWorkspaces(policies); + // When looking if a user has any categories to display, we want to ignore the policies that are of type PERSONAL const hasNonPersonalPolicyCategories = Object.keys(allPolicyCategories).some((policyCategoryId) => { const categoryPolicyID = policyCategoryId.replace(ONYXKEYS.COLLECTION.POLICY_CATEGORIES, ''); @@ -332,58 +339,49 @@ function useAdvancedSearchFilters() { const shouldDisplayCategoryFilter = shouldDisplayFilter(hasNonPersonalPolicyCategories ? 1 : 0, policyDerived?.areCategoriesEnabled ?? false, selectedPolicyCategories?.length > 0); const shouldDisplayTagFilter = shouldDisplayFilter(hasTags ? 1 : 0, policyDerived?.areTagsEnabled ?? false, !!selectedPolicyTagLists); - const shouldDisplayCardFilter = shouldDisplayFilter(Object.keys(searchCards ?? {}).length, true); const shouldDisplayTaxFilter = shouldDisplayFilter(policyDerived?.hasAnyTaxRates ? 1 : 0, policyDerived?.areTaxEnabled ?? false); const shouldDisplayWorkspaceFilter = workspaces.some((section) => section.data.length > 1); - let currentType = searchAdvancedFilters?.type ?? CONST.SEARCH.DATA_TYPES.EXPENSE; + let currentType = type ?? CONST.SEARCH.DATA_TYPES.EXPENSE; if (!(currentType in typeFiltersKeys)) { currentType = CONST.SEARCH.DATA_TYPES.EXPENSE; } - return { - currentType, - workspaces, - shouldShowWorkspaceSearchInput, - taxRates, - searchCards, - policies, - typeFiltersKeys: typeFiltersKeys[currentType] - .map((section) => - section - .map((key) => { - if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY && !shouldDisplayCategoryFilter) { - return; - } - if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG && !shouldDisplayTagFilter) { - return; - } - if ( - (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID || key === CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED || key === CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED) && - !shouldDisplayCardFilter - ) { - return; - } - if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE && !shouldDisplayTaxFilter) { - return; - } - if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID && !shouldDisplayWorkspaceFilter) { - return; - } - if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE && !(policyDerived?.isAttendeeTrackingEnabled ?? true)) { - return; - } - if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_FIELD && !(policyDerived?.hasReportFields ?? false)) { - return; - } - return key; - }) - .filter((filter): filter is NonNullable => !!filter), - ) - .filter((section) => !!section.length), - }; + return typeFiltersKeys[currentType] + .map((section) => + section + .map((key) => { + if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY && !shouldDisplayCategoryFilter) { + return; + } + if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG && !shouldDisplayTagFilter) { + return; + } + if ( + (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID || key === CONST.SEARCH.SYNTAX_FILTER_KEYS.POSTED || key === CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED) && + !shouldDisplayCardFilter + ) { + return; + } + if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE && !shouldDisplayTaxFilter) { + return; + } + if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID && !shouldDisplayWorkspaceFilter) { + return; + } + if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE && !(policyDerived?.isAttendeeTrackingEnabled ?? true)) { + return; + } + if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_FIELD && !(policyDerived?.hasReportFields ?? false)) { + return; + } + return key; + }) + .filter((filter): filter is NonNullable => !!filter), + ) + .filter((section) => !!section.length); } export default useAdvancedSearchFilters; -export {advancedSearchPoliciesSelector}; +export {useAdvancedSearchFiltersWorkspaces, advancedSearchPoliciesSelector}; diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx index 0e305421e634..c55ebec90346 100644 --- a/src/pages/Search/AdvancedSearchFilters.tsx +++ b/src/pages/Search/AdvancedSearchFilters.tsx @@ -10,7 +10,7 @@ import ScrollView from '@components/ScrollView'; import type {SearchAmountFilterKeys, SearchDateFilterKeys, SearchFilterKey} from '@components/Search/types'; import SpacerView from '@components/SpacerView'; import Text from '@components/Text'; -import useAdvancedSearchFilters from '@hooks/useAdvancedSearchFilters'; +import useAdvancedSearchFilters, {advancedSearchPoliciesSelector, useAdvancedSearchFiltersWorkspaces} from '@hooks/useAdvancedSearchFilters'; import {useCurrencyListActions} from '@hooks/useCurrencyList'; import type {CurrencyListActionsContextType} from '@hooks/useCurrencyList'; import useLocalize from '@hooks/useLocalize'; @@ -23,7 +23,7 @@ import {createCardFeedKey, getCardFeedKey, getCardFeedNamesWithType, getFeedCoun import {getCardDescription} from '@libs/CardUtils'; import Navigation from '@libs/Navigation/Navigation'; import {createDisplayName} from '@libs/PersonalDetailsUtils'; -import {getCleanedTagName} from '@libs/PolicyUtils'; +import {getAllTaxRates, getCleanedTagName} from '@libs/PolicyUtils'; import {getReportName} from '@libs/ReportNameUtils'; import { buildCannedSearchQuery, @@ -40,6 +40,7 @@ import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import {filterCardsHiddenFromSearch} from '@src/selectors/Card'; import type {SearchAdvancedFiltersForm} from '@src/types/form'; import {AMOUNT_FILTER_KEYS, DATE_FILTER_KEYS} from '@src/types/form/SearchAdvancedFiltersForm'; import type {CardList, PersonalDetailsList, Policy, Report, ReportAttributesDerivedValue, WorkspaceCardsList} from '@src/types/onyx'; @@ -601,11 +602,16 @@ function AdvancedSearchFilters() { const {singleExecution} = useSingleExecution(); const waitForNavigate = useWaitForNavigation(); const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); + const [policies = getEmptyObject>>()] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {selector: advancedSearchPoliciesSelector}); const [searchAdvancedFilters = getEmptyObject()] = useOnyx(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM); + const [searchCards] = useOnyx(ONYXKEYS.DERIVED.PERSONAL_AND_WORKSPACE_CARD_LIST, {selector: filterCardsHiddenFromSearch}); const personalDetails = usePersonalDetails(); const [reportAttributes] = useOnyx(ONYXKEYS.DERIVED.REPORT_ATTRIBUTES); - const {currentType, typeFiltersKeys, workspaces, taxRates, searchCards, policies} = useAdvancedSearchFilters(); + const typeFiltersKeys = useAdvancedSearchFilters(searchAdvancedFilters.type, searchAdvancedFilters.policyID); + const currentType = searchAdvancedFilters.type; + const {workspaces} = useAdvancedSearchFiltersWorkspaces(policies); + const taxRates = getAllTaxRates(policies); const queryString = useMemo(() => { const currentQueryJSON = getCurrentSearchQueryJSON(); diff --git a/tests/perf-test/useAdvancedSearchFilters.perf-test.tsx b/tests/perf-test/useAdvancedSearchFilters.perf-test.tsx index b2167af5f270..e8fd48a10b65 100644 --- a/tests/perf-test/useAdvancedSearchFilters.perf-test.tsx +++ b/tests/perf-test/useAdvancedSearchFilters.perf-test.tsx @@ -69,7 +69,8 @@ jest.mock('@react-navigation/native', () => { }); function TestComponent() { - const {currentType, typeFiltersKeys: filters} = useAdvancedSearchFilters(); + const currentType = 'expense'; + const filters = useAdvancedSearchFilters(currentType, undefined); return ; } diff --git a/tests/unit/hooks/useAdvancedSearchFilters.test.ts b/tests/unit/hooks/useAdvancedSearchFilters.test.ts index 93bb82d50494..e5628a05a744 100644 --- a/tests/unit/hooks/useAdvancedSearchFilters.test.ts +++ b/tests/unit/hooks/useAdvancedSearchFilters.test.ts @@ -100,10 +100,10 @@ describe('useAdvancedSearchFilters', () => { const policy = buildPolicy(1, {areCategoriesEnabled: false}); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).not.toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY); }); }); @@ -117,10 +117,10 @@ describe('useAdvancedSearchFilters', () => { }; await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}1`, categories); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY); }); }); @@ -137,10 +137,10 @@ describe('useAdvancedSearchFilters', () => { }; await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}1`, categories); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).not.toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY); }); }); @@ -151,10 +151,10 @@ describe('useAdvancedSearchFilters', () => { const policy = buildPolicy(1, {areTagsEnabled: false}); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).not.toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG); }); }); @@ -164,10 +164,10 @@ describe('useAdvancedSearchFilters', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY_TAGS}1`, buildTagList('Engineering')); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG); }); }); @@ -186,11 +186,11 @@ describe('useAdvancedSearchFilters', () => { }; await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY_TAGS}1`, emptyTagList); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); // Tag filter is visible because singlePolicyCondition (!!selectedPolicyTagLists) is always true await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG); }); }); @@ -201,10 +201,10 @@ describe('useAdvancedSearchFilters', () => { const policy = buildPolicy(1, {tax: {trackingEnabled: false}}); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).not.toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE); }); }); @@ -224,10 +224,10 @@ describe('useAdvancedSearchFilters', () => { }); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE); }); }); @@ -245,10 +245,10 @@ describe('useAdvancedSearchFilters', () => { }); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).not.toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE); }); }); @@ -259,10 +259,10 @@ describe('useAdvancedSearchFilters', () => { const policy = buildPolicy(1, {type: CONST.POLICY.TYPE.CORPORATE, isAttendeeTrackingEnabled: false}); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).not.toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE); }); }); @@ -273,10 +273,10 @@ describe('useAdvancedSearchFilters', () => { delete (policy as Record).isAttendeeTrackingEnabled; await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE); }); }); @@ -285,10 +285,10 @@ describe('useAdvancedSearchFilters', () => { const policy = buildPolicy(1, {type: CONST.POLICY.TYPE.CORPORATE, isAttendeeTrackingEnabled: true}); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.ATTENDEE); }); }); @@ -299,10 +299,10 @@ describe('useAdvancedSearchFilters', () => { const policy = buildPolicy(1, {fieldList: {}}); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).not.toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_FIELD); }); }); @@ -329,10 +329,10 @@ describe('useAdvancedSearchFilters', () => { }); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_FIELD); }); }); @@ -359,35 +359,15 @@ describe('useAdvancedSearchFilters', () => { }); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}1`, policy); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).not.toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_FIELD); }); }); }); - describe('currentType', () => { - it('defaults to expense when no type is set', async () => { - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); - - await waitFor(() => { - expect(result.current.currentType).toBe(CONST.SEARCH.DATA_TYPES.EXPENSE); - }); - }); - - it('uses the type from search filters form', async () => { - await Onyx.merge(ONYXKEYS.FORMS.SEARCH_ADVANCED_FILTERS_FORM, {type: CONST.SEARCH.DATA_TYPES.CHAT}); - - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); - - await waitFor(() => { - expect(result.current.currentType).toBe(CONST.SEARCH.DATA_TYPES.CHAT); - }); - }); - }); - describe('cross-feature interaction', () => { it('shows multiple filters when multiple features are enabled', async () => { const policy = buildPolicy(1, { @@ -414,10 +394,10 @@ describe('useAdvancedSearchFilters', () => { await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}1`, categories); await Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY_TAGS}1`, buildTagList('Engineering')); - const {result} = renderHook(() => useAdvancedSearchFilters(), {wrapper}); + const {result} = renderHook(() => useAdvancedSearchFilters(undefined, undefined), {wrapper}); await waitFor(() => { - const allKeys = result.current.typeFiltersKeys.flat(); + const allKeys = result.current.flat(); expect(allKeys).toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY); expect(allKeys).toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG); expect(allKeys).toContain(CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE);