From 4f37a30dc1b60bea7804cef8aa5667613f5e6202 Mon Sep 17 00:00:00 2001 From: Kevin Brian Bader Date: Thu, 20 Feb 2025 19:04:07 -0800 Subject: [PATCH 1/2] Expensify Card promotion banner conditional display --- src/libs/CardUtils.ts | 9 + .../WorkspaceCompanyCardPageEmptyState.tsx | 16 +- tests/unit/CardUtilsTest.ts | 168 +++++++++++------- 3 files changed, 125 insertions(+), 68 deletions(-) diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index 7a48cf6bcf90..4f5a55f3cf73 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -512,6 +512,14 @@ function checkIfFeedConnectionIsBroken(feedCards: Record | undefin return Object.values(feedCards).some((card) => card.bank !== feedToExclude && card.lastScrapeResult !== 200); } +/** + * Checks if an Expensify Card was issued for a given workspace. The `allCardList` argument was added for testing purposes. + */ +function hasIssuedExpensifyCard(workspaceAccountID: number, allCardList?: OnyxCollection): boolean { + const cards = getAllCardsForWorkspace(workspaceAccountID, allCardList); + return Object.values(cards).some((card) => card.bank === CONST.EXPENSIFY_CARD.BANK); +} + export { isExpensifyCard, isCorporateCard, @@ -549,4 +557,5 @@ export { getFeedType, flatAllCardsList, checkIfFeedConnectionIsBroken, + hasIssuedExpensifyCard, }; diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx index d31deed58d23..1450121225be 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx @@ -4,30 +4,32 @@ import {useOnyx} from 'react-native-onyx'; import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import FeatureList from '@components/FeatureList'; import type {FeatureListItem} from '@components/FeatureList'; -import * as Illustrations from '@components/Icon/Illustrations'; +import {CompanyCardsEmptyState, CreditCardsNew, HandCard, MagnifyingGlassMoney} from '@components/Icon/Illustrations'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; +import {hasIssuedExpensifyCard} from '@libs/CardUtils'; import Navigation from '@libs/Navigation/Navigation'; import withPolicyAndFullscreenLoading from '@pages/workspace/withPolicyAndFullscreenLoading'; import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading'; import colors from '@styles/theme/colors'; import {clearAddNewCardFlow} from '@userActions/CompanyCards'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import WorkspaceCompanyCardExpensifyCardPromotionBanner from './WorkspaceCompanyCardExpensifyCardPromotionBanner'; const companyCardFeatures: FeatureListItem[] = [ { - icon: Illustrations.CreditCardsNew, + icon: CreditCardsNew, translationKey: 'workspace.moreFeatures.companyCards.feed.features.support', }, { - icon: Illustrations.HandCard, + icon: HandCard, translationKey: 'workspace.moreFeatures.companyCards.feed.features.assignCards', }, { - icon: Illustrations.MagnifyingGlassMoney, + icon: MagnifyingGlassMoney, translationKey: 'workspace.moreFeatures.companyCards.feed.features.automaticImport', }, ]; @@ -36,9 +38,9 @@ function WorkspaceCompanyCardPageEmptyState({policy}: WithPolicyAndFullscreenLoa const {translate} = useLocalize(); const styles = useThemeStyles(); const {shouldUseNarrowLayout} = useResponsiveLayout(); - const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); + const shouldShowExpensifyCardPromotionBanner = !hasIssuedExpensifyCard(policy?.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID); const handleCtaPress = useCallback(() => { if (!policy?.id) { @@ -54,7 +56,7 @@ function WorkspaceCompanyCardPageEmptyState({policy}: WithPolicyAndFullscreenLoa return ( - + {shouldShowExpensifyCardPromotionBanner && } = { +const cardFeedsCollection: OnyxCollection = { // Policy with both custom and direct feeds FAKE_ID_1: { settings: { @@ -223,113 +237,113 @@ const allCardsList = { state: 2, }, }, -} as OnyxCollection; +} as OnyxCollection; /* eslint-enable @typescript-eslint/naming-convention */ describe('CardUtils', () => { describe('Expiration date formatting', () => { it('Should format expirationDate month and year to MM/YYYY', () => { - expect(CardUtils.getMonthFromExpirationDateString(longDateSlashed)).toBe(expectedMonth); - expect(CardUtils.getYearFromExpirationDateString(longDateSlashed)).toBe(expectedYear); + expect(getMonthFromExpirationDateString(longDateSlashed)).toBe(expectedMonth); + expect(getYearFromExpirationDateString(longDateSlashed)).toBe(expectedYear); }); it('Should format expirationDate month and year to MM-YYYY', () => { - expect(CardUtils.getMonthFromExpirationDateString(longDateHyphen)).toBe(expectedMonth); - expect(CardUtils.getYearFromExpirationDateString(longDateHyphen)).toBe(expectedYear); + expect(getMonthFromExpirationDateString(longDateHyphen)).toBe(expectedMonth); + expect(getYearFromExpirationDateString(longDateHyphen)).toBe(expectedYear); }); it('Should format expirationDate month and year to MMYYYY', () => { - expect(CardUtils.getMonthFromExpirationDateString(longDate)).toBe(expectedMonth); - expect(CardUtils.getYearFromExpirationDateString(longDate)).toBe(expectedYear); + expect(getMonthFromExpirationDateString(longDate)).toBe(expectedMonth); + expect(getYearFromExpirationDateString(longDate)).toBe(expectedYear); }); it('Should format expirationDate month and year to MM/YY', () => { - expect(CardUtils.getMonthFromExpirationDateString(shortDateSlashed)).toBe(expectedMonth); - expect(CardUtils.getYearFromExpirationDateString(shortDateSlashed)).toBe(expectedYear); + expect(getMonthFromExpirationDateString(shortDateSlashed)).toBe(expectedMonth); + expect(getYearFromExpirationDateString(shortDateSlashed)).toBe(expectedYear); }); it('Should format expirationDate month and year to MM-YY', () => { - expect(CardUtils.getMonthFromExpirationDateString(shortDateHyphen)).toBe(expectedMonth); - expect(CardUtils.getYearFromExpirationDateString(shortDateHyphen)).toBe(expectedYear); + expect(getMonthFromExpirationDateString(shortDateHyphen)).toBe(expectedMonth); + expect(getYearFromExpirationDateString(shortDateHyphen)).toBe(expectedYear); }); it('Should format expirationDate month and year to MMYY', () => { - expect(CardUtils.getMonthFromExpirationDateString(shortDate)).toBe(expectedMonth); - expect(CardUtils.getYearFromExpirationDateString(shortDate)).toBe(expectedYear); + expect(getMonthFromExpirationDateString(shortDate)).toBe(expectedMonth); + expect(getYearFromExpirationDateString(shortDate)).toBe(expectedYear); }); it('Should format to MM/YYYY given MM/YY', () => { - expect(CardUtils.formatCardExpiration(shortDateSlashed)).toBe(longDateSlashed); - expect(CardUtils.formatCardExpiration(shortDateSlashed)).toBe(longDateSlashed); + expect(formatCardExpiration(shortDateSlashed)).toBe(longDateSlashed); + expect(formatCardExpiration(shortDateSlashed)).toBe(longDateSlashed); }); it('Should format to MM/YYYY given MMYY', () => { - expect(CardUtils.formatCardExpiration(shortDate)).toBe(longDateSlashed); - expect(CardUtils.formatCardExpiration(shortDate)).toBe(longDateSlashed); + expect(formatCardExpiration(shortDate)).toBe(longDateSlashed); + expect(formatCardExpiration(shortDate)).toBe(longDateSlashed); }); }); describe('isCustomFeed', () => { it('Should return true for the custom visa feed with no number', () => { const customFeed = CONST.COMPANY_CARD.FEED_BANK_NAME.VISA; - const isCustomFeed = CardUtils.isCustomFeed(customFeed); + const isCustomFeed = isCustomFeedCardUtils(customFeed); expect(isCustomFeed).toBe(true); }); it('Should return true for the custom visa feed with a number', () => { const customFeed = `${CONST.COMPANY_CARD.FEED_BANK_NAME.VISA}1` as CompanyCardFeedWithNumber; - const isCustomFeed = CardUtils.isCustomFeed(customFeed); + const isCustomFeed = isCustomFeedCardUtils(customFeed); expect(isCustomFeed).toBe(true); }); it('Should return true for the custom mastercard feed with no number', () => { const customFeed = CONST.COMPANY_CARD.FEED_BANK_NAME.MASTER_CARD; - const isCustomFeed = CardUtils.isCustomFeed(customFeed); + const isCustomFeed = isCustomFeedCardUtils(customFeed); expect(isCustomFeed).toBe(true); }); it('Should return true for the custom mastercard feed with a number', () => { const customFeed = `${CONST.COMPANY_CARD.FEED_BANK_NAME.MASTER_CARD}3` as CompanyCardFeedWithNumber; - const isCustomFeed = CardUtils.isCustomFeed(customFeed); + const isCustomFeed = isCustomFeedCardUtils(customFeed); expect(isCustomFeed).toBe(true); }); it('Should return true for the custom amex feed with no number', () => { const customFeed = CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX; - const isCustomFeed = CardUtils.isCustomFeed(customFeed); + const isCustomFeed = isCustomFeedCardUtils(customFeed); expect(isCustomFeed).toBe(true); }); it('Should return true for the custom amex feed with a number', () => { const customFeed = `${CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX}2` as CompanyCardFeedWithNumber; - const isCustomFeed = CardUtils.isCustomFeed(customFeed); + const isCustomFeed = isCustomFeedCardUtils(customFeed); expect(isCustomFeed).toBe(true); }); test.each(directFeedBanks)('Should return false for the direct feed %s', (directFeed) => { - const isCustomFeed = CardUtils.isCustomFeed(directFeed); + const isCustomFeed = isCustomFeedCardUtils(directFeed); expect(isCustomFeed).toBe(false); }); }); describe('getCompanyFeeds', () => { it('Should return both custom and direct feeds with filtered out "Expensify Card" bank', () => { - const companyFeeds = CardUtils.getCompanyFeeds(cardFeedsCollection.FAKE_ID_1); + const companyFeeds = getCompanyFeeds(cardFeedsCollection.FAKE_ID_1); expect(companyFeeds).toStrictEqual(companyCardsSettingsWithoutExpensifyBank); }); it('Should return direct feeds only since custom feeds are not exist', () => { - const companyFeeds = CardUtils.getCompanyFeeds(cardFeedsCollection.FAKE_ID_2); + const companyFeeds = getCompanyFeeds(cardFeedsCollection.FAKE_ID_2); expect(companyFeeds).toStrictEqual(companyCardsDirectFeedSettings); }); it('Should return custom feeds only with filtered out "Expensify Card" bank since direct feeds are not exist', () => { - const companyFeeds = CardUtils.getCompanyFeeds(cardFeedsCollection.FAKE_ID_3); + const companyFeeds = getCompanyFeeds(cardFeedsCollection.FAKE_ID_3); expect(companyFeeds).toStrictEqual(companyCardsCustomFeedSettingsWithoutExpensifyBank); }); it('Should return empty object if undefined is passed', () => { - const companyFeeds = CardUtils.getCompanyFeeds(undefined); + const companyFeeds = getCompanyFeeds(undefined); expect(companyFeeds).toStrictEqual({}); }); }); @@ -337,32 +351,32 @@ describe('CardUtils', () => { describe('getSelectedFeed', () => { it('Should return last selected custom feed', () => { const lastSelectedCustomFeed = CONST.COMPANY_CARD.FEED_BANK_NAME.VISA; - const selectedFeed = CardUtils.getSelectedFeed(lastSelectedCustomFeed, cardFeedsCollection.FAKE_ID_1); + const selectedFeed = getSelectedFeed(lastSelectedCustomFeed, cardFeedsCollection.FAKE_ID_1); expect(selectedFeed).toBe(lastSelectedCustomFeed); }); it('Should return last selected direct feed', () => { const lastSelectedDirectFeed = CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE; - const selectedFeed = CardUtils.getSelectedFeed(lastSelectedDirectFeed, cardFeedsCollection.FAKE_ID_1); + const selectedFeed = getSelectedFeed(lastSelectedDirectFeed, cardFeedsCollection.FAKE_ID_1); expect(selectedFeed).toBe(lastSelectedDirectFeed); }); it('Should return the first available custom feed if lastSelectedFeed is undefined', () => { const lastSelectedFeed = undefined; - const selectedFeed = CardUtils.getSelectedFeed(lastSelectedFeed, cardFeedsCollection.FAKE_ID_3); + const selectedFeed = getSelectedFeed(lastSelectedFeed, cardFeedsCollection.FAKE_ID_3); expect(selectedFeed).toBe(CONST.COMPANY_CARD.FEED_BANK_NAME.MASTER_CARD); }); it('Should return the first available direct feed if lastSelectedFeed is undefined', () => { const lastSelectedFeed = undefined; - const selectedFeed = CardUtils.getSelectedFeed(lastSelectedFeed, cardFeedsCollection.FAKE_ID_2); + const selectedFeed = getSelectedFeed(lastSelectedFeed, cardFeedsCollection.FAKE_ID_2); expect(selectedFeed).toBe(CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE); }); it('Should return undefined if lastSelectedFeed is undefined and there is no card feeds', () => { const lastSelectedFeed = undefined; const cardFeeds = undefined; - const selectedFeed = CardUtils.getSelectedFeed(lastSelectedFeed, cardFeeds); + const selectedFeed = getSelectedFeed(lastSelectedFeed, cardFeeds); expect(selectedFeed).toBe(undefined); }); }); @@ -371,21 +385,21 @@ describe('CardUtils', () => { it('Should return custom name if exists', () => { const feed = CONST.COMPANY_CARD.FEED_BANK_NAME.VISA; const companyCardNicknames = cardFeedsCollection.FAKE_ID_1?.settings?.companyCardNicknames; - const feedName = CardUtils.getCustomOrFormattedFeedName(feed, companyCardNicknames); + const feedName = getCustomOrFormattedFeedName(feed, companyCardNicknames); expect(feedName).toBe(customFeedName); }); it('Should return formatted name if there is no custom name', () => { const feed = CONST.COMPANY_CARD.FEED_BANK_NAME.VISA; const companyCardNicknames = cardFeedsCollection.FAKE_ID_3?.settings?.companyCardNicknames; - const feedName = CardUtils.getCustomOrFormattedFeedName(feed, companyCardNicknames); + const feedName = getCustomOrFormattedFeedName(feed, companyCardNicknames); expect(feedName).toBe('Visa cards'); }); it('Should return undefined if no feed provided', () => { const feed = undefined; const companyCardNicknames = cardFeedsCollection.FAKE_ID_1?.settings?.companyCardNicknames; - const feedName = CardUtils.getCustomOrFormattedFeedName(feed, companyCardNicknames); + const feedName = getCustomOrFormattedFeedName(feed, companyCardNicknames); expect(feedName).toBe(undefined); }); }); @@ -393,36 +407,36 @@ describe('CardUtils', () => { describe('maskCardNumber', () => { it("Should return the card number divided into chunks of 4, with 'X' replaced by '•' if it's provided in the '480801XXXXXX2554' format", () => { const cardNumber = '480801XXXXXX2554'; - const maskedCardNumber = CardUtils.maskCardNumber(cardNumber, CONST.COMPANY_CARD.FEED_BANK_NAME.MASTER_CARD); + const maskedCardNumber = maskCardNumber(cardNumber, CONST.COMPANY_CARD.FEED_BANK_NAME.MASTER_CARD); expect(maskedCardNumber).toBe('4808 01•• •••• 2554'); }); it('Should return card number without changes if it has empty space', () => { const cardNumber = 'CREDIT CARD...6607'; - const maskedCardNumber = CardUtils.maskCardNumber(cardNumber, CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE); + const maskedCardNumber = maskCardNumber(cardNumber, CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE); expect(maskedCardNumber).toBe(cardNumber); }); it("Should return the Amex direct feed card number divided into 4/6/5 chunks, with 'X' replaced by '•' if it's provided in '211944XXXXX6557' format", () => { const cardNumber = '211944XXXXX6557'; - const maskedCardNumber = CardUtils.maskCardNumber(cardNumber, CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX_DIRECT); + const maskedCardNumber = maskCardNumber(cardNumber, CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX_DIRECT); expect(maskedCardNumber).toBe('2119 44•••• •6557'); }); it("Should return the Amex custom feed card number divided into 4/6/5 chunks, with 'X' replaced by '•' if it's provided in '211944XXXXX6557' format", () => { const cardNumber = '211944XXXXX6557'; - const maskedCardNumber = CardUtils.maskCardNumber(cardNumber, CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX); + const maskedCardNumber = maskCardNumber(cardNumber, CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX); expect(maskedCardNumber).toBe('2119 44•••• •6557'); }); it('Should return masked card number even if undefined feed was provided', () => { const cardNumber = '480801XXXXXX2554'; - const maskedCardNumber = CardUtils.maskCardNumber(cardNumber, undefined); + const maskedCardNumber = maskCardNumber(cardNumber, undefined); expect(maskedCardNumber).toBe('4808 01•• •••• 2554'); }); it('Should return empty string if invalid card name was provided', () => { - const maskedCardNumber = CardUtils.maskCardNumber('', CONST.COMPANY_CARD.FEED_BANK_NAME.MASTER_CARD); + const maskedCardNumber = maskCardNumber('', CONST.COMPANY_CARD.FEED_BANK_NAME.MASTER_CARD); expect(maskedCardNumber).toBe(''); }); }); @@ -430,26 +444,26 @@ describe('CardUtils', () => { describe('getCardFeedName', () => { it('Should return a valid name if a valid feed was provided', () => { const feed = 'vcf'; - const feedName = CardUtils.getBankName(feed); + const feedName = getBankName(feed); expect(feedName).toBe('Visa'); }); it('Should return a valid name if an OldDot feed variation was provided', () => { - const feed = 'oauth.americanexpressfdx.com 2003' as OnyxTypes.CompanyCardFeed; - const feedName = CardUtils.getBankName(feed); + const feed = 'oauth.americanexpressfdx.com 2003' as CompanyCardFeed; + const feedName = getBankName(feed); expect(feedName).toBe('American Express'); }); it('Should return empty string if invalid feed was provided', () => { - const feed = 'vvcf' as OnyxTypes.CompanyCardFeed; - const feedName = CardUtils.getBankName(feed); + const feed = 'vvcf' as CompanyCardFeed; + const feedName = getBankName(feed); expect(feedName).toBe(''); }); }); describe('getFilteredCardList', () => { it('Should return filtered custom feed cards list', () => { - const cardsList = CardUtils.getFilteredCardList(customFeedCardsList, undefined); + const cardsList = getFilteredCardList(customFeedCardsList, undefined); expect(cardsList).toStrictEqual({ // eslint-disable-next-line @typescript-eslint/naming-convention '480801XXXXXX2111': 'ENCRYPTED_CARD_NUMBER', @@ -459,13 +473,13 @@ describe('CardUtils', () => { }); it('Should return filtered direct feed cards list with a single card', () => { - const cardsList = CardUtils.getFilteredCardList(directFeedCardsSingleList, oAuthAccountDetails[CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE]); + const cardsList = getFilteredCardList(directFeedCardsSingleList, oAuthAccountDetails[CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE]); // eslint-disable-next-line @typescript-eslint/naming-convention expect(cardsList).toStrictEqual({'CREDIT CARD...6607': 'CREDIT CARD...6607'}); }); it('Should return filtered direct feed cards list with multiple cards', () => { - const cardsList = CardUtils.getFilteredCardList(directFeedCardsMultipleList, oAuthAccountDetails[CONST.COMPANY_CARD.FEED_BANK_NAME.CAPITAL_ONE]); + const cardsList = getFilteredCardList(directFeedCardsMultipleList, oAuthAccountDetails[CONST.COMPANY_CARD.FEED_BANK_NAME.CAPITAL_ONE]); expect(cardsList).toStrictEqual({ // eslint-disable-next-line @typescript-eslint/naming-convention 'CREDIT CARD...1233': 'CREDIT CARD...1233', @@ -477,24 +491,24 @@ describe('CardUtils', () => { }); it('Should return empty object if no data was provided', () => { - const cardsList = CardUtils.getFilteredCardList(undefined, undefined); + const cardsList = getFilteredCardList(undefined, undefined); expect(cardsList).toStrictEqual({}); }); }); describe('getFeedType', () => { it('should return the feed name with a consecutive number, if there is already a feed with a number', () => { - const feedType = CardUtils.getFeedType('vcf', cardFeedsCollection.FAKE_ID_4); + const feedType = getFeedType('vcf', cardFeedsCollection.FAKE_ID_4); expect(feedType).toBe('vcf2'); }); it('should return the feed name with 1, if there is already a feed without a number', () => { - const feedType = CardUtils.getFeedType('vcf', cardFeedsCollection.FAKE_ID_3); + const feedType = getFeedType('vcf', cardFeedsCollection.FAKE_ID_3); expect(feedType).toBe('vcf1'); }); it('should return the feed name with with the first smallest available number', () => { - const feedType = CardUtils.getFeedType('vcf', cardFeedsCollection.FAKE_ID_5); + const feedType = getFeedType('vcf', cardFeedsCollection.FAKE_ID_5); expect(feedType).toBe('vcf2'); }); }); @@ -536,4 +550,36 @@ describe('CardUtils', () => { expect(checkIfFeedConnectionIsBroken(cards, feedToExclude)).toBeFalsy(); }); }); + + describe('checkIfFeedConnectionIsBroken', () => { + it('should return true if at least one of the feed(s) cards has the lastScrapeResult not equal to 200', () => { + expect(checkIfFeedConnectionIsBroken(directFeedCardsMultipleList)).toBeTruthy(); + }); + + it('should return false if all of the feed(s) cards has the lastScrapeResult equal to 200', () => { + expect(checkIfFeedConnectionIsBroken(directFeedCardsSingleList)).toBeFalsy(); + }); + + it('should return false if no feed(s) cards are provided', () => { + expect(checkIfFeedConnectionIsBroken({})).toBeFalsy(); + }); + + it('should not take into consideration cards related to feed which is provided as feedToExclude', () => { + const cards = {...directFeedCardsMultipleList, ...directFeedCardsSingleList}; + const feedToExclude = CONST.COMPANY_CARD.FEED_BANK_NAME.CAPITAL_ONE; + expect(checkIfFeedConnectionIsBroken(cards, feedToExclude)).toBeFalsy(); + }); + }); + + describe('hasIssuedExpensifyCard', () => { + it('should return true when Expensify Card was issued for given workspace', () => { + const workspaceAccountID = 11111111; + expect(hasIssuedExpensifyCard(workspaceAccountID, allCardsList)).toBe(true); + }); + + it('should return false when Expensify Card was not issued for given workspace', () => { + const workspaceAccountID = 11111111; + expect(hasIssuedExpensifyCard(workspaceAccountID, {})).toBe(false); + }); + }); }); From 5a814050e8b8d97aeeaa18ac315f0eabdf8d5f73 Mon Sep 17 00:00:00 2001 From: Kevin Brian Bader Date: Fri, 21 Feb 2025 14:57:15 -0800 Subject: [PATCH 2/2] code review adjustments and sync w/ main --- src/libs/CardUtils.ts | 4 ++-- .../companyCards/WorkspaceCompanyCardPageEmptyState.tsx | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index 1db5539ce496..0e65c66d963e 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -517,9 +517,9 @@ function checkIfFeedConnectionIsBroken(feedCards: Record | undefin } /** - * Checks if an Expensify Card was issued for a given workspace. The `allCardList` argument was added for testing purposes. + * Checks if an Expensify Card was issued for a given workspace. */ -function hasIssuedExpensifyCard(workspaceAccountID: number, allCardList?: OnyxCollection): boolean { +function hasIssuedExpensifyCard(workspaceAccountID: number, allCardList: OnyxCollection = allWorkspaceCards): boolean { const cards = getAllCardsForWorkspace(workspaceAccountID, allCardList); return Object.values(cards).some((card) => card.bank === CONST.EXPENSIFY_CARD.BANK); } diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx index 1450121225be..bbb77685c2f8 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState.tsx @@ -40,7 +40,8 @@ function WorkspaceCompanyCardPageEmptyState({policy}: WithPolicyAndFullscreenLoa const {shouldUseNarrowLayout} = useResponsiveLayout(); const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: (account) => !!account?.delegatedAccess?.delegate}); const [isNoDelegateAccessMenuVisible, setIsNoDelegateAccessMenuVisible] = useState(false); - const shouldShowExpensifyCardPromotionBanner = !hasIssuedExpensifyCard(policy?.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID); + const [allWorkspaceCards] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST); + const shouldShowExpensifyCardPromotionBanner = !hasIssuedExpensifyCard(policy?.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID, allWorkspaceCards); const handleCtaPress = useCallback(() => { if (!policy?.id) {