From 68213ac781e93d564e9a076b97c880e66cc1b6d0 Mon Sep 17 00:00:00 2001
From: Shubham Agrawal <shubham.agra1206@gmail.com>
Date: Thu, 31 Jul 2025 21:51:28 +0530
Subject: [PATCH 1/3] Removed Onyx.connect in CardUtils lib file (part 2)

---
 package.json                                  |  2 +-
 src/components/EReceipt.tsx                   |  2 +-
 .../Search/SearchAutocompleteList.tsx         |  5 ++-
 src/libs/CardUtils.ts                         | 35 ++++---------------
 src/libs/SearchQueryUtils.ts                  |  4 +--
 src/pages/Search/AdvancedSearchFilters.tsx    |  2 +-
 .../settings/Wallet/PaymentMethodList.tsx     |  4 +--
 7 files changed, 16 insertions(+), 38 deletions(-)

diff --git a/package.json b/package.json
index 0bd9828532d5..9be43ceff0bb 100644
--- a/package.json
+++ b/package.json
@@ -46,7 +46,7 @@
     "test:debug": "TZ=utc NODE_OPTIONS='--inspect-brk --experimental-vm-modules' jest --runInBand",
     "perf-test": "NODE_OPTIONS=--experimental-vm-modules npx reassure",
     "typecheck": "NODE_OPTIONS=--max_old_space_size=8192 tsc",
-    "lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=324 --cache --cache-location=node_modules/.cache/eslint",
+    "lint": "NODE_OPTIONS=--max_old_space_size=8192 eslint . --max-warnings=323 --cache --cache-location=node_modules/.cache/eslint",
     "lint-changed": "NODE_OPTIONS=--max_old_space_size=8192 ./scripts/lintChanged.sh",
     "lint-watch": "npx eslint-watch --watch --changed",
     "shellcheck": "./scripts/shellCheck.sh",
