[$250] Wallet - Bank account icon still exists after deletion
If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!
Version Number: v9.2.86-0 Reproducible in staging?: Yes Reproducible in production?: Yes If this was caught during regression testing, add the test name, ID and link from BrowserStack: https://test-management.browserstack.com/projects/2219752/test-runs/TR-2489/folder/13176687/41236662/1089920276?p=2 Email or phone of affected tester (no customers): N/A Issue reported by: Applause Internal Team Bug source: Regression TC Execution Device used: iPhone 14 / iOS 26.1 App Component: User Settings
Action Performed:
- Open the NewDot app
- Navigate the account settings
- Tap on the Wallet
- Tap on the Enable wallet button
- Complete adding the bank account with the Onfido verify step
- Tap on the three dots button on the bank account
- Select Delete -> Tap Delete on the confirm banner
Expected Result:
The bank account was removed completely
Actual Result:
The name disappears, but the icon of the bank account still exists
Workaround:
Unknown
Platforms:
- [ ] Android: App
- [ ] Android: mWeb Chrome
- [x] iOS: App
- [ ] iOS: mWeb Safari
- [ ] iOS: mWeb Chrome
- [x] Windows: Chrome
- [x] MacOS: Chrome / Safari
Screenshots/Videos
https://github.com/user-attachments/assets/2cfe47bf-e1b0-499d-976f-3c12aea1acad
Upwork Automation - Do Not Edit
- Upwork Job URL: https://www.upwork.com/jobs/~022003808029537028224
- Upwork Job ID: 2003808029537028224
- Last Price Increase: 2025-12-24
Issue Owner
Current Issue Owner: @Pujan92
Triggered auto assignment to @heyjennahay (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.
Proposal
Please re-state the problem that we are trying to solve in this issue.
When users delete a bank account from the Wallet in account settings, the bank account name disappears but the bank account icon still remains visible on screen.
What is the root cause of that problem?
The issue is in the formatPaymentMethods function in App/src/libs/PaymentUtils.ts which doesn't handle null entries in the bank account list.
How deletion works:
When a bank account is deleted, the Onyx store is updated in two phases:
- Optimistic Update (
App/src/libs/actions/BankAccounts.tslines 384-390):
optimisticData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.BANK_ACCOUNT_LIST}`,
value: {[bankAccountID]: {pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE}},
},
],
- Success Update (
App/src/libs/actions/BankAccounts.tslines 394-400):
successData: [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.BANK_ACCOUNT_LIST}`,
value: {[bankAccountID]: null},
},
],
On successful deletion, the bank account entry is set to null in BANK_ACCOUNT_LIST.
The Problem - formatPaymentMethods (App/src/libs/PaymentUtils.ts lines 90-113):
function formatPaymentMethods(bankAccountList: Record<string, BankAccount>, fundList: Record<string, Fund> | Fund[], styles: ThemeStyles, translate: LocalizedTranslate): PaymentMethod[] {
const combinedPaymentMethods: PaymentMethod[] = [];
for (const bankAccount of Object.values(bankAccountList)) {
// Add all bank accounts besides the wallet
if (bankAccount?.accountData?.type === CONST.BANK_ACCOUNT_TYPES.WALLET) {
continue;
}
const {icon, iconSize, iconHeight, iconWidth, iconStyles} = getBankIcon({
bankName: bankAccount?.accountData?.additionalData?.bankName,
isCard: false,
styles,
});
combinedPaymentMethods.push({
...bankAccount,
description: getPaymentMethodDescription(bankAccount?.accountType, bankAccount.accountData, translate, bankAccount.bankCurrency),
icon,
iconSize,
iconHeight,
iconWidth,
iconStyles,
});
}
// ... rest of function
}
The Bug Flow:
Object.values(bankAccountList)includesnullentries (deleted accounts)- The loop iterates over these
nullentries - For a
nullentry,bankAccount?.accountData?.typeisundefined(not WALLET), so it doesn't skip getBankIconis called withbankName: undefined
getBankIcon with undefined bankName (App/src/components/Icon/BankIcons/index.ts lines 20-31):
export default function getBankIcon({styles, bankName, isCard = false}: BankIconParams): BankIcon {
const bankIcon: BankIcon = {
icon: isCard ? GenericBankCard : GenericBank,
};
if (bankName) {
const bankNameKey = getBankNameKey(bankName.toLowerCase());
if (bankNameKey && bankNameKey in CONST.BANK_NAMES) {
bankIcon.icon = (getBankIconAsset(bankNameKey, isCard) as BankIconAsset).default;
}
}
// Returns GenericBank icon when bankName is undefined
}
- When
bankNameisundefined,getBankIconreturns the generic bank icon - A payment method entry is created with the generic icon but no title/name (because
bankAccountisnull) - The UI renders an icon with no text
What changes do you think we should make in order to solve the problem?
Add null/undefined checks at the start of both loops in formatPaymentMethods to skip deleted entries.
File to modify: App/src/libs/PaymentUtils.ts
Change 1 - Bank Accounts Loop (line 93):
for (const bankAccount of Object.values(bankAccountList)) {
// Skip null/undefined entries (deleted accounts)
if (!bankAccount) {
continue;
}
// Add all bank accounts besides the wallet
if (bankAccount?.accountData?.type === CONST.BANK_ACCOUNT_TYPES.WALLET) {
continue;
}
// ... rest of loop
}
Change 2 - Fund List Loop (line 120):
for (const card of Object.values(fundList)) {
// Skip null/undefined entries (deleted cards)
if (!card) {
continue;
}
const {icon, iconSize, iconHeight, iconWidth, iconStyles} = getBankIcon({bankName: card?.accountData?.bank, isCard: true, styles});
// ... rest of loop
}
What alternative solutions did you explore? (Optional)
None
Job added to Upwork: https://www.upwork.com/jobs/~022003808029537028224
Triggered auto assignment to Contributor-plus team member for initial proposal review - @Pujan92 (External)
Note there might be delays on the Expensify side of things while people are out for the holidays
@abbasifaizan70 your RCA makes sense but are you able to reproduce this? I tried on the web but was unable to reproduce it(haven't tried on native yet)
@Pujan92 i am not able to add bank.
You can use this comment to add a bank account.
Please re-state the problem that we are trying to solve in this issue
Deleting a wallet bank account removes the name but leaves its icon visible in the Wallet list.
What is the root cause of that problem?
The payment method builder includes bank accounts even when their data is empty or their status is marked as DELETED. This results in entries that only display an icon. The logic currently adds every bank account without excluding deleted ones.
What changes do you think we should make in order to solve the problem?
Ignore bank accounts that do not have accountData or are marked as DELETED before adding them to the payment method list. This ensures removed accounts fully disappear and do not leave icons behind.
Updated code:
// src/libs/PaymentUtils.ts
for (const bankAccount of Object.values(bankAccountList)) {
if (!bankAccount?.accountData || bankAccount.accountData.state === CONST.BANK_ACCOUNT.STATE.DELETED) {
continue;
}
if (bankAccount?.accountData?.type === CONST.BANK_ACCOUNT_TYPES.WALLET) {
continue;
}
const {icon, iconSize, iconHeight, iconWidth, iconStyles} = getBankIcon({
bankName: bankAccount?.accountData?.additionalData?.bankName,
isCard: false,
styles,
});
combinedPaymentMethods.push({
...bankAccount,
description: getPaymentMethodDescription(
bankAccount?.accountType,
bankAccount.accountData,
translate,
bankAccount.bankCurrency,
),
icon,
iconSize,
iconHeight,
iconWidth,
iconStyles,
});
}
⚠️ @ShridharGoel Your proposal is a duplicate of an already existing proposal and has been automatically withdrawn to prevent spam. Please review the existing proposals before submitting a new one.
@Pujan92, can you please add my email to the Expensify Slack, as I am unable to access the above Slack chat?
You can request to join in the slack group. @heyjennahay can help you to allow access.
You can request to join in the slack group. @heyjennahay can help you to allow access.
I filled out the form to join Expensify Slack, but I didn't receive any reply. So waiting for response.Thanks for helping @Pujan92
📣 It's been a week! Do we have any satisfactory proposals yet? Do we need to adjust the bounty for this issue? 💸
@Pujan92 Still overdue 6 days?! Let's take care of this!
@nlemma is it still reproducible for you?
I am not able to bypass onfido screen yet.
@Pujan92 the issue is still reproducible.
https://github.com/user-attachments/assets/02a50172-684c-4ced-81c6-609d18e95e24
@nlemma can you add me to slack please. Here my email [email protected]
Thanks @nlemma , I am able to reproduce with the enabled wallet.
@heyjennahay this looks like a BE issue as DeletePaymentBankAccount api responding the incorrect data which causes this issue. On reopening the page(OpenPaymentsPage) it sets the data correctly.
Let's add an internal label here so they can investigate this.
https://github.com/user-attachments/assets/84eae3f3-8119-4f86-aaae-56cad5fd09bd
Thanks @Pujan92 issue label updated!
@heyjennahay @Pujan92 this issue was created 2 weeks ago. Are we close to a solution? Let's make sure we're treating this as a top priority. Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!