From 932bef80768604ced30af929540ab8c3a382bbe8 Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 26 Nov 2024 11:57:27 +0100 Subject: [PATCH 1/3] Fix getCardFeedName method and add tests --- src/libs/CardUtils.ts | 9 ++++++++- tests/unit/CardUtilsTest.ts | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index 4f6bf6036538..960ce32e0ad0 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -279,7 +279,14 @@ function getCardFeedName(feedType: CompanyCardFeed): string { [CONST.COMPANY_CARD.FEED_BANK_NAME.BREX]: 'Brex', }; - return feedNamesMapping[feedType]; + // In existing OldDot setups other variations of feeds could exist, ex: vcf2, vcf3, oauth.americanexpressfdx.com 2003 + const feedKey = (Object.keys(feedNamesMapping) as CompanyCardFeed[]).find((feed) => feedType.startsWith(feed)); + + if (!feedKey) { + return ''; + } + + return feedNamesMapping[feedKey]; } const getBankCardDetailsImage = (bank: ValueOf): IconAsset => { diff --git a/tests/unit/CardUtilsTest.ts b/tests/unit/CardUtilsTest.ts index 9d4af5aa3760..1377b89bc441 100644 --- a/tests/unit/CardUtilsTest.ts +++ b/tests/unit/CardUtilsTest.ts @@ -252,4 +252,24 @@ describe('CardUtils', () => { expect(maskedCardNumber).toBe(''); }); }); + + describe('getCardFeedName', () => { + it('Should return a valid name if a valid feed was provided', () => { + const feed = 'vcf'; + const feedName = CardUtils.getCardFeedName(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.getCardFeedName(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.getCardFeedName(feed); + expect(feedName).toBe(''); + }); + }); }); From 29aeb8b79f4d4b5f06b16069545b1bc269898eec Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 26 Nov 2024 14:20:05 +0100 Subject: [PATCH 2/3] Fix feed connection navigation --- .../addNew/BankConnection/index.tsx | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/companyCards/addNew/BankConnection/index.tsx b/src/pages/workspace/companyCards/addNew/BankConnection/index.tsx index 98b19b8efbc7..ed5849d046eb 100644 --- a/src/pages/workspace/companyCards/addNew/BankConnection/index.tsx +++ b/src/pages/workspace/companyCards/addNew/BankConnection/index.tsx @@ -1,4 +1,4 @@ -import React, {useCallback, useEffect} from 'react'; +import React, {useCallback, useEffect, useMemo} from 'react'; import {useOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; import BlockingView from '@components/BlockingViews/BlockingView'; @@ -8,6 +8,7 @@ import ScreenWrapper from '@components/ScreenWrapper'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; import useLocalize from '@hooks/useLocalize'; +import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -18,7 +19,7 @@ import getCompanyCardBankConnection from '@userActions/getCompanyCardBankConnect import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; +import type {CompanyCardFeed} from '@src/types/onyx'; import openBankConnection from './openBankConnection'; let customWindow: Window | null = null; @@ -37,6 +38,18 @@ function BankConnection({policyID}: BankConnectionStepProps) { const bankKey = Object.keys(CONST.COMPANY_CARDS.BANKS).find((value) => CONST.COMPANY_CARDS.BANKS?.[value as keyof typeof CONST.COMPANY_CARDS.BANKS] === bankName); const feedName = bankKey && bankKey !== CONST.COMPANY_CARDS.BANKS.OTHER ? CONST.COMPANY_CARD.FEED_BANK_NAME?.[bankKey as keyof typeof CONST.COMPANY_CARD.FEED_BANK_NAME] : undefined; const connectedBank = feedName ? cardFeeds?.settings?.oAuthAccountDetails?.[feedName] : undefined; + const prevFeedsData = usePrevious(cardFeeds?.settings?.oAuthAccountDetails); + const {isNewFeedConnected, newFeed} = useMemo(() => { + const prevFeeds = Object.keys(prevFeedsData ?? {}); + const currentFeeds = Object.keys(cardFeeds?.settings?.oAuthAccountDetails ?? {}); + const isNewFeed = currentFeeds.length > prevFeeds.length; + + if (!isNewFeed) { + return {isNewFeedConnected: false}; + } + + return {isNewFeedConnected: true, newFeed: currentFeeds.find((feed) => !prevFeeds.includes(feed)) as CompanyCardFeed}; + }, [cardFeeds, prevFeedsData]); const currentUrl = getCurrentUrl(); const isBankConnectionCompleteRoute = currentUrl.includes(ROUTES.BANK_CONNECTION_COMPLETE); @@ -73,9 +86,11 @@ function BankConnection({policyID}: BankConnectionStepProps) { if (!url) { return; } - if (feedName && connectedBank && !isEmptyObject(connectedBank)) { + if (isNewFeedConnected) { customWindow?.close(); - Card.updateSelectedFeed(feedName, policyID ?? '-1'); + if (newFeed) { + Card.updateSelectedFeed(newFeed, policyID ?? '-1'); + } Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS.getRoute(policyID ?? '-1')); return; } From a19489994a9e8bc9517971f54dba98becf3f7eaa Mon Sep 17 00:00:00 2001 From: VickyStash Date: Tue, 26 Nov 2024 14:39:02 +0100 Subject: [PATCH 3/3] Code improvements --- src/libs/CardUtils.ts | 11 +++++++++++ .../addNew/BankConnection/index.native.tsx | 18 ++++++++++-------- .../addNew/BankConnection/index.tsx | 19 +++---------------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index 960ce32e0ad0..211bd8e53c55 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -369,6 +369,16 @@ function getDefaultCardName(cardholder?: string) { return `${cardholder}'s card`; } +function checkIfNewFeedConnected(prevFeedsData: CompanyFeeds, currentFeedsData: CompanyFeeds) { + const prevFeeds = Object.keys(prevFeedsData); + const currentFeeds = Object.keys(currentFeedsData); + + return { + isNewFeedConnected: currentFeeds.length > prevFeeds.length, + newFeed: currentFeeds.find((feed) => !prevFeeds.includes(feed)) as CompanyCardFeed | undefined, + }; +} + export { isExpensifyCard, isCorporateCard, @@ -396,5 +406,6 @@ export { removeExpensifyCardFromCompanyCards, getFilteredCardList, hasOnlyOneCardToAssign, + checkIfNewFeedConnected, getDefaultCardName, }; diff --git a/src/pages/workspace/companyCards/addNew/BankConnection/index.native.tsx b/src/pages/workspace/companyCards/addNew/BankConnection/index.native.tsx index b465704a7995..4081cacaf74e 100644 --- a/src/pages/workspace/companyCards/addNew/BankConnection/index.native.tsx +++ b/src/pages/workspace/companyCards/addNew/BankConnection/index.native.tsx @@ -1,4 +1,4 @@ -import React, {useEffect, useRef, useState} from 'react'; +import React, {useEffect, useMemo, useRef, useState} from 'react'; import {useOnyx} from 'react-native-onyx'; import {WebView} from 'react-native-webview'; import type {ValueOf} from 'type-fest'; @@ -7,6 +7,8 @@ import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import Modal from '@components/Modal'; import useLocalize from '@hooks/useLocalize'; +import usePrevious from '@hooks/usePrevious'; +import * as CardUtils from '@libs/CardUtils'; import getUAForWebView from '@libs/getUAForWebView'; import Navigation from '@libs/Navigation/Navigation'; import * as PolicyUtils from '@libs/PolicyUtils'; @@ -16,7 +18,6 @@ import getCompanyCardBankConnection from '@userActions/getCompanyCardBankConnect import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {isEmptyObject} from '@src/types/utils/EmptyObject'; type BankConnectionStepProps = { policyID?: string; @@ -33,9 +34,8 @@ function BankConnection({policyID}: BankConnectionStepProps) { const url = getCompanyCardBankConnection(policyID, bankName); const workspaceAccountID = PolicyUtils.getWorkspaceAccountID(policyID ?? '-1'); const [cardFeeds] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`); - const bankKey = Object.keys(CONST.COMPANY_CARDS.BANKS).find((value) => CONST.COMPANY_CARDS.BANKS?.[value as keyof typeof CONST.COMPANY_CARDS.BANKS] === bankName); - const feedName = bankKey && bankKey !== CONST.COMPANY_CARDS.BANKS.OTHER ? CONST.COMPANY_CARD.FEED_BANK_NAME?.[bankKey as keyof typeof CONST.COMPANY_CARD.FEED_BANK_NAME] : undefined; - const connectedBank = feedName ? cardFeeds?.settings?.oAuthAccountDetails?.[feedName] : undefined; + const prevFeedsData = usePrevious(cardFeeds?.settings?.oAuthAccountDetails); + const {isNewFeedConnected, newFeed} = useMemo(() => CardUtils.checkIfNewFeedConnected(prevFeedsData ?? {}, cardFeeds?.settings?.oAuthAccountDetails ?? {}), [cardFeeds, prevFeedsData]); const renderLoading = () => ; @@ -60,11 +60,13 @@ function BankConnection({policyID}: BankConnectionStepProps) { if (!url) { return; } - if (feedName && connectedBank && !isEmptyObject(connectedBank)) { - Card.updateSelectedFeed(feedName, policyID ?? '-1'); + if (isNewFeedConnected) { + if (newFeed) { + Card.updateSelectedFeed(newFeed, policyID ?? '-1'); + } Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS.getRoute(policyID ?? '-1')); } - }, [connectedBank, feedName, policyID, url]); + }, [isNewFeedConnected, newFeed, policyID, url]); return ( | undefined = addNewCard?.data?.selectedBank; const workspaceAccountID = PolicyUtils.getWorkspaceAccountID(policyID ?? '-1'); const [cardFeeds] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${workspaceAccountID}`); - const bankKey = Object.keys(CONST.COMPANY_CARDS.BANKS).find((value) => CONST.COMPANY_CARDS.BANKS?.[value as keyof typeof CONST.COMPANY_CARDS.BANKS] === bankName); - const feedName = bankKey && bankKey !== CONST.COMPANY_CARDS.BANKS.OTHER ? CONST.COMPANY_CARD.FEED_BANK_NAME?.[bankKey as keyof typeof CONST.COMPANY_CARD.FEED_BANK_NAME] : undefined; - const connectedBank = feedName ? cardFeeds?.settings?.oAuthAccountDetails?.[feedName] : undefined; const prevFeedsData = usePrevious(cardFeeds?.settings?.oAuthAccountDetails); - const {isNewFeedConnected, newFeed} = useMemo(() => { - const prevFeeds = Object.keys(prevFeedsData ?? {}); - const currentFeeds = Object.keys(cardFeeds?.settings?.oAuthAccountDetails ?? {}); - const isNewFeed = currentFeeds.length > prevFeeds.length; - - if (!isNewFeed) { - return {isNewFeedConnected: false}; - } - - return {isNewFeedConnected: true, newFeed: currentFeeds.find((feed) => !prevFeeds.includes(feed)) as CompanyCardFeed}; - }, [cardFeeds, prevFeedsData]); + const {isNewFeedConnected, newFeed} = useMemo(() => CardUtils.checkIfNewFeedConnected(prevFeedsData ?? {}, cardFeeds?.settings?.oAuthAccountDetails ?? {}), [cardFeeds, prevFeedsData]); const currentUrl = getCurrentUrl(); const isBankConnectionCompleteRoute = currentUrl.includes(ROUTES.BANK_CONNECTION_COMPLETE); @@ -99,7 +86,7 @@ function BankConnection({policyID}: BankConnectionStepProps) { return; } customWindow = openBankConnection(url); - }, [connectedBank, feedName, isBankConnectionCompleteRoute, policyID, url]); + }, [isNewFeedConnected, newFeed, isBankConnectionCompleteRoute, policyID, url]); return (