diff --git a/src/components/EReceipt.tsx b/src/components/EReceipt.tsx
index 11a415f8090d..e9fe5bf1ceef 100644
--- a/src/components/EReceipt.tsx
+++ b/src/components/EReceipt.tsx
@@ -54,7 +54,7 @@ function EReceipt({transactionID, transactionItem, isThumbnail = false}: EReceip
     const formattedAmount = convertToDisplayString(transactionAmount, transactionCurrency);
     const currency = getCurrencySymbol(transactionCurrency ?? '');
     const amount = currency ? formattedAmount.replace(currency, '') : formattedAmount;
-    const cardDescription = getCompanyCardDescription(transactionCardName, transactionCardID, cardList) ?? (transactionCardID ? getCardDescription(transactionCardID) : '');
+    const cardDescription = getCompanyCardDescription(transactionCardName, transactionCardID, cardList) ?? (transactionCardID ? getCardDescription(cardList?.[transactionCardID]) : '');
 
     const secondaryBgcolorStyle = secondaryColor ? StyleUtils.getBackgroundColorStyle(secondaryColor) : undefined;
     const primaryTextColorStyle = primaryColor ? StyleUtils.getColorStyle(primaryColor) : undefined;
diff --git a/src/components/Search/SearchAutocompleteList.tsx b/src/components/Search/SearchAutocompleteList.tsx
index b329a582f58d..e05989ce73b0 100644
--- a/src/components/Search/SearchAutocompleteList.tsx
+++ b/src/components/Search/SearchAutocompleteList.tsx
@@ -391,14 +391,14 @@ function SearchAutocompleteList(
                     .filter(
                         (card) =>
                             (card.bank.toLowerCase().includes(autocompleteValue.toLowerCase()) || card.lastFourPAN?.includes(autocompleteValue)) &&
-                            !alreadyAutocompletedKeys.includes(getCardDescription(card.cardID).toLowerCase()),
+                            !alreadyAutocompletedKeys.includes(getCardDescription(card).toLowerCase()),
                     )
                     .sort()
                     .slice(0, 10);
 
                 return filteredCards.map((card) => ({
                     filterKey: CONST.SEARCH.SEARCH_USER_FRIENDLY_KEYS.CARD_ID,
-                    text: getCardDescription(card.cardID, allCards),
+                    text: getCardDescription(card),
                     autocompleteID: card.cardID.toString(),
                     mapKey: CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID,
                 }));
@@ -460,7 +460,6 @@ function SearchAutocompleteList(
         expenseTypes,
         feedAutoCompleteList,
         cardAutocompleteList,
-        allCards,
         booleanTypes,
         workspaceList,
     ]);
diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts
index c1954578638c..8e91437f8868 100644
--- a/src/libs/CardUtils.ts
+++ b/src/libs/CardUtils.ts
@@ -9,7 +9,6 @@ import type IllustrationsType from '@styles/theme/illustrations/types';
 import * as Illustrations from '@src/components/Icon/Illustrations';
 import CONST from '@src/CONST';
 import type {TranslationPaths} from '@src/languages/types';
-import type {OnyxValues} from '@src/ONYXKEYS';
 import ONYXKEYS from '@src/ONYXKEYS';
 import type {BankAccountList, Card, CardFeeds, CardList, CompanyCardFeed, CurrencyList, ExpensifyCardSettings, PersonalDetailsList, Policy, WorkspaceCardsList} from '@src/types/onyx';
 import type {FilteredCardList} from '@src/types/onyx/Card';
@@ -21,18 +20,6 @@ import {filterObject} from './ObjectUtils';
 import {getDisplayNameOrDefault} from './PersonalDetailsUtils';
 import StringUtils from './StringUtils';
 
-let allCards: OnyxValues[typeof ONYXKEYS.CARD_LIST] = {};
-Onyx.connect({
-    key: ONYXKEYS.CARD_LIST,
-    callback: (val) => {
-        if (!val || Object.keys(val).length === 0) {
-            return;
-        }
-
-        allCards = val;
-    },
-});
-
 let allWorkspaceCards: OnyxCollection<WorkspaceCardsList> = {};
 Onyx.connect({
     key: ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST,
@@ -58,14 +45,10 @@ function getMonthFromExpirationDateString(expirationDateString: string) {
 }
 
 /**
- * @param cardID
+ * @param card
  * @returns boolean
  */
-function isExpensifyCard(cardID?: number) {
-    if (!cardID) {
-        return false;
-    }
-    const card = allCards[cardID];
+function isExpensifyCard(card?: Card) {
     if (!card) {
         return false;
     }
@@ -73,14 +56,10 @@ function isExpensifyCard(cardID?: number) {
 }
 
 /**
- * @param cardID
+ * @param card
  * @returns string in format %<bank> - <lastFourPAN || Not Activated>%.
  */
-function getCardDescription(cardID?: number, cards: CardList = allCards) {
-    if (!cardID) {
-        return '';
-    }
-    const card = cards[cardID];
+function getCardDescription(card?: Card) {
     if (!card) {
         return '';
     }
@@ -98,7 +77,7 @@ function getCardDescription(cardID?: number, cards: CardList = allCards) {
  * @returns company card name
  */
 function getCompanyCardDescription(transactionCardName?: string, cardID?: number, cards?: CardList) {
-    if (!cardID || isExpensifyCard(cardID) || !cards?.[cardID]) {
+    if (!cardID || !cards?.[cardID] || isExpensifyCard(cards[cardID])) {
         return transactionCardName;
     }
     const card = cards[cardID];
@@ -118,9 +97,9 @@ function isCardClosed(card: Card) {
     return card?.state === CONST.EXPENSIFY_CARD.STATE.CLOSED;
 }
 
-function mergeCardListWithWorkspaceFeeds(workspaceFeeds: Record<string, WorkspaceCardsList | undefined>, cardList = allCards, shouldExcludeCardHiddenFromSearch = false) {
+function mergeCardListWithWorkspaceFeeds(workspaceFeeds: Record<string, WorkspaceCardsList | undefined>, cardList: CardList | undefined, shouldExcludeCardHiddenFromSearch = false) {
     const feedCards: CardList = {};
-    Object.values(cardList).forEach((card) => {
+    Object.values(cardList ?? {}).forEach((card) => {
         if (!isCard(card) || (shouldExcludeCardHiddenFromSearch && isCardHiddenFromSearch(card))) {
             return;
         }
diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts
index d185f0ff3150..5112af4c8060 100644
--- a/src/libs/SearchQueryUtils.ts
+++ b/src/libs/SearchQueryUtils.ts
@@ -721,7 +721,7 @@ function getFilterDisplayValue(
         if (Number.isNaN(cardID)) {
             return filterValue;
         }
-        return getCardDescription(cardID, cardList) || filterValue;
+        return getCardDescription(cardList?.[cardID]) || filterValue;
     }
     if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) {
         return getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filterValue}`]) || filterValue;
@@ -821,7 +821,7 @@ function buildUserReadableQueryString(
                     if (Number.isNaN(cardID)) {
                         acc.push({operator: filter.operator, value: cardID});
                     } else {
-                        acc.push({operator: filter.operator, value: getCardDescription(cardID, cardList) || cardID});
+                        acc.push({operator: filter.operator, value: getCardDescription(cardList?.[cardID]) || cardID});
                     }
                 }
                 return acc;
diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx
index c734ac3183f1..050bb0fa291d 100644
--- a/src/pages/Search/AdvancedSearchFilters.tsx
+++ b/src/pages/Search/AdvancedSearchFilters.tsx
@@ -351,7 +351,7 @@ function getFilterCardDisplayTitle(filters: Partial<SearchAdvancedFiltersForm>,
 
     const cardNames = Object.values(cards)
         .filter((card) => cardIdsFilter.includes(card.cardID.toString()) && !feedFilter.includes(createCardFeedKey(card.fundID, card.bank)))
-        .map((card) => getCardDescription(card.cardID, cards));
+        .map((card) => getCardDescription(card));
 
     const feedNames = Object.keys(cardFeedNamesWithType)
         .filter((workspaceCardFeedKey) => {
diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx
index ab0c1c3ac2b1..836f361cc9fc 100644
--- a/src/pages/settings/Wallet/PaymentMethodList.tsx
+++ b/src/pages/settings/Wallet/PaymentMethodList.tsx
@@ -219,14 +219,14 @@ function PaymentMethodList({
             const assignedCards = Object.values(isLoadingCardList ? {} : (cardList ?? {}))
                 // Filter by active cards associated with a domain
                 .filter((card) => !!card.domainName && CONST.EXPENSIFY_CARD.ACTIVE_STATES.includes(card.state ?? 0));
-            const assignedCardsSorted = lodashSortBy(assignedCards, (card) => !isExpensifyCard(card.cardID));
+            const assignedCardsSorted = lodashSortBy(assignedCards, (card) => !isExpensifyCard(card));
 
             const assignedCardsGrouped: PaymentMethodItem[] = [];
             assignedCardsSorted.forEach((card) => {
                 const isDisabled = card.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || !!card.errors;
                 const icon = getCardFeedIcon(card.bank as CompanyCardFeed, illustrations);
 
-                if (!isExpensifyCard(card.cardID)) {
+                if (!isExpensifyCard(card)) {
                     const pressHandler = onPress as CardPressHandler;
                     const lastFourPAN = lastFourNumbersFromCardName(card.cardName);
                     const plaidUrl = getPlaidInstitutionIconUrl(card.bank);

From c193e586bd0395969ba585ba39c51560fab42807 Mon Sep 17 00:00:00 2001
From: Shubham Agrawal <shubham.agra1206@gmail.com>
Date: Thu, 31 Jul 2025 23:46:18 +0530
Subject: [PATCH 2/3] Add some tests

---
 tests/unit/CardUtilsTest.ts | 40 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 insertions(+), 1 deletion(-)

diff --git a/tests/unit/CardUtilsTest.ts b/tests/unit/CardUtilsTest.ts
index b0aa29d56096..bb8b16c8cf14 100644
--- a/tests/unit/CardUtilsTest.ts
+++ b/tests/unit/CardUtilsTest.ts
@@ -10,6 +10,7 @@ import {
     formatCardExpiration,
     getBankCardDetailsImage,
     getBankName,
+    getCardDescription,
     getCardFeedIcon,
     getCardsByCardholderName,
     getCompanyFeeds,
@@ -26,7 +27,7 @@ import {
     maskCardNumber,
     sortCardsByCardholderName,
 } from '@src/libs/CardUtils';
-import type {CardFeeds, CardList, CompanyCardFeed, ExpensifyCardSettings, PersonalDetailsList, Policy, WorkspaceCardsList} from '@src/types/onyx';
+import type {Card, CardFeeds, CardList, CompanyCardFeed, ExpensifyCardSettings, PersonalDetailsList, Policy, WorkspaceCardsList} from '@src/types/onyx';
 import type {CompanyCardFeedWithNumber} from '@src/types/onyx/CardFeeds';
 import {localeCompare} from '../utils/TestHelper';
 import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
@@ -1005,4 +1006,41 @@ describe('CardUtils', () => {
             expect(sortedCards.at(0)?.cardID).toBe(1);
         });
     });
+
+    describe('getCardDescription', () => {
+        it('should return the correct card description for company card', () => {
+            const card: Card = {
+                accountID: 18439984,
+                bank: CONST.COMPANY_CARD.FEED_BANK_NAME.VISA,
+                cardID: 21310091,
+                cardName: '480801XXXXXX2554',
+                domainName: 'expensify-policy41314f4dc5ce25af.exfy',
+                fraud: 'none',
+                lastFourPAN: '2554',
+                lastUpdated: '',
+                lastScrape: '2024-11-27 11:00:53',
+                scrapeMinDate: '2024-10-17',
+                state: 3,
+            };
+            const description = getCardDescription(card);
+            expect(description).toBe('Visa - 2554');
+        });
+
+        it('should return the correct card description for Expensify card', () => {
+            const card: Card = {
+                accountID: 18439984,
+                bank: CONST.EXPENSIFY_CARD.BANK,
+                cardID: 21570657,
+                cardName: 'CREDIT CARD...5644',
+                domainName: 'expensify-policy17f617b9fe23d2f1.exfy',
+                fraud: 'none',
+                lastFourPAN: '',
+                lastScrape: '',
+                lastUpdated: '',
+                state: 2,
+            };
+            const description = getCardDescription(card);
+            expect(description).toBe('Expensify Card');
+        });
+    });
 });

From 46b7f4ea9e2f97ee7f556a6fa5852f4f2ecca68f Mon Sep 17 00:00:00 2001
From: Shubham Agrawal <shubham.agra1206@gmail.com>
Date: Thu, 7 Aug 2025 20:05:07 +0530
Subject: [PATCH 3/3] Added some tests

---
 tests/unit/CardUtilsTest.ts | 76 +++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/tests/unit/CardUtilsTest.ts b/tests/unit/CardUtilsTest.ts
index bb8b16c8cf14..e31bdc87e33f 100644
--- a/tests/unit/CardUtilsTest.ts
+++ b/tests/unit/CardUtilsTest.ts
@@ -13,6 +13,7 @@ import {
     getCardDescription,
     getCardFeedIcon,
     getCardsByCardholderName,
+    getCompanyCardDescription,
     getCompanyFeeds,
     getCustomOrFormattedFeedName,
     getFeedType,
@@ -22,6 +23,7 @@ import {
     getYearFromExpirationDateString,
     hasIssuedExpensifyCard,
     isCustomFeed as isCustomFeedCardUtils,
+    isExpensifyCard,
     isExpensifyCardFullySetUp,
     lastFourNumbersFromCardName,
     maskCardNumber,
@@ -1043,4 +1045,78 @@ describe('CardUtils', () => {
             expect(description).toBe('Expensify Card');
         });
     });
+
+    describe('isExpensifyCard', () => {
+        it('should return true for Expensify Card', () => {
+            const card: Card = {
+                accountID: 18439984,
+                bank: CONST.EXPENSIFY_CARD.BANK,
+                cardID: 21570657,
+                cardName: 'CREDIT CARD...5644',
+                domainName: 'expensify-policy17f617b9fe23d2f1.exfy',
+                fraud: 'none',
+                lastFourPAN: '',
+                lastScrape: '',
+                lastUpdated: '',
+                state: 2,
+            };
+            expect(isExpensifyCard(card)).toBe(true);
+        });
+
+        it('should return false for non-Expensify Card', () => {
+            const card: Card = {
+                accountID: 18439984,
+                bank: CONST.COMPANY_CARD.FEED_BANK_NAME.VISA,
+                cardID: 21310091,
+                cardName: '480801XXXXXX2554',
+                domainName: 'expensify-policy41314f4dc5ce25af.exfy',
+                fraud: 'none',
+                lastFourPAN: '2554',
+                lastUpdated: '',
+                lastScrape: '2024-11-27 11:00:53',
+                scrapeMinDate: '2024-10-17',
+                state: 3,
+            };
+            expect(isExpensifyCard(card)).toBe(false);
+        });
+    });
+
+    describe('getCompanyCardDescription', () => {
+        const cardList: CardList = {
+            '21310091': {
+                accountID: 18439984,
+                bank: CONST.COMPANY_CARD.FEED_BANK_NAME.VISA,
+                cardID: 21310091,
+                cardName: '480801XXXXXX2554',
+                domainName: 'expensify-policy41314f4dc5ce25af.exfy',
+                fraud: 'none',
+                lastFourPAN: '2554',
+                lastUpdated: '',
+                lastScrape: '2024-11-27 11:00:53',
+                scrapeMinDate: '2024-10-17',
+                state: 3,
+            },
+            '21570657': {
+                accountID: 18439984,
+                bank: CONST.EXPENSIFY_CARD.BANK,
+                cardID: 21570657,
+                cardName: 'CREDIT CARD...5644',
+                domainName: 'expensify-policy17f617b9fe23d2f1.exfy',
+                fraud: 'none',
+                lastFourPAN: '',
+                lastScrape: '',
+                lastUpdated: '',
+                state: 2,
+            },
+        };
+        it('should return the correct description for a company card', () => {
+            const description = getCompanyCardDescription('Test', 21310091, cardList);
+            expect(description).toBe('480801XXXXXX2554');
+        });
+
+        it('should return the correct description for an Expensify card', () => {
+            const description = getCompanyCardDescription('Test', 21570657, cardList);
+            expect(description).toBe('Test');
+        });
+    });
 });
