Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
146 commits
Select commit Hold shift + click to select a range
5e04a97
Add bankAccount SYNTAX_FILTER_KEYS entries
allgandalf May 15, 2026
3becfee
Add bank account RHP screen constant
allgandalf May 15, 2026
f5de9fd
Add bankAccount filter key to form types
allgandalf May 15, 2026
f185a84
Map bank account RHP screen to filter route
allgandalf May 15, 2026
c643533
Register bank account RHP in SEARCH_TO_RHP relations
allgandalf May 15, 2026
2e3e735
Register bank account RHP screen in ModalStackNavigator
allgandalf May 15, 2026
12f0383
Add SearchFiltersBankAccountPage component
allgandalf May 15, 2026
3e63d3d
Show bank account row in advanced filters list
allgandalf May 15, 2026
21b128c
Gate bank account filter row to expense type with bank accounts
allgandalf May 15, 2026
0795430
Serialize bankAccount filter to query string
allgandalf May 15, 2026
4bed07b
Parse bankAccount filter from jsonQuery into form values
allgandalf May 15, 2026
d43728b
Render bankAccount filter chip display value
allgandalf May 15, 2026
16fc975
Add bankAccount to peggy baseRules
allgandalf May 15, 2026
aaade06
Add bankAccount to search and autocomplete parser grammars
allgandalf May 15, 2026
4becdd8
Regenerate parser artifacts for bankAccount
allgandalf May 15, 2026
1d25a34
Add bankAccount to autocomplete substitution map
allgandalf May 15, 2026
cef8778
Handle bankAccount in isValidAutocompleteRange
allgandalf May 15, 2026
36c6544
Suggest bank accounts in autocomplete dropdown
allgandalf May 15, 2026
f3f6b5b
Add BankAccountSelector chip popover component
allgandalf May 15, 2026
3e970cb
Map BankAccount filter to BankAccountSelector
allgandalf May 15, 2026
5c261cf
Render bank account chip on search filter bar
allgandalf May 15, 2026
2af656d
Add bankAccount to FILTER_LABEL_MAP
allgandalf May 15, 2026
69a7541
Add SearchQueryUtilsTest case for bankAccount filter
allgandalf May 15, 2026
3e879ab
Add SearchParserTest case for bankAccount filter
allgandalf May 15, 2026
e6bad71
Add SearchAutocompleteParserTest case for bankAccount
allgandalf May 15, 2026
09b634f
Add SearchAutocompleteUtilsTest cases for bankAccount
allgandalf May 15, 2026
0f9ddc2
Add useAdvancedSearchFilters bank account gating tests
allgandalf May 15, 2026
5e1035a
Fix bankName indexing types in SearchQueryUtils
allgandalf May 15, 2026
f9ae792
Fix types in SearchFiltersBankAccountPage
allgandalf May 15, 2026
6235fff
Fix types in BankAccountSelector
allgandalf May 15, 2026
1fafd5b
Fix bankName type in useAutocompleteSuggestions
allgandalf May 15, 2026
59efdf1
Fix bankName type in useFilterBankAccountValue
allgandalf May 15, 2026
f2d4040
Use nullish coalescing for formattedBankName in BankAccountSelector
allgandalf May 15, 2026
fd266f4
Use nullish coalescing for formattedBankName in useFilterBankAccountV…
allgandalf May 15, 2026
e78057a
Use nullish coalescing for formattedBankName in useAutocompleteSugges…
allgandalf May 15, 2026
d0329d2
Use nullish coalescing for formattedBankName in SearchQueryUtils
allgandalf May 15, 2026
4bbf120
Use nullish coalescing for formattedBankName in SearchFiltersBankAcco…
allgandalf May 15, 2026
dca6f7b
Use localeCompare from useLocalize in bank account autocomplete sort
allgandalf May 15, 2026
ad0f065
Read localeCompare from useLocalize inside useAutocompleteSuggestions
allgandalf May 15, 2026
a01cec2
Use computed key for bankAccountID in test fixtures
allgandalf May 15, 2026
dda71ee
Disable max-params lint on buildSubstitutionsMap
allgandalf May 15, 2026
f30d07d
Merge main into add-bank-account-search-filter
allgandalf May 18, 2026
4770a01
Reorder buildFilterFormValuesFromQuery params and disable max-params
allgandalf May 18, 2026
245823d
Merge branch 'Expensify:main' into add-bank-account-search-filter
allgandalf May 22, 2026
51b5487
Merge branch 'Expensify:main' into add-bank-account-search-filter
allgandalf May 23, 2026
19f5107
Add getBankAccountSearchLabel util in BankAccountUtils
allgandalf May 23, 2026
65501dd
Use getBankAccountSearchLabel in BankAccountSelector
allgandalf May 23, 2026
3582237
Use getBankAccountSearchLabel in useFilterBankAccountValue
allgandalf May 23, 2026
872d111
Use getBankAccountSearchLabel in SearchFiltersBankAccountPage
allgandalf May 23, 2026
704a2d9
Use getBankAccountSearchLabel in useAutocompleteSuggestions
allgandalf May 23, 2026
42403d1
Use getBankAccountSearchLabel in SearchQueryUtils getFilterDisplayValue
allgandalf May 23, 2026
a78a13e
Justify max-params disable on buildSubstitutionsMap
allgandalf May 23, 2026
2f8abec
Justify max-params disable on buildFilterFormValuesFromQuery
allgandalf May 23, 2026
5a2f7b2
Restore CONST import in BankAccountSelector after refactor
allgandalf May 23, 2026
8038d1a
Render bank account labels in advanced filter list row
allgandalf May 25, 2026
4eff095
Drop FilterKey suffix from peggy bankAccount rule
allgandalf May 25, 2026
e423cd5
Merge main into add-bank-account-search-filter
allgandalf May 25, 2026
94e8c34
Sync Mobile-Expensify submodule pointer with main
allgandalf May 25, 2026
b03ea71
Extend BankAccountSelector props with SearchFilterSelectionListProps
allgandalf May 26, 2026
24f067d
Pass footer through BankAccountSelector to render mobile Confirm button
allgandalf May 26, 2026
f4f94f3
Pass autoFocus through BankAccountSelector
allgandalf May 26, 2026
30984eb
Pass selectionListTextInputStyle through BankAccountSelector
allgandalf May 26, 2026
d061a0f
Pass selectionListStyle through BankAccountSelector
allgandalf May 26, 2026
8b64b01
Pass searchPlaceholder through BankAccountSelector
allgandalf May 26, 2026
75a8d55
Add JSDoc comments to BankAccountItem fields
allgandalf May 26, 2026
fb6a5a5
Accept bank-account user-friendly form in peggy bankAccount rule
allgandalf May 26, 2026
7cc2f60
Show loading indicator on SearchFiltersBankAccountPage while Onyx loads
allgandalf May 26, 2026
f49291f
Use kebab-case bank-account for user-friendly filter key
allgandalf May 26, 2026
a9248e8
Pass bankAccountList to buildUserReadableQueryString in SearchAutocom…
allgandalf May 26, 2026
72bbf79
Pass bankAccountList to buildUserReadableQueryString from saved searc…
allgandalf May 26, 2026
3f87f92
Merge remote-tracking branch 'origin/main' into add-bank-account-sear…
allgandalf May 26, 2026
60d719a
Include bankAccountList in useMemo deps for SearchAutocompleteList
allgandalf May 26, 2026
bfe5e75
Merge upstream/main into add-bank-account-search-filter
allgandalf May 26, 2026
f1e9111
Align BankAccountSelector and loading spinner with upstream MultiSele…
allgandalf May 26, 2026
c4501fd
Sync Mobile-Expensify submodule pointer with main
allgandalf Jun 1, 2026
9d59abe
Merge remote-tracking branch 'upstream/main' into add-bank-account-se…
allgandalf Jun 1, 2026
be652ec
Add isSearchEligibleBankAccount + getSearchEligibleBankAccounts util
allgandalf Jun 3, 2026
d27e79f
Filter SearchFiltersBankAccountPage picker to settlement-eligible ban…
allgandalf Jun 3, 2026
f49cf89
Filter BankAccountSelector chip popover to settlement-eligible bank a…
allgandalf Jun 3, 2026
c171c63
Filter useAutocompleteSuggestions to settlement-eligible bank accounts
allgandalf Jun 3, 2026
4829c93
Filter useFilterBankAccountValue chip label to settlement-eligible ba…
allgandalf Jun 3, 2026
7e3a1d7
Gate SearchQueryUtils bank account paths on isSearchEligibleBankAccount
allgandalf Jun 3, 2026
d9208e5
Filter AdvancedSearchFilters bank account row title to settlement-eli…
allgandalf Jun 3, 2026
68a0bdc
Gate shouldDisplayBankAccountFilter on count of settlement-eligible a…
allgandalf Jun 3, 2026
5d17fda
Test BANK_ACCOUNT row gating against settlement-eligible predicate
allgandalf Jun 3, 2026
33ca711
Pin selected bank accounts to top of picker to match Card filter
allgandalf Jun 3, 2026
677ec68
Merge branch 'Expensify:main' into add-bank-account-search-filter
allgandalf Jun 4, 2026
279c429
Validate bankAccount filter on presence only so saved searches surviv…
allgandalf Jun 4, 2026
101c7a3
Render bankAccount filter label on presence only in user-readable query
allgandalf Jun 4, 2026
2ba2765
Render bankAccount filter list title on presence only
allgandalf Jun 4, 2026
19547fa
Drop unused isSearchEligibleBankAccount export to satisfy knip
allgandalf Jun 4, 2026
0acb06e
Drop coined word from bankAccount filter comment to satisfy spellcheck
allgandalf Jun 4, 2026
230c4e2
Merge branch 'Expensify:main' into add-bank-account-search-filter
allgandalf Jun 7, 2026
17a378b
i18n: add bank-account filter section titles
allgandalf Jun 9, 2026
ef013e4
Export isSearchEligibleBankAccount for the closed-banks picker section
allgandalf Jun 9, 2026
673c062
i18n: localize bank-account filter section titles
allgandalf Jun 9, 2026
dfad6af
Show closed bank accounts in search filter picker
allgandalf Jun 9, 2026
b6b5785
Hoist picker into a child component so initial selection loads from a…
allgandalf Jun 9, 2026
82b49f0
Merge remote-tracking branch 'origin/add-bank-account-search-filter' …
allgandalf Jun 9, 2026
1a54f7f
Merge branch 'Expensify:main' into add-bank-account-search-filter
allgandalf Jun 10, 2026
b0588db
Apply Polyglot Parrot translations for bank-account filter sections
allgandalf Jun 10, 2026
abecb69
Merge remote-tracking branch 'upstream/main' into add-bank-account-se…
allgandalf Jun 16, 2026
e8c320f
Resolve filter-bar pill label from full bankAccountList so closed sel…
allgandalf Jun 16, 2026
f8a93c7
Resolve filter-bar popover picker from full bankAccountList so closed…
allgandalf Jun 16, 2026
4e181ec
Preserve bank-account filter IDs while Onyx list is loading
allgandalf Jun 16, 2026
fb368b2
Show bank-account filter row when user has any business account, open…
allgandalf Jun 16, 2026
860215b
Document BankAccountPicker props with JSDoc
allgandalf Jun 16, 2026
0af3ff7
Drop redundant useCallback on buildItem
allgandalf Jun 16, 2026
874c769
Drop redundant useMemo on openItems and closedItems
allgandalf Jun 16, 2026
10b399f
Drop redundant useCallback on searchFilter
allgandalf Jun 16, 2026
ffadf3b
Drop redundant useMemo on sections
allgandalf Jun 16, 2026
1716f3b
Bump eslint-seatbelt baseline for bank-account additions
allgandalf Jun 16, 2026
dd00bbc
Drop duplicate FinancialForce write-command keys from API/types.ts me…
allgandalf Jun 16, 2026
88f504e
Restore Mobile-Expensify pointer to PR base so submodule diff is empty
allgandalf Jun 16, 2026
24a0da7
Merge remote-tracking branch 'upstream/main' into add-bank-account-se…
allgandalf Jun 17, 2026
14da041
Restore Mobile-Expensify pointer to PR base after main merge
allgandalf Jun 17, 2026
3a4ffa4
Adapt BankAccountSelector to new generic SearchFilterCommonProps
allgandalf Jun 17, 2026
c8fb6fb
Resync Mobile-Expensify pointer with current main tip
allgandalf Jun 17, 2026
91ed111
refactor BankAccountSelector to sectioned picker mirroring CardSelector
allgandalf Jun 17, 2026
ceaa434
drop dead SearchFiltersBankAccountPage and its route registration
allgandalf Jun 17, 2026
ad84a77
suggest closed business accounts in autocomplete to match the picker
allgandalf Jun 17, 2026
334e341
render bank account label on save search page instead of raw id
allgandalf Jun 17, 2026
24132a7
widen useFilterBankAccountValue to SearchFilter value and drop call s…
allgandalf Jun 17, 2026
3ba274a
Resync Mobile-Expensify pointer with current main tip
allgandalf Jun 17, 2026
7c07c96
Restore Mobile-Expensify pointer to merge-base value
allgandalf Jun 17, 2026
5141948
Drop unused isSearchEligibleBankAccount and getSearchEligibleBankAcco…
allgandalf Jun 17, 2026
88fe4dd
Normalize useFilterBankAccountValue to handle single-id string value
allgandalf Jun 19, 2026
e83ddb5
Merge remote-tracking branch 'upstream/main' into add-bank-account-se…
allgandalf Jun 19, 2026
86a8f2d
Bump eslint-seatbelt SearchQueryUtils count to 73 after main merge
allgandalf Jun 22, 2026
cca88b2
Pass bankAccount form value through getDisplayValue as array, not joi…
allgandalf Jun 22, 2026
557bcf4
Merge branch 'Expensify:main' into add-bank-account-search-filter
allgandalf Jun 22, 2026
49cad7a
Add common.bank translation key for generic bank label
allgandalf Jun 23, 2026
641f22f
Use common.bank in getBankAccountSearchLabel so generic label is loca…
allgandalf Jun 23, 2026
40c71bf
Localize bank-account translation values in 9 non-English locales
allgandalf Jun 23, 2026
ba04b29
Drop partially-setup bank account IDs at filter validation
allgandalf Jun 23, 2026
3f6385f
Merge remote-tracking branch 'upstream/main' into add-bank-account-se…
allgandalf Jun 23, 2026
8229a14
Revert "Localize bank-account translation values in 9 non-English loc…
allgandalf Jun 23, 2026
d22547f
Revert "Use common.bank in getBankAccountSearchLabel so generic label…
allgandalf Jun 23, 2026
199ec51
Revert "Add common.bank translation key for generic bank label"
allgandalf Jun 23, 2026
e5b31c2
Lowercase bankName before BANK_NAMES_USER_FRIENDLY lookup and add isF…
allgandalf Jun 26, 2026
532fc85
Use isFilterableBankAccount in advanced filter gate, picker, and auto…
allgandalf Jun 26, 2026
ee7ee61
Merge remote-tracking branch 'upstream/main' into add-bank-account-se…
allgandalf Jun 26, 2026
e58842f
Cast lowercased bankName to BANK_NAMES_USER_FRIENDLY key for type-saf…
allgandalf Jun 26, 2026
29a8a3e
Update bank-account visibility test: LOCKED shows filter, PENDING hid…
allgandalf Jun 26, 2026
1d7bbd0
Bump eslint-seatbelt for BankAccountUtils.ts cast to BANK_NAMES_USER_…
allgandalf Jun 27, 2026
894855b
Merge remote-tracking branch 'upstream/main' into add-bank-account-se…
allgandalf Jun 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions config/eslint/eslint.seatbelt.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@
"../../src/components/Search/SearchList/index.tsx" "@typescript-eslint/no-unsafe-type-assertion" 7
"../../src/components/Search/SearchMultipleSelectionPicker.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/components/Search/SearchPageHeader/SearchActionsBarCreateButton.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/components/Search/SearchPageHeader/SearchFilterBar.tsx" "@typescript-eslint/no-unsafe-type-assertion" 3
"../../src/components/Search/SearchPageHeader/SearchFilterBar.tsx" "@typescript-eslint/no-unsafe-type-assertion" 4
"../../src/components/Search/SearchPageHeader/useSearchFiltersBar.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/components/Search/SearchPageHeader/useSearchPageInput.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/components/Search/SearchPageHeader/useSearchPageInput.tsx" "react-hooks/set-state-in-effect" 2
Expand Down Expand Up @@ -578,6 +578,7 @@
"../../src/libs/Accessibility/moveAccessibilityFocus/types.ts" "@typescript-eslint/no-deprecated/ElementRef" 1
"../../src/libs/AccountingUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/libs/AttendeeUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 3
"../../src/libs/BankAccountUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/libs/Avatars/InitialAvatars.ts" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../src/libs/Avatars/PresetAvatarCatalog.ts" "@typescript-eslint/no-unsafe-type-assertion" 2
"../../src/libs/CardFeedUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 4
Expand Down Expand Up @@ -744,7 +745,7 @@
"../../src/libs/ReportUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 33
"../../src/libs/ReportUtils.ts" "rulesdir/no-onyx-connect" 16
"../../src/libs/SearchAutocompleteUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 4
"../../src/libs/SearchQueryUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 71
"../../src/libs/SearchQueryUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 73
"../../src/libs/SearchUIUtils.ts" "@typescript-eslint/no-unsafe-type-assertion" 69
"../../src/libs/SearchUIUtils.ts" "no-restricted-imports" 1
"../../src/libs/SelectionScraper/index.ts" "@typescript-eslint/no-unsafe-type-assertion" 4
Expand Down Expand Up @@ -1819,7 +1820,7 @@
"../../tests/unit/RequireA11yDisableJustificationRuleTest.ts" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../tests/unit/RequireLiveRegionForStatusUpdatesRuleTest.ts" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../tests/unit/Search/SearchListRenderCountTest.tsx" "@typescript-eslint/no-unsafe-type-assertion" 2
"../../tests/unit/Search/SearchQueryUtilsTest.ts" "@typescript-eslint/no-unsafe-type-assertion" 9
"../../tests/unit/Search/SearchQueryUtilsTest.ts" "@typescript-eslint/no-unsafe-type-assertion" 10
"../../tests/unit/Search/SearchSingleSelectionPickerTest.tsx" "@typescript-eslint/no-unsafe-type-assertion" 1
"../../tests/unit/Search/SearchUIUtilsTest.ts" "@typescript-eslint/no-unsafe-type-assertion" 136
"../../tests/unit/Search/buildCardFilterDataTest.ts" "@typescript-eslint/no-unsafe-type-assertion" 22
Expand Down
2 changes: 2 additions & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6804,6 +6804,7 @@ const CONST = {
TAX_RATE: 'taxRate',
CARD_ID: 'cardID',
FEED: 'feed',
BANK_ACCOUNT: 'bankAccount',
REPORT_ID: 'reportID',
KEYWORD: 'keyword',
IN: 'in',
Expand Down Expand Up @@ -6880,6 +6881,7 @@ const CONST = {
TAX_RATE: 'tax-rate',
CARD_ID: 'card',
FEED: 'feed',
BANK_ACCOUNT: 'bank-account',
REPORT_ID: 'report-id',
KEYWORD: 'keyword',
IN: 'in',
Expand Down
181 changes: 181 additions & 0 deletions src/components/Search/FilterComponents/BankAccountSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import React from 'react';
import {View} from 'react-native';
import ActivityIndicator from '@components/ActivityIndicator';
import Icon from '@components/Icon';
import getBankIcon from '@components/Icon/BankIcons';
import type {SearchFilterCommonProps} from '@components/Search/types';
import MultiSelectListItem from '@components/SelectionList/ListItem/MultiSelectListItem';
import SelectionListWithSections from '@components/SelectionList/SelectionListWithSections';
import type {TextInputOptions} from '@components/SelectionList/types';
import useDebouncedState from '@hooks/useDebouncedState';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import {getBankAccountSearchLabel, isFilterableBankAccount} from '@libs/BankAccountUtils';
import type {SkeletonSpanReasonAttributes} from '@libs/telemetry/useSkeletonSpan';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
import ListFilterView from './ListFilterViewWrapper';

type BankAccountSelectorProps = SearchFilterCommonProps<string[] | undefined>;

/** Row item rendered by SelectionListWithSections for a single bank account. */
type BankAccountFilterItem = {
/** Display label, e.g. `Chase xx1234`. */
text: string;
/** Bank account ID stringified — used as both the stable list key and the filter value. */
keyForList: string;
/** Same as keyForList; kept on the item so onChange logic mirrors CardSelector. */
value: string;
/** Whether this account is currently selected in the filter. */
isSelected: boolean;
/** Bank icon wrapper rendered at the start of the row. */
leftElement: React.JSX.Element;
/** Last four digits of the account number — searched in addition to the display text. */
lastFour: string;
};

function BankAccountSelector({value = [], selectionListTextInputStyle, selectionListStyle, autoFocus, footer, onChange}: BankAccountSelectorProps) {
const theme = useTheme();
const styles = useThemeStyles();
const {translate} = useLocalize();
const {isLargeScreenWidth} = useResponsiveLayout();
const [bankAccountList, bankAccountListMetadata] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST);
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState('');

const openItems: BankAccountFilterItem[] = [];
const closedItems: BankAccountFilterItem[] = [];
for (const bankAccount of Object.values(bankAccountList ?? {})) {
const bankAccountID = bankAccount?.accountData?.bankAccountID;
Comment on lines +52 to +53

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Filter personal accounts out of the bank selector

When an account has both a business settlement account and a personal deposit account, the bank-account filter is shown because visibility only requires a business account, but this selector adds every bank account that has an ID. The new full-page picker explicitly excludes personal accounts because the backend search filter does not accept them, so this shared selector can let users create bankAccount:<personalID> searches that will never match. Filter this list to business accounts here as well, while preserving whichever non-open business accounts should remain searchable.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is valid concert @allgandalf

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in 91ed111. BankAccountSelector now skips anything that is not type=BUSINESS before adding to the picker, matching the dedicated page logic. same filter applied to the autocomplete in ad84a77.

if (!bankAccountID) {
continue;
}
if (!isFilterableBankAccount(bankAccount)) {
continue;
}

const key = bankAccountID.toString();
const bankName = bankAccount?.accountData?.additionalData?.bankName;
const accountNumber = bankAccount?.accountData?.accountNumber ?? '';
const {icon, iconSize, iconStyles} = getBankIcon({bankName, styles, maxIconSize: isLargeScreenWidth ? variables.w28 : undefined});
const leftElement = (
<View style={[styles.mr3, styles.alignItemsCenter, styles.justifyContentCenter]}>
<Icon
src={icon}
width={iconSize}
height={iconSize}
additionalStyles={iconStyles}
/>
</View>
);

const item: BankAccountFilterItem = {
text: getBankAccountSearchLabel(bankAccount),
keyForList: key,
value: key,
isSelected: value.includes(key),
leftElement,
lastFour: accountNumber.slice(-4),
};

if (bankAccount?.accountData?.state === CONST.BANK_ACCOUNT.STATE.OPEN) {
openItems.push(item);
} else {
closedItems.push(item);
}
}

const shouldShowSearchInput = openItems.length + closedItems.length >= CONST.STANDARD_LIST_ITEM_LIMIT;

const searchFunction = (item: BankAccountFilterItem) =>
item.text.toLocaleLowerCase().includes(debouncedSearchTerm.toLocaleLowerCase()) || item.lastFour.toLocaleLowerCase().includes(debouncedSearchTerm.toLocaleLowerCase());

const selectedData = [...openItems, ...closedItems].filter((item) => item.isSelected && searchFunction(item));
const unselectedOpenData = openItems.filter((item) => !item.isSelected && searchFunction(item));
const unselectedClosedData = closedItems.filter((item) => !item.isSelected && searchFunction(item));

const itemCount = selectedData.length + unselectedOpenData.length + unselectedClosedData.length;
const sectionHeaderCount = unselectedClosedData.length > 0 ? 1 : 0;

const sections = [
{
title: undefined,
data: selectedData,
sectionIndex: 0,
},
{
title: undefined,
data: unselectedOpenData,
sectionIndex: 1,
},
{
title: translate('search.filters.bankAccount.closedBankAccounts'),
data: unselectedClosedData,
sectionIndex: 2,
},
];

const updateSelection = (item: BankAccountFilterItem) => {
if (!item.keyForList) {
return;
}
if (item.isSelected) {
onChange(value.filter((id) => id !== item.keyForList));
return;
}
onChange([...value, item.keyForList]);
};

const textInputOptions: TextInputOptions = {
value: searchTerm,
label: translate('common.search'),
onChangeText: setSearchTerm,
headerMessage: debouncedSearchTerm.trim() && sections.every((section) => !section.data.length) ? translate('common.noResultsFound') : '',
style: {
containerStyle: selectionListTextInputStyle,
},
disableAutoFocus: !autoFocus,
};

const isLoadingOnyxData = isLoadingOnyxValue(bankAccountListMetadata);
const reasonAttributes: SkeletonSpanReasonAttributes = {context: 'SearchFiltersBankAccountPage', isLoadingFromOnyx: isLoadingOnyxData};

return (
<ListFilterView
itemCount={itemCount}
itemHeight={variables.optionRowHeight}
isSearchable={shouldShowSearchInput}
extraHeight={28 * sectionHeaderCount}
>
{isLoadingOnyxData ? (
<View style={[styles.flex1, styles.flexColumn, styles.justifyContentCenter, styles.alignItemsCenter]}>
<ActivityIndicator
color={theme.spinner}
size={CONST.ACTIVITY_INDICATOR_SIZE.LARGE}
style={[styles.pl3]}
reasonAttributes={reasonAttributes}
/>
</View>
) : (
<SelectionListWithSections<BankAccountFilterItem>
sections={sections}
ListItem={MultiSelectListItem}
onSelectRow={updateSelection}
shouldPreventDefaultFocusOnSelectRow={false}
shouldShowTextInput={shouldShowSearchInput}
textInputOptions={textInputOptions}
shouldStopPropagation
canSelectMultiple
style={selectionListStyle}
footerContent={footer}
/>
)}
</ListFilterView>
);
}

export default BankAccountSelector;
3 changes: 3 additions & 0 deletions src/components/Search/FilterComponents/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {SearchFilter} from '@libs/SearchUIUtils';
import CONST from '@src/CONST';
import type {SearchAdvancedFiltersForm} from '@src/types/form/SearchAdvancedFiltersForm';
import type {SearchDataTypes} from '@src/types/onyx/SearchResults';
import BankAccountSelector from './BankAccountSelector';
import CardSelector from './CardSelector';
import CategorySelector from './CategorySelector';
import CurrencySelector from './CurrencySelector';
Expand Down Expand Up @@ -126,6 +127,7 @@ function FilterComponents({filterKey, value, type, policyIDs, policyIDQuery, sel
switch (filterKey) {
case CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.BANK_ACCOUNT:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.IN:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE:
case CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED_TO:
Expand All @@ -134,6 +136,7 @@ function FilterComponents({filterKey, value, type, policyIDs, policyIDQuery, sel
const Component = {
[CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED]: FeedSelector,
[CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID]: CardSelector,
[CONST.SEARCH.SYNTAX_FILTER_KEYS.BANK_ACCOUNT]: BankAccountSelector,
[CONST.SEARCH.SYNTAX_FILTER_KEYS.IN]: InSelector,
[CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE]: TaxRateSelector,
[CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPORTED_TO]: ExportedToSelector,
Expand Down
3 changes: 3 additions & 0 deletions src/components/Search/SearchAutocompleteList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ function SearchAutocompleteList({
const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT);
const [personalAndWorkspaceCards] = useOnyx(ONYXKEYS.DERIVED.PERSONAL_AND_WORKSPACE_CARD_LIST);
const [allFeeds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER);
const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST);
const allCards = personalAndWorkspaceCards ?? CONST.EMPTY_OBJECT;
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
Expand Down Expand Up @@ -346,6 +347,7 @@ function SearchAutocompleteList({
translate,
feedKeysWithCards,
reportAttributes,
bankAccountList,
})
: query,
singleIcon: expensifyIcons.History,
Expand All @@ -367,6 +369,7 @@ function SearchAutocompleteList({
translate,
feedKeysWithCards,
reportAttributes,
bankAccountList,
expensifyIcons.History,
]);

Expand Down
15 changes: 15 additions & 0 deletions src/components/Search/SearchPageHeader/SearchFilterBar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import DropdownButton from '@components/Search/FilterDropdowns/DropdownButton';
import type {DropdownButtonProps} from '@components/Search/FilterDropdowns/DropdownButton';
import useFilterBankAccountValue from '@components/Search/hooks/useFilterBankAccountValue';
import useFilterCardValue from '@components/Search/hooks/useFilterCardValue';
import useFilterFeedValue from '@components/Search/hooks/useFilterFeedValue';
import useFilterReportValue from '@components/Search/hooks/useFilterReportValue';
Expand Down Expand Up @@ -67,6 +68,19 @@ function CardDropdown({label, value, PopoverComponent, sentryLabel, onClosePress
);
}

function BankAccountDropdown({label, value, PopoverComponent, sentryLabel, onClosePress}: DropdownProps) {
const bankAccountValue = useFilterBankAccountValue(value);
return (
<DropdownButton
label={label}
value={bankAccountValue}
PopoverComponent={PopoverComponent}
sentryLabel={sentryLabel}
onClosePress={onClosePress}
/>
);
}

function TaxRateDropdown({label, value, PopoverComponent, sentryLabel, onClosePress}: DropdownProps) {
const taxRateValue = useFilterTaxRateValue(value as string[]);
return (
Expand Down Expand Up @@ -103,6 +117,7 @@ const FILTER_COMPONENT_MAP: Partial<Record<SearchFilter['key'], React.ComponentT

[CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED]: FeedDropdown,
[CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID]: CardDropdown,
[CONST.SEARCH.SYNTAX_FILTER_KEYS.BANK_ACCOUNT]: BankAccountDropdown,

[CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE]: TaxRateDropdown,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {SearchAutocompleteQueryRange} from '@components/Search/types';
import {parse} from '@libs/SearchParser/autocompleteParser';
import {getFilterDisplayValue} from '@libs/SearchQueryUtils';
import CONST from '@src/CONST';
import type {CardFeeds, CardList, PersonalDetailsList, Policy, Report, ReportAttributesDerivedValue} from '@src/types/onyx';
import type {BankAccountList, CardFeeds, CardList, PersonalDetailsList, Policy, Report, ReportAttributesDerivedValue} from '@src/types/onyx';
import type {SubstitutionMap} from './getQueryWithSubstitutions';
import {getSubstitutionMapKey, getSubstitutionMapKeyWithIndex} from './getQueryWithSubstitutions';

Expand All @@ -24,6 +24,8 @@ import {getSubstitutionMapKey, getSubstitutionMapKeyWithIndex} from './getQueryW
* to:SomeoneElse: 98765,
* }
*/
// Adds bankAccountList for the new bank account filter. Refactoring this to a params object would touch every call site and is out of scope here.
// eslint-disable-next-line @typescript-eslint/max-params
Comment thread
allgandalf marked this conversation as resolved.
function buildSubstitutionsMap(
query: string,
personalDetails: PersonalDetailsList | undefined,
Expand All @@ -35,6 +37,7 @@ function buildSubstitutionsMap(
currentUserAccountID: number,
translate: LocalizedTranslate,
reportAttributes: ReportAttributesDerivedValue['reports'] | undefined,
bankAccountList?: BankAccountList,
): SubstitutionMap {
const parsedQuery = parse(query) as {ranges: SearchAutocompleteQueryRange[]};

Expand Down Expand Up @@ -70,6 +73,7 @@ function buildSubstitutionsMap(
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.BANK_ACCOUNT ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.FEED ||
filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.POLICY_ID ||
Expand All @@ -89,6 +93,7 @@ function buildSubstitutionsMap(
currentUserAccountID,
translate,
reportAttributes,
bankAccountList,
});

// If displayValue === filterValue, then it means there is nothing to substitute, so we don't add any key to map
Expand Down
18 changes: 18 additions & 0 deletions src/components/Search/hooks/useFilterBankAccountValue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import useOnyx from '@hooks/useOnyx';
import {getBankAccountSearchLabel} from '@libs/BankAccountUtils';
import type {SearchFilter} from '@libs/SearchUIUtils';
import ONYXKEYS from '@src/ONYXKEYS';

function useFilterBankAccountValue(value: SearchFilter['value']): string {
const [bankAccountList] = useOnyx(ONYXKEYS.BANK_ACCOUNT_LIST);

const ids = Array.isArray(value) ? value : [value];

const bankAccountLabels = Object.values(bankAccountList ?? {})
.filter((bankAccount) => ids.includes(bankAccount?.accountData?.bankAccountID?.toString() ?? ''))
.map((bankAccount) => getBankAccountSearchLabel(bankAccount));

return bankAccountLabels.join(', ');
}

export default useFilterBankAccountValue;
Loading
Loading