Skip to content

Commit 8830cac

Browse files
authored
Merge pull request Expensify#75638 from TaduJR/feat-Add-an-exposed-filter-for-workspace-when-a-user-is-a-member-of-several-workspaces
feat: [CFI] Add an exposed filter for workspace when a user is a member of several workspaces
2 parents 65929b4 + fecd3bc commit 8830cac

File tree

3 files changed

+58
-4
lines changed

3 files changed

+58
-4
lines changed

src/components/Search/FilterDropdowns/DropdownButton.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,7 @@ function DropdownButton({label, value, viewportOffsetTop, PopoverComponent}: Dro
105105

106106
const popoverContent = useMemo(() => {
107107
return PopoverComponent({closeOverlay: toggleOverlay});
108-
// PopoverComponent is stable so we don't need it here as a dep.
109-
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
110-
}, [toggleOverlay]);
108+
}, [PopoverComponent, toggleOverlay]);
111109

112110
return (
113111
<View ref={anchorRef}>

src/components/Search/SearchPageHeader/SearchFiltersBar.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import usePolicy from '@hooks/usePolicy';
3737
import useResponsiveLayout from '@hooks/useResponsiveLayout';
3838
import useTheme from '@hooks/useTheme';
3939
import useThemeStyles from '@hooks/useThemeStyles';
40+
import useWorkspaceList from '@hooks/useWorkspaceList';
4041
import {close} from '@libs/actions/Modal';
4142
import {handleBulkPayItemSelected, updateAdvancedFilters} from '@libs/actions/Search';
4243
import {mergeCardListWithWorkspaceFeeds} from '@libs/CardUtils';
@@ -116,6 +117,29 @@ function SearchFiltersBar({
116117
const expensifyIcons = useMemoizedLazyExpensifyIcons(['Filter'] as const);
117118

118119
const taxRates = getAllTaxRates(allPolicies);
120+
121+
// Get workspace data for the filter
122+
const {sections: workspaces} = useWorkspaceList({
123+
policies: allPolicies,
124+
currentUserLogin: email,
125+
shouldShowPendingDeletePolicy: false,
126+
selectedPolicyIDs: undefined,
127+
searchTerm: '',
128+
localeCompare,
129+
});
130+
131+
const shouldDisplayWorkspaceFilter = useMemo(() => workspaces.some((section) => section.data.length > 1), [workspaces]);
132+
133+
const workspaceOptions = useMemo<Array<MultiSelectItem<string>>>(() => {
134+
return workspaces
135+
.flatMap((section) => section.data)
136+
.filter((workspace): workspace is typeof workspace & {policyID: string} => !!workspace.policyID)
137+
.map((workspace) => ({
138+
text: workspace.text,
139+
value: workspace.policyID,
140+
}));
141+
}, [workspaces]);
142+
119143
const allCards = useMemo(() => mergeCardListWithWorkspaceFeeds(workspaceCardFeeds ?? CONST.EMPTY_OBJECT, userCardList), [userCardList, workspaceCardFeeds]);
120144
const selectedTransactionsKeys = useMemo(() => Object.keys(selectedTransactions ?? {}), [selectedTransactions]);
121145
const hasMultipleOutputCurrency = useMemo(() => {
@@ -128,6 +152,16 @@ function SearchFiltersBar({
128152
return buildFilterFormValuesFromQuery(queryJSON, policyCategories, policyTagsLists, currencyList, personalDetails, allCards, reports, taxRates);
129153
}, [allCards, currencyList, personalDetails, policyCategories, policyTagsLists, queryJSON, reports, taxRates]);
130154

155+
// Get selected workspace options from filterFormValues or queryJSON
156+
const selectedWorkspaceOptions = useMemo(() => {
157+
const policyIDs = filterFormValues.policyID ?? queryJSON.policyID;
158+
if (!policyIDs) {
159+
return [];
160+
}
161+
const normalizedIDs = Array.isArray(policyIDs) ? policyIDs : [policyIDs];
162+
return workspaceOptions.filter((option) => normalizedIDs.includes(option.value));
163+
}, [filterFormValues.policyID, queryJSON.policyID, workspaceOptions]);
164+
131165
const hasErrors = Object.keys(searchResultsErrors ?? {}).length > 0 && !isOffline;
132166
const shouldShowSelectedDropdown = headerButtonsOptions.length > 0 && (!shouldUseNarrowLayout || isMobileSelectionModeEnabled);
133167

@@ -475,6 +509,15 @@ function SearchFiltersBar({
475509
[filterFormValues.from, updateFilterForm],
476510
);
477511

512+
const workspaceComponent = useMemo(() => {
513+
const updateWorkspaceFilterForm = (items: Array<MultiSelectItem<string>>) => {
514+
updateFilterForm({policyID: items.map((item) => item.value)});
515+
};
516+
return createMultiSelectComponent('workspace.common.workspace', workspaceOptions, selectedWorkspaceOptions, updateWorkspaceFilterForm);
517+
}, [createMultiSelectComponent, workspaceOptions, selectedWorkspaceOptions, updateFilterForm]);
518+
519+
const workspaceValue = useMemo(() => selectedWorkspaceOptions.map((option) => option.text), [selectedWorkspaceOptions]);
520+
478521
const {typeFiltersKeys} = useAdvancedSearchFilters();
479522

480523
/**
@@ -596,6 +639,16 @@ function SearchFiltersBar({
596639
value: fromValue,
597640
filterKey: FILTER_KEYS.FROM,
598641
},
642+
...(shouldDisplayWorkspaceFilter
643+
? [
644+
{
645+
label: translate('workspace.common.workspace'),
646+
PopoverComponent: workspaceComponent,
647+
value: workspaceValue,
648+
filterKey: FILTER_KEYS.POLICY_ID,
649+
},
650+
]
651+
: []),
599652
].filter((filterItem) => isFilterSupported(filterItem.filterKey, type?.value ?? CONST.SEARCH.DATA_TYPES.EXPENSE));
600653

601654
return filterList;
@@ -636,6 +689,9 @@ function SearchFiltersBar({
636689
hasMultipleOutputCurrency,
637690
has,
638691
is,
692+
shouldDisplayWorkspaceFilter,
693+
workspaceComponent,
694+
workspaceValue,
639695
]);
640696

641697
const hiddenSelectedFilters = useMemo(() => {

src/hooks/useAdvancedSearchFilters.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ function useAdvancedSearchFilters() {
259259
const shouldDisplayTagFilter = shouldDisplayFilter(tagListsUnpacked.length, areTagsEnabled, !!selectedPolicyTagLists);
260260
const shouldDisplayCardFilter = shouldDisplayFilter(Object.keys(allCards).length, areCardsEnabled);
261261
const shouldDisplayTaxFilter = shouldDisplayFilter(Object.keys(taxRates).length, areTaxEnabled);
262-
const shouldDisplayWorkspaceFilter = workspaces.some((section) => section.data.length !== 0);
262+
const shouldDisplayWorkspaceFilter = workspaces.some((section) => section.data.length > 1);
263263
const shouldDisplayGroupByFilter = !!groupBy;
264264
const shouldDisplayGroupCurrencyFilter = shouldDisplayGroupByFilter;
265265
const shouldDisplayReportFieldFilter = Object.values(policies).some((policy): policy is NonNullable<Policy> => {

0 commit comments

Comments
 (0)