diff --git a/src/components/FeedSelector.tsx b/src/components/FeedSelector.tsx
index 3af19065119de..8fee5ed822b49 100644
--- a/src/components/FeedSelector.tsx
+++ b/src/components/FeedSelector.tsx
@@ -49,7 +49,7 @@ function FeedSelector({onFeedSelect, CardFeedIcon, feedName, supportingText, sho
-
+
({
return rightHandSideComponent;
};
+ const shouldShowCheckmark = !canSelectMultiple && !!item.isSelected && !rightHandSideComponent && shouldUseDefaultRightHandSideCheckmark;
+
+ const shouldShowRBRIndicator = (!item.isSelected || !!item.canShowSeveralIndicators) && !!item.brickRoadIndicator && shouldDisplayRBR;
+
+ const shouldShowHiddenCheckmark = shouldShowRBRIndicator && !shouldShowCheckmark;
+
return (
onDismissError(item)}
@@ -136,9 +142,19 @@ function BaseListItem({
>
{typeof children === 'function' ? children(hovered) : children}
- {!canSelectMultiple && !!item.isSelected && !rightHandSideComponent && shouldUseDefaultRightHandSideCheckmark && (
+ {shouldShowRBRIndicator && (
+
+
+
+ )}
+
+ {(shouldShowCheckmark || shouldShowHiddenCheckmark) && (
@@ -149,15 +165,6 @@ function BaseListItem({
)}
- {(!item.isSelected || !!item.canShowSeveralIndicators) && !!item.brickRoadIndicator && shouldDisplayRBR && (
-
-
-
- )}
{rightHandSideComponentRender()}
diff --git a/src/hooks/useCompanyCards.ts b/src/hooks/useCompanyCards.ts
index 89f6542692c46..d09fac5ef5b29 100644
--- a/src/hooks/useCompanyCards.ts
+++ b/src/hooks/useCompanyCards.ts
@@ -13,6 +13,11 @@ import useOnyx from './useOnyx';
type CardFeedType = ValueOf;
+type UseCompanyCardsProps = {
+ policyID: string | undefined;
+ feedName?: CompanyCardFeedWithDomainID;
+};
+
type UsCompanyCardsResult = Partial<{
cardFeedType: CardFeedType;
bankName: CompanyCardFeed;
@@ -31,11 +36,11 @@ type UsCompanyCardsResult = Partial<{
};
};
-function useCompanyCards(policyID?: string): UsCompanyCardsResult {
+function useCompanyCards({policyID, feedName: feedNameProp}: UseCompanyCardsProps): UsCompanyCardsResult {
const [lastSelectedFeed, lastSelectedFeedMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.LAST_SELECTED_FEED}${policyID}`, {canBeMissing: true});
const [allCardFeeds, allCardFeedsMetadata] = useCardFeeds(policyID);
- const feedName = getSelectedFeed(lastSelectedFeed, allCardFeeds);
+ const feedName = feedNameProp ?? getSelectedFeed(lastSelectedFeed, allCardFeeds);
const bankName = feedName ? getCompanyCardFeed(feedName) : undefined;
const [cardsList, cardListMetadata] = useCardsList(feedName);
diff --git a/src/libs/actions/CompanyCards.ts b/src/libs/actions/CompanyCards.ts
index d7b2b49841c87..898230b9ab191 100644
--- a/src/libs/actions/CompanyCards.ts
+++ b/src/libs/actions/CompanyCards.ts
@@ -309,7 +309,13 @@ function deleteWorkspaceCompanyCardFeed(policyID: string, domainOrWorkspaceAccou
API.write(WRITE_COMMANDS.DELETE_COMPANY_CARD_FEED, parameters, {optimisticData, successData, failureData});
}
-function assignWorkspaceCompanyCard(policy: OnyxEntry, domainOrWorkspaceAccountID: number, translate: LocaleContextProps['translate'], data?: Partial) {
+function assignWorkspaceCompanyCard(
+ policy: OnyxEntry,
+ domainOrWorkspaceAccountID: number,
+ translate: LocaleContextProps['translate'],
+ feed: CompanyCardFeedWithDomainID,
+ data?: Partial,
+) {
if (!data || !policy?.id) {
return;
}
@@ -318,6 +324,8 @@ function assignWorkspaceCompanyCard(policy: OnyxEntry, domainOrWorkspace
const optimisticCardAssignedReportAction = ReportUtils.buildOptimisticCardAssignedReportAction(assigneeDetails?.accountID ?? CONST.DEFAULT_NUMBER_ID);
const failedCardAssignment: FailedCompanyCardAssignment = {
+ domainOrWorkspaceAccountID,
+ feed,
cardholder,
cardName,
cardNumber: encryptedCardNumber,
@@ -373,7 +381,7 @@ function assignWorkspaceCompanyCard(policy: OnyxEntry, domainOrWorkspace
},
{
onyxMethod: Onyx.METHOD.MERGE,
- key: `${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}`,
+ key: `${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}_${feed}`,
value: {
[encryptedCardNumber]: failedCardAssignment,
},
@@ -464,8 +472,12 @@ function unassignWorkspaceCompanyCard(domainOrWorkspaceAccountID: number, bankNa
API.write(WRITE_COMMANDS.UNASSIGN_COMPANY_CARD, parameters, onyxData);
}
-function resetFailedWorkspaceCompanyCardAssignment(domainOrWorkspaceAccountID: number, cardNumber: string) {
- Onyx.merge(`${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}`, {
+function resetFailedWorkspaceCompanyCardAssignment(domainOrWorkspaceAccountID: number, feed: CompanyCardFeedWithDomainID | undefined, cardNumber: string) {
+ if (!feed) {
+ return;
+ }
+
+ Onyx.merge(`${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}_${feed}`, {
[cardNumber]: null,
});
}
diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx
index 8939aa5af66cc..87de40a152876 100644
--- a/src/pages/workspace/WorkspaceInitialPage.tsx
+++ b/src/pages/workspace/WorkspaceInitialPage.tsx
@@ -13,7 +13,6 @@ import OfflineWithFeedback from '@components/OfflineWithFeedback';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
import Text from '@components/Text';
-import useCardFeeds from '@hooks/useCardFeeds';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useGetReceiptPartnersIntegrationData from '@hooks/useGetReceiptPartnersIntegrationData';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
@@ -30,7 +29,6 @@ import {confirmReadyToOpenApp} from '@libs/actions/App';
import {isConnectionInProgress} from '@libs/actions/connections';
import {shouldShowQBOReimbursableExportDestinationAccountError} from '@libs/actions/connections/QuickbooksOnline';
import {clearErrors, openPolicyInitialPage, removeWorkspace} from '@libs/actions/Policy/Policy';
-import {checkIfFeedConnectionIsBroken, flatAllCardsList, getCompanyFeeds} from '@libs/CardUtils';
import {convertToDisplayString} from '@libs/CurrencyUtils';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
@@ -58,6 +56,7 @@ import type {PendingAction} from '@src/types/onyx/OnyxCommon';
import type {PolicyFeatureName} from '@src/types/onyx/Policy';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import type IconAsset from '@src/types/utils/IconAsset';
+import useHasWorkspaceCompanyCardErrors from './companyCards/hooks/useHasWorkspaceCompanyCardErrors';
import type {WithPolicyAndFullscreenLoadingProps} from './withPolicyAndFullscreenLoading';
import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading';
@@ -113,17 +112,11 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
] as const);
const policy = policyDraft?.id ? policyDraft : policyProp;
- const workspaceAccountID = policy?.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID;
const hasPolicyCreationError = policy?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && !isEmptyObject(policy.errors);
const isFocused = useIsFocused();
- const [cardFeeds] = useCardFeeds(policy?.id);
- const [allFeedsCards] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}`, {canBeMissing: true});
const [connectionSyncProgress] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CONNECTION_SYNC_PROGRESS}${policy?.id}`, {canBeMissing: true});
const [currentUserLogin] = useOnyx(ONYXKEYS.SESSION, {selector: emailSelector, canBeMissing: false});
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${route.params?.policyID}`, {canBeMissing: true});
- const cardsDomainIDs = Object.values(getCompanyFeeds(cardFeeds))
- .map((data) => data.domainID)
- .filter((domainID): domainID is number => !!domainID);
const {login, accountID} = useCurrentUserPersonalDetails();
const hasSyncError = shouldShowSyncError(policy, isConnectionInProgress(connectionSyncProgress, policy));
const {shouldShowEnterCredentialsError} = useGetReceiptPartnersIntegrationData(policy?.id);
@@ -210,6 +203,8 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
const [highlightedFeature, setHighlightedFeature] = useState(undefined);
+ const hasCompanyCardFeedError = useHasWorkspaceCompanyCardErrors({policyID});
+
const workspaceMenuItems: WorkspaceMenuItem[] = useMemo(() => {
const protectedMenuItems: WorkspaceMenuItem[] = [];
@@ -330,14 +325,12 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
}
if (featureStates?.[CONST.POLICY.MORE_FEATURES.ARE_COMPANY_CARDS_ENABLED]) {
- const hasBrokenFeedConnection = checkIfFeedConnectionIsBroken(flatAllCardsList(allFeedsCards, workspaceAccountID, cardsDomainIDs));
-
protectedMenuItems.push({
translationKey: 'workspace.common.companyCards',
icon: expensifyIcons.CreditCard,
action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS.getRoute(policyID)))),
screenName: SCREENS.WORKSPACE.COMPANY_CARDS,
- brickRoadIndicator: hasBrokenFeedConnection ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
+ brickRoadIndicator: hasCompanyCardFeedError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
highlighted: highlightedFeature === CONST.POLICY.MORE_FEATURES.ARE_COMPANY_CARDS_ENABLED,
});
}
@@ -391,7 +384,23 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
return menuItems;
}, [
- expensifyIcons,
+ expensifyIcons.Document,
+ expensifyIcons.Gear,
+ expensifyIcons.Building,
+ expensifyIcons.Users,
+ expensifyIcons.Sync,
+ expensifyIcons.Receipt,
+ expensifyIcons.Folder,
+ expensifyIcons.Tag,
+ expensifyIcons.Coins,
+ expensifyIcons.Workflows,
+ expensifyIcons.Feed,
+ expensifyIcons.Car,
+ expensifyIcons.LuggageWithLines,
+ expensifyIcons.ExpensifyCard,
+ expensifyIcons.CreditCard,
+ expensifyIcons.CalendarSolid,
+ expensifyIcons.InvoiceGeneric,
singleExecution,
waitForNavigate,
featureStates,
@@ -402,11 +411,9 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, route}: Workspac
policyID,
hasSyncError,
highlightedFeature,
- hasPolicyCategoryError,
shouldShowEnterCredentialsError,
- allFeedsCards,
- workspaceAccountID,
- cardsDomainIDs,
+ hasPolicyCategoryError,
+ hasCompanyCardFeedError,
]);
// We only update feature states if they aren't pending.
diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardFeedSelectorPage.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardFeedSelectorPage.tsx
index abce9b520dd08..242a49502ee59 100644
--- a/src/pages/workspace/companyCards/WorkspaceCompanyCardFeedSelectorPage.tsx
+++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardFeedSelectorPage.tsx
@@ -8,9 +8,9 @@ import ScreenWrapper from '@components/ScreenWrapper';
import SelectionList from '@components/SelectionList';
import RadioListItem from '@components/SelectionList/ListItem/RadioListItem';
import type {ListItem} from '@components/SelectionList/types';
-import useCardFeeds from '@hooks/useCardFeeds';
import type {CombinedCardFeed, CompanyCardFeedWithDomainID} from '@hooks/useCardFeeds';
import {useCompanyCardFeedIcons} from '@hooks/useCompanyCardIcons';
+import useCompanyCards from '@hooks/useCompanyCards';
import useIsBlockedToAddFeed from '@hooks/useIsBlockedToAddFeed';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
@@ -18,16 +18,7 @@ import useOnyx from '@hooks/useOnyx';
import usePolicy from '@hooks/usePolicy';
import useThemeIllustrations from '@hooks/useThemeIllustrations';
import useThemeStyles from '@hooks/useThemeStyles';
-import {
- checkIfFeedConnectionIsBroken,
- filterInactiveCards,
- getCardFeedIcon,
- getCompanyFeeds,
- getCustomOrFormattedFeedName,
- getDomainOrWorkspaceAccountID,
- getPlaidInstitutionIconUrl,
- getSelectedFeed,
-} from '@libs/CardUtils';
+import {getCardFeedIcon, getCustomOrFormattedFeedName, getPlaidInstitutionIconUrl} from '@libs/CardUtils';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import Navigation from '@navigation/Navigation';
@@ -40,6 +31,7 @@ import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {CompanyCardFeed} from '@src/types/onyx';
+import useCompanyCardFeedErrors from './hooks/useCardFeedErrors';
type CardFeedListItem = ListItem & {
/** Combined feed key */
@@ -54,41 +46,36 @@ type WorkspaceCompanyCardFeedSelectorPageProps = PlatformStackScreenProps).map(([key, feedSettings]) => {
- const filteredFeedCards = filterInactiveCards(
- allFeedsCards?.[`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}${getDomainOrWorkspaceAccountID(workspaceAccountID, feedSettings)}_${feedSettings.feed}`],
- );
- const isFeedConnectionBroken = checkIfFeedConnectionIsBroken(filteredFeedCards);
+ const {companyCardFeeds, feedName: selectedFeedName} = useCompanyCards({policyID});
+ const {getCardFeedErrors} = useCompanyCardFeedErrors({policyID, feedName: selectedFeedName});
+
+ const feeds: CardFeedListItem[] = (Object.entries(companyCardFeeds ?? {}) as Array<[CompanyCardFeedWithDomainID, CombinedCardFeed]>).map(([feedName, feedSettings]) => {
const plaidUrl = getPlaidInstitutionIconUrl(feedSettings.feed);
const domain = allDomains?.[`${ONYXKEYS.COLLECTION.DOMAIN}${feedSettings.domainID}`];
const domainName = domain?.email ? Str.extractEmailDomain(domain.email) : undefined;
+ const {shouldShowRBR} = getCardFeedErrors(feedName);
+
return {
- value: key,
+ value: feedName,
feed: feedSettings.feed,
alternateText: domainName ?? policy?.name,
text: getCustomOrFormattedFeedName(feedSettings.feed, feedSettings.customFeedName),
- keyForList: key,
- isSelected: key === selectedFeed,
+ keyForList: feedName,
+ isSelected: feedName === selectedFeedName,
isDisabled: feedSettings.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
pendingAction: feedSettings.pendingAction,
- brickRoadIndicator: isFeedConnectionBroken ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
- canShowSeveralIndicators: isFeedConnectionBroken,
+ brickRoadIndicator: shouldShowRBR ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined,
+ canShowSeveralIndicators: shouldShowRBR,
leftElement: plaidUrl ? (
{
if (!feedName) {
return;
@@ -130,7 +115,7 @@ function WorkspaceCompanyCardsTableHeaderButtons({policyID, feedName, isLoading,
CardFeedIcon={CardFeedIcon}
feedName={formattedFeedName}
supportingText={supportingText}
- shouldShowRBR={checkIfFeedConnectionIsBroken(flatAllCardsList(allFeedsCards, domainOrWorkspaceAccountID), feedName)}
+ shouldShowRBR={hasCompanyCardFeedError}
/>
)}
@@ -161,7 +146,7 @@ function WorkspaceCompanyCardsTableHeaderButtons({policyID, feedName, isLoading,
- {isSelectedFeedConnectionBroken && !!bankName && (
+ {(isFeedConnectionBroken || hasFeedError) && (
onAssignCard(cardName);
diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/index.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/index.tsx
index 9a0dd90785e9d..5b5e2a4a1b238 100644
--- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/index.tsx
+++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/index.tsx
@@ -54,7 +54,7 @@ function WorkspaceCompanyCardsTable({policy, onAssignCard, isAssigningCardDisabl
cardFeedType,
selectedFeed,
onyxMetadata: {cardListMetadata, lastSelectedFeedMetadata, allCardFeedsMetadata},
- } = useCompanyCards(policy?.id);
+ } = useCompanyCards({policyID: policy?.id});
const isDirectCardFeed = cardFeedType === 'directFeed';
const workspaceAccountID = policy?.workspaceAccountID ?? CONST.DEFAULT_NUMBER_ID;
@@ -62,7 +62,7 @@ function WorkspaceCompanyCardsTable({policy, onAssignCard, isAssigningCardDisabl
const [countryByIp] = useOnyx(ONYXKEYS.COUNTRY, {canBeMissing: false});
const [personalDetails, personalDetailsMetadata] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false});
const [customCardNames] = useOnyx(ONYXKEYS.NVP_EXPENSIFY_COMPANY_CARDS_CUSTOM_NAMES, {canBeMissing: true});
- const [failedCompanyCardAssignments] = useOnyx(`${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}`, {canBeMissing: true});
+ const [failedCompanyCardAssignments] = useOnyx(`${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}_${feedName ?? ''}`, {canBeMissing: true});
const hasNoAssignedCard = Object.keys(assignedCards ?? {}).length === 0;
const isInitiallyLoadingFeeds = isLoadingOnyxValue(allCardFeedsMetadata);
@@ -225,6 +225,7 @@ function WorkspaceCompanyCardsTable({policy, onAssignCard, isAssigningCardDisabl
key={`${item.cardName}_${index}`}
item={item}
policyID={policy?.id ?? String(CONST.DEFAULT_NUMBER_ID)}
+ feed={feedName}
domainOrWorkspaceAccountID={domainOrWorkspaceAccountID}
CardFeedIcon={cardFeedIcon}
isPlaidCardFeed={isDirectCardFeed}
diff --git a/src/pages/workspace/companyCards/assignCard/ConfirmationStep.tsx b/src/pages/workspace/companyCards/assignCard/ConfirmationStep.tsx
index 7439dc0282a36..a2f21efb0b4c9 100644
--- a/src/pages/workspace/companyCards/assignCard/ConfirmationStep.tsx
+++ b/src/pages/workspace/companyCards/assignCard/ConfirmationStep.tsx
@@ -93,7 +93,7 @@ function ConfirmationStep({route}: ConfirmationStepProps) {
Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS_BROKEN_CARD_FEED_CONNECTION.getRoute(policyID, feed));
return;
}
- assignWorkspaceCompanyCard(policy, domainOrWorkspaceAccountID, translate, {...cardToAssign, cardholder, bankName});
+ assignWorkspaceCompanyCard(policy, domainOrWorkspaceAccountID, translate, feed, {...cardToAssign, cardholder, bankName});
};
const editStep = (step: string) => {
diff --git a/src/pages/workspace/companyCards/hooks/useCardFeedErrors.ts b/src/pages/workspace/companyCards/hooks/useCardFeedErrors.ts
new file mode 100644
index 0000000000000..24cdcb3175759
--- /dev/null
+++ b/src/pages/workspace/companyCards/hooks/useCardFeedErrors.ts
@@ -0,0 +1,59 @@
+import type {CompanyCardFeedWithDomainID} from '@hooks/useCardFeeds';
+import useCompanyCards from '@hooks/useCompanyCards';
+import useOnyx from '@hooks/useOnyx';
+import useWorkspaceAccountID from '@hooks/useWorkspaceAccountID';
+import {checkIfFeedConnectionIsBroken, flatAllCardsList, getCompanyCardFeed, getDomainOrWorkspaceAccountID} from '@libs/CardUtils';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {isEmptyObject} from '@src/types/utils/EmptyObject';
+
+type UseCompanyCardFeedErrorsProps = {
+ policyID: string | undefined;
+ feedName?: CompanyCardFeedWithDomainID;
+};
+
+type CompanyCardFeedErrors = {
+ shouldShowRBR: boolean;
+ hasFailedCardAssignments: boolean;
+ hasFeedError: boolean;
+ isFeedConnectionBroken: boolean;
+};
+
+type UseCompanyCardFeedErrorsResult = CompanyCardFeedErrors & {
+ getCardFeedErrors: (feedName: CompanyCardFeedWithDomainID) => CompanyCardFeedErrors;
+};
+
+function useCompanyCardFeedErrors({policyID, feedName}: UseCompanyCardFeedErrorsProps): UseCompanyCardFeedErrorsResult {
+ const workspaceAccountID = useWorkspaceAccountID(policyID);
+
+ const {companyCardFeeds} = useCompanyCards({policyID, feedName});
+ const [allFeedsCards] = useOnyx(`${ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST}`, {canBeMissing: false});
+ const [failedCompanyCardAssignmentsPerFeed] = useOnyx(ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS, {canBeMissing: true});
+
+ const getCardFeedErrors = (feedNameFn: CompanyCardFeedWithDomainID | undefined): CompanyCardFeedErrors => {
+ const bankName = getCompanyCardFeed(feedNameFn);
+ const selectedFeed = bankName && companyCardFeeds?.[bankName];
+ const domainOrWorkspaceAccountID = getDomainOrWorkspaceAccountID(workspaceAccountID, selectedFeed);
+
+ const hasFailedCardAssignments = !isEmptyObject(
+ failedCompanyCardAssignmentsPerFeed?.[`${ONYXKEYS.COLLECTION.FAILED_COMPANY_CARDS_ASSIGNMENTS}${domainOrWorkspaceAccountID}_${feedNameFn ?? ''}`],
+ );
+ const hasFeedError = feedNameFn ? !!selectedFeed?.errors : false;
+ const isFeedConnectionBroken = checkIfFeedConnectionIsBroken(flatAllCardsList(allFeedsCards, domainOrWorkspaceAccountID), feedNameFn);
+
+ const shouldShowRBR = hasFailedCardAssignments || hasFeedError || isFeedConnectionBroken;
+
+ return {
+ shouldShowRBR,
+ hasFailedCardAssignments,
+ hasFeedError,
+ isFeedConnectionBroken,
+ };
+ };
+
+ return {
+ ...getCardFeedErrors(feedName),
+ getCardFeedErrors,
+ };
+}
+
+export default useCompanyCardFeedErrors;
diff --git a/src/pages/workspace/companyCards/hooks/useHasWorkspaceCompanyCardErrors.ts b/src/pages/workspace/companyCards/hooks/useHasWorkspaceCompanyCardErrors.ts
new file mode 100644
index 0000000000000..e1f5546ea9ed2
--- /dev/null
+++ b/src/pages/workspace/companyCards/hooks/useHasWorkspaceCompanyCardErrors.ts
@@ -0,0 +1,17 @@
+import type {CompanyCardFeedWithDomainID} from '@hooks/useCardFeeds';
+import useCompanyCards from '@hooks/useCompanyCards';
+import useCompanyCardFeedErrors from './useCardFeedErrors';
+
+type UseHasWorkspaceCompanyCardErrorsProps = {
+ policyID: string | undefined;
+};
+
+function useHasWorkspaceCompanyCardErrors({policyID}: UseHasWorkspaceCompanyCardErrorsProps): boolean {
+ const {companyCardFeeds} = useCompanyCards({policyID});
+ const companyCardFeedNames = Object.keys(companyCardFeeds ?? {}) as CompanyCardFeedWithDomainID[];
+ const {getCardFeedErrors} = useCompanyCardFeedErrors({policyID});
+ const hasCompanyCardFeedError = companyCardFeedNames.some((feed) => getCardFeedErrors(feed).shouldShowRBR);
+ return hasCompanyCardFeedError;
+}
+
+export default useHasWorkspaceCompanyCardErrors;
diff --git a/src/types/onyx/Card.ts b/src/types/onyx/Card.ts
index 73f65a038a030..05e10fe6518f0 100644
--- a/src/types/onyx/Card.ts
+++ b/src/types/onyx/Card.ts
@@ -1,5 +1,6 @@
import type {ValueOf} from 'type-fest';
import type CONST from '@src/CONST';
+import type {CompanyCardFeedWithDomainID} from './CardFeeds';
import type * as OnyxCommon from './OnyxCommon';
import type PersonalDetails from './PersonalDetails';
@@ -293,6 +294,12 @@ type WorkspaceCardsList = CardList & {
* Pending action for a company card assignment
*/
type FailedCompanyCardAssignment = {
+ /** The domain or workspace account ID */
+ domainOrWorkspaceAccountID: number;
+
+ /** The name of the feed */
+ feed: CompanyCardFeedWithDomainID;
+
/** Cardholder personal details */
cardholder?: PersonalDetails;