Skip to content

Commit 2273f92

Browse files
authored
Merge pull request Expensify#89457 from fedirjh/fix-rbr-broken-feed
Fix extra/missing RBRs on company card feed selector
2 parents 190856c + fa85068 commit 2273f92

2 files changed

Lines changed: 165 additions & 3 deletions

File tree

src/components/Tables/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableHeaderButtons.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,12 @@ function WorkspaceCompanyCardsTableHeaderButtons({policyID, feedName, isLoading,
6666
const [countryByIp] = useOnyx(ONYXKEYS.COUNTRY);
6767
const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
6868

69-
const {cardFeedErrors} = useCardFeedErrors();
69+
const {cardFeedErrors, shouldShowRbrForFeedNameWithDomainID} = useCardFeedErrors();
7070
const feedErrors = cardFeedErrors[feedName];
7171
const hasFeedErrors = feedErrors?.hasFeedErrors;
7272
const isFeedConnectionBroken = feedErrors?.isFeedConnectionBroken;
73-
const shouldShowRBR = feedErrors?.shouldShowRBR;
73+
const hasOtherFeedWithRBR = Object.keys(companyFeeds ?? {}).some((feed) => feed !== feedName && shouldShowRbrForFeedNameWithDomainID[feed]);
74+
const shouldShowFeedSelectorRBR = hasOtherFeedWithRBR || !!feedErrors?.hasWorkspaceErrors;
7475

7576
const openBankConnection = () => {
7677
if (!feedName) {
@@ -144,7 +145,7 @@ function WorkspaceCompanyCardsTableHeaderButtons({policyID, feedName, isLoading,
144145
CardFeedIcon={CardFeedIcon}
145146
feedName={formattedFeedName}
146147
supportingText={supportingText}
147-
shouldShowRBR={shouldShowRBR}
148+
shouldShowRBR={shouldShowFeedSelectorRBR}
148149
/>
149150
)}
150151

tests/unit/CardFeedErrorsDerivedValueTest.ts

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,5 +551,166 @@ describe('CardFeedErrors Derived Value', () => {
551551
expect(result.all.shouldShowRBR).toBe(false);
552552
});
553553
});
554+
555+
describe('feed selector RBR - per-feed granularity for multi-feed workspaces', () => {
556+
const SHARED_WORKSPACE_ACCOUNT_ID = 77777777;
557+
const AMEX_FEED = {
558+
workspaceAccountID: SHARED_WORKSPACE_ACCOUNT_ID,
559+
feedName: CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX_DIRECT,
560+
feedNameWithDomainID: getCardFeedWithDomainID(CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX_DIRECT, SHARED_WORKSPACE_ACCOUNT_ID),
561+
};
562+
const CHASE_FEED = {
563+
workspaceAccountID: SHARED_WORKSPACE_ACCOUNT_ID,
564+
feedName: CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE,
565+
feedNameWithDomainID: getCardFeedWithDomainID(CONST.COMPANY_CARD.FEED_BANK_NAME.CHASE, SHARED_WORKSPACE_ACCOUNT_ID),
566+
};
567+
568+
it('should mark only the broken feed when another feed in the same workspace is healthy', () => {
569+
const brokenCard = createCard({
570+
cardID: CARD_IDS.card1,
571+
bank: CHASE_FEED.feedName,
572+
fundID: String(SHARED_WORKSPACE_ACCOUNT_ID),
573+
lastScrapeResult: 403,
574+
});
575+
const healthyCard = createCard({
576+
cardID: CARD_IDS.card2,
577+
bank: AMEX_FEED.feedName,
578+
fundID: String(SHARED_WORKSPACE_ACCOUNT_ID),
579+
lastScrapeResult: 200,
580+
});
581+
582+
const globalCardList: CardList = {
583+
[CARD_IDS.card1]: brokenCard,
584+
[CARD_IDS.card2]: healthyCard,
585+
};
586+
587+
const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}], DERIVED_VALUE_CONTEXT);
588+
589+
expect(result.shouldShowRbrForFeedNameWithDomainID[CHASE_FEED.feedNameWithDomainID]).toBe(true);
590+
expect(result.shouldShowRbrForFeedNameWithDomainID[AMEX_FEED.feedNameWithDomainID]).toBe(false);
591+
});
592+
593+
it('should clear RBR for a fixed feed while keeping it for other broken feeds', () => {
594+
const brokenMockCard = createCard({
595+
cardID: CARD_IDS.card1,
596+
bank: CHASE_FEED.feedName,
597+
fundID: String(SHARED_WORKSPACE_ACCOUNT_ID),
598+
lastScrapeResult: 403,
599+
});
600+
const fixedAmexCard = createCard({
601+
cardID: CARD_IDS.card2,
602+
bank: AMEX_FEED.feedName,
603+
fundID: String(SHARED_WORKSPACE_ACCOUNT_ID),
604+
lastScrapeResult: 200,
605+
});
606+
607+
const globalCardList: CardList = {
608+
[CARD_IDS.card1]: brokenMockCard,
609+
[CARD_IDS.card2]: fixedAmexCard,
610+
};
611+
612+
const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}], DERIVED_VALUE_CONTEXT);
613+
614+
expect(result.shouldShowRbrForFeedNameWithDomainID[CHASE_FEED.feedNameWithDomainID]).toBe(true);
615+
expect(result.shouldShowRbrForFeedNameWithDomainID[AMEX_FEED.feedNameWithDomainID]).toBe(false);
616+
expect(result.shouldShowRbrForWorkspaceAccountID[SHARED_WORKSPACE_ACCOUNT_ID]).toBe(true);
617+
});
618+
619+
it('should clear all RBR when all feeds in a workspace are healthy', () => {
620+
const healthyChaseCard = createCard({
621+
cardID: CARD_IDS.card1,
622+
bank: CHASE_FEED.feedName,
623+
fundID: String(SHARED_WORKSPACE_ACCOUNT_ID),
624+
lastScrapeResult: 200,
625+
});
626+
const healthyAmexCard = createCard({
627+
cardID: CARD_IDS.card2,
628+
bank: AMEX_FEED.feedName,
629+
fundID: String(SHARED_WORKSPACE_ACCOUNT_ID),
630+
lastScrapeResult: 200,
631+
});
632+
633+
const globalCardList: CardList = {
634+
[CARD_IDS.card1]: healthyChaseCard,
635+
[CARD_IDS.card2]: healthyAmexCard,
636+
};
637+
638+
const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}], DERIVED_VALUE_CONTEXT);
639+
640+
expect(result.shouldShowRbrForFeedNameWithDomainID[CHASE_FEED.feedNameWithDomainID]).toBe(false);
641+
expect(result.shouldShowRbrForFeedNameWithDomainID[AMEX_FEED.feedNameWithDomainID]).toBe(false);
642+
expect(result.shouldShowRbrForWorkspaceAccountID[SHARED_WORKSPACE_ACCOUNT_ID]).toBe(false);
643+
});
644+
645+
it('should show RBR on both feeds when both have broken connections', () => {
646+
const brokenChaseCard = createCard({
647+
cardID: CARD_IDS.card1,
648+
bank: CHASE_FEED.feedName,
649+
fundID: String(SHARED_WORKSPACE_ACCOUNT_ID),
650+
lastScrapeResult: 403,
651+
});
652+
const brokenAmexCard = createCard({
653+
cardID: CARD_IDS.card2,
654+
bank: AMEX_FEED.feedName,
655+
fundID: String(SHARED_WORKSPACE_ACCOUNT_ID),
656+
lastScrapeResult: 401,
657+
});
658+
659+
const globalCardList: CardList = {
660+
[CARD_IDS.card1]: brokenChaseCard,
661+
[CARD_IDS.card2]: brokenAmexCard,
662+
};
663+
664+
const result = cardFeedErrorsConfig.compute([globalCardList, {}, {}], DERIVED_VALUE_CONTEXT);
665+
666+
expect(result.shouldShowRbrForFeedNameWithDomainID[CHASE_FEED.feedNameWithDomainID]).toBe(true);
667+
expect(result.shouldShowRbrForFeedNameWithDomainID[AMEX_FEED.feedNameWithDomainID]).toBe(true);
668+
});
669+
670+
it('should only mark the feed with errors when mixed feed-level error and broken connection', () => {
671+
const healthyChaseCard = createCard({
672+
cardID: CARD_IDS.card1,
673+
bank: CHASE_FEED.feedName,
674+
fundID: String(SHARED_WORKSPACE_ACCOUNT_ID),
675+
lastScrapeResult: 200,
676+
});
677+
const healthyAmexCard = createCard({
678+
cardID: CARD_IDS.card2,
679+
bank: AMEX_FEED.feedName,
680+
fundID: String(SHARED_WORKSPACE_ACCOUNT_ID),
681+
lastScrapeResult: 200,
682+
});
683+
684+
const globalCardList: CardList = {
685+
[CARD_IDS.card1]: healthyChaseCard,
686+
[CARD_IDS.card2]: healthyAmexCard,
687+
};
688+
689+
const cardFeeds: OnyxCollection<CardFeeds> = {
690+
[`${ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_DOMAIN_MEMBER}${SHARED_WORKSPACE_ACCOUNT_ID}`]: {
691+
settings: {
692+
companyCards: {
693+
[AMEX_FEED.feedName]: {
694+
pending: false,
695+
errors: {feedError: 'Connection expired'},
696+
},
697+
[CHASE_FEED.feedName]: {
698+
pending: false,
699+
},
700+
},
701+
oAuthAccountDetails: {
702+
[AMEX_FEED.feedName]: {accountList: ['CREDIT CARD...1234'], credentials: 'xxxxx', expiration: 1730998958},
703+
[CHASE_FEED.feedName]: {accountList: ['CREDIT CARD...5678'], credentials: 'xxxxx', expiration: 1730998958},
704+
},
705+
},
706+
},
707+
};
708+
709+
const result = cardFeedErrorsConfig.compute([globalCardList, {}, cardFeeds], DERIVED_VALUE_CONTEXT);
710+
711+
expect(result.shouldShowRbrForFeedNameWithDomainID[AMEX_FEED.feedNameWithDomainID]).toBe(true);
712+
expect(result.shouldShowRbrForFeedNameWithDomainID[CHASE_FEED.feedNameWithDomainID]).toBe(false);
713+
});
714+
});
554715
});
555716
});

0 commit comments

Comments
 (0)