From e7341cc8b108ec8a9165a347a533ed8eaf66d7c6 Mon Sep 17 00:00:00 2001 From: Ben Limpich Date: Thu, 19 Mar 2026 10:31:26 -0700 Subject: [PATCH 1/4] don't use card.isTravelCard --- src/libs/CardUtils.ts | 8 ++++++-- src/pages/settings/Wallet/ExpensifyCardPage/index.tsx | 11 +++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index 1add3b4cbf9e1..7fbe1cb2ecd31 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -1405,6 +1405,10 @@ function getBrokenConnectionUrlToFixPersonalCard(cards: Record, en return `${environmentURL}/${ROUTES.SETTINGS_WALLET}`; } +function isTravelCard(card: Card): boolean { + return card?.nameValuePairs?.feedCountry === CONST.TRAVEL.PROGRAM_TRAVEL_US; +} + /** * Gets displayable Expensify cards, filtering out inactive cards and grouping combo cards * (physical + virtual pairs) so only the physical card is shown per domain. @@ -1425,8 +1429,7 @@ function getDisplayableExpensifyCards(cardList: CardList | undefined): Card[] { return sortedCards.filter((card) => { const isAdminIssuedVirtualCard = !!card.nameValuePairs?.issuedBy && !!card.nameValuePairs?.isVirtual; - const isTravelCard = !!card.nameValuePairs?.isVirtual && !!card.nameValuePairs?.isTravelCard; - const isComboCard = !!card.domainName && !isAdminIssuedVirtualCard && !isTravelCard; + const isComboCard = !!card.domainName && !isAdminIssuedVirtualCard && !(isTravelCard(card)); // Always show non-combo cards (admin-issued virtual, travel cards, or cards without domain) if (!isComboCard) { @@ -1516,6 +1519,7 @@ export { getCardFeedIcon, getBankName, isSelectedFeedExpired, + isTravelCard, getCompanyFeeds, isPersonalCardBrokenConnection, isCustomFeed, diff --git a/src/pages/settings/Wallet/ExpensifyCardPage/index.tsx b/src/pages/settings/Wallet/ExpensifyCardPage/index.tsx index aa3d26945172c..b4c95c94d4e80 100644 --- a/src/pages/settings/Wallet/ExpensifyCardPage/index.tsx +++ b/src/pages/settings/Wallet/ExpensifyCardPage/index.tsx @@ -27,7 +27,7 @@ import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; import {freezeCard, unfreezeCard} from '@libs/actions/Card'; import {resetValidateActionCodeSent} from '@libs/actions/User'; -import {formatCardExpiration, getCardCurrency, getCardHintText, getDomainCards, getTranslationKeyForLimitType, isCardFrozen, maskCard, maskPin} from '@libs/CardUtils'; +import {formatCardExpiration, getCardCurrency, getCardHintText, getDomainCards, getTranslationKeyForLimitType, isCardFrozen, isTravelCard, maskCard, maskPin} from '@libs/CardUtils'; import {convertToDisplayString} from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; @@ -77,10 +77,9 @@ function ExpensifyCardPage({route}: ExpensifyCardPageProps) { const styles = useThemeStyles(); const {isOffline} = useNetwork(); const {translate} = useLocalize(); - const isTravelCard = cardList?.[cardID]?.nameValuePairs?.isTravelCard; - const shouldDisplayCardDomain = !isTravelCard && (!cardList?.[cardID]?.nameValuePairs?.issuedBy || !cardList?.[cardID]?.nameValuePairs?.isVirtual); + const shouldDisplayCardDomain = !isTravelCard(cardList?.[cardID]) && (!cardList?.[cardID]?.nameValuePairs?.issuedBy || !cardList?.[cardID]?.nameValuePairs?.isVirtual); const domain = cardList?.[cardID]?.domainName ?? ''; - const expensifyCardTitle = isTravelCard ? translate('cardPage.expensifyTravelCard') : translate('cardPage.expensifyCard'); + const expensifyCardTitle = isTravelCard(cardList?.[cardID]) ? translate('cardPage.expensifyTravelCard') : translate('cardPage.expensifyCard'); const pageTitle = shouldDisplayCardDomain ? expensifyCardTitle : (cardList?.[cardID]?.nameValuePairs?.cardTitle ?? expensifyCardTitle); const {displayName} = useCurrentUserPersonalDetails(); const personalDetails = usePersonalDetails(); @@ -94,8 +93,8 @@ function ExpensifyCardPage({route}: ExpensifyCardPageProps) { }, [shouldDisplayCardDomain, cardList, cardID, domain]); const currentCard = useMemo(() => cardsToShow?.find((card) => String(card?.cardID) === cardID) ?? cardsToShow?.at(0), [cardsToShow, cardID]); - const virtualCards = useMemo(() => cardsToShow?.filter((card) => card?.nameValuePairs?.isVirtual && !card?.nameValuePairs?.isTravelCard), [cardsToShow]); - const travelCards = useMemo(() => cardsToShow?.filter((card) => card?.nameValuePairs?.isVirtual && card?.nameValuePairs?.isTravelCard), [cardsToShow]); + const virtualCards = useMemo(() => cardsToShow?.filter((card) => card?.nameValuePairs?.isVirtual && !isTravelCard(card)), [cardsToShow]); + const travelCards = useMemo(() => cardsToShow?.filter((card) => card?.nameValuePairs?.isVirtual && isTravelCard(card)), [cardsToShow]); const physicalCards = useMemo(() => cardsToShow?.filter((card) => !card?.nameValuePairs?.isVirtual), [cardsToShow]); const cardToAdd = useMemo(() => { return virtualCards?.at(0); From 31d13cf42f2372402b8e07987dc855a0c7f25017 Mon Sep 17 00:00:00 2001 From: Ben Limpich Date: Thu, 19 Mar 2026 10:41:09 -0700 Subject: [PATCH 2/4] Fix prettier and typecheck errors for isTravelCard Co-Authored-By: Claude Opus 4.6 (1M context) --- src/libs/CardUtils.ts | 4 ++-- src/pages/settings/Wallet/ExpensifyCardPage/index.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index 7fbe1cb2ecd31..dbf12c6b12af6 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -1405,7 +1405,7 @@ function getBrokenConnectionUrlToFixPersonalCard(cards: Record, en return `${environmentURL}/${ROUTES.SETTINGS_WALLET}`; } -function isTravelCard(card: Card): boolean { +function isTravelCard(card: Card | undefined): boolean { return card?.nameValuePairs?.feedCountry === CONST.TRAVEL.PROGRAM_TRAVEL_US; } @@ -1429,7 +1429,7 @@ function getDisplayableExpensifyCards(cardList: CardList | undefined): Card[] { return sortedCards.filter((card) => { const isAdminIssuedVirtualCard = !!card.nameValuePairs?.issuedBy && !!card.nameValuePairs?.isVirtual; - const isComboCard = !!card.domainName && !isAdminIssuedVirtualCard && !(isTravelCard(card)); + const isComboCard = !!card.domainName && !isAdminIssuedVirtualCard && !isTravelCard(card); // Always show non-combo cards (admin-issued virtual, travel cards, or cards without domain) if (!isComboCard) { diff --git a/src/pages/settings/Wallet/ExpensifyCardPage/index.tsx b/src/pages/settings/Wallet/ExpensifyCardPage/index.tsx index b4c95c94d4e80..f2f5c28e116ed 100644 --- a/src/pages/settings/Wallet/ExpensifyCardPage/index.tsx +++ b/src/pages/settings/Wallet/ExpensifyCardPage/index.tsx @@ -344,7 +344,7 @@ function ExpensifyCardPage({route}: ExpensifyCardPageProps) { )} ))} - {isTravelCard && + {isTravelCard(cardList?.[cardID]) && travelCards.map((card) => ( {!!cardsDetails[card.cardID] && cardsDetails[card.cardID]?.cvv ? ( From fcd9939e4d0ee0cd676efccc913bf55b31ebe7d0 Mon Sep 17 00:00:00 2001 From: Ben Limpich Date: Thu, 19 Mar 2026 10:49:19 -0700 Subject: [PATCH 3/4] Update test to use feedCountry instead of isTravelCard Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/unit/CardUtilsTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/CardUtilsTest.ts b/tests/unit/CardUtilsTest.ts index 61428e2f62a30..ba18d85de300c 100644 --- a/tests/unit/CardUtilsTest.ts +++ b/tests/unit/CardUtilsTest.ts @@ -2487,7 +2487,7 @@ describe('CardUtils', () => { state: CONST.EXPENSIFY_CARD.STATE.OPEN, nameValuePairs: { isVirtual: true, - isTravelCard: true, + feedCountry: CONST.TRAVEL.PROGRAM_TRAVEL_US, }, }, } as unknown as CardList; From 149a21e55760607520996a6f619d31bdcccb1fbf Mon Sep 17 00:00:00 2001 From: Ben Limpich Date: Thu, 19 Mar 2026 10:52:19 -0700 Subject: [PATCH 4/4] update PaymentMethodList.tsx --- src/pages/settings/Wallet/PaymentMethodList.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index 28a0b680ac304..88290d8929945 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -32,6 +32,7 @@ import { isExpensifyCardPendingAction, isExpiredCard, isPersonalCard, + isTravelCard, lastFourNumbersFromCardName, maskCardNumber, } from '@libs/CardUtils'; @@ -313,10 +314,9 @@ function PaymentMethodList({ } const isAdminIssuedVirtualCard = !!card?.nameValuePairs?.issuedBy && !!card?.nameValuePairs?.isVirtual; - const isTravelCard = card?.nameValuePairs?.feedCountry === CONST.TRAVEL.PROGRAM_TRAVEL_US; // Travel cards are handled by the dedicated travelCardGrouped section below - if (isTravelCard) { + if (isTravelCard(card)) { continue; }