Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e4253f5
fix: Update loading logic for company cards based on feed type
fedirjh Jan 20, 2026
4350f3e
fix: Refactor loading logic for company cards to improve readability
fedirjh Jan 20, 2026
f03a1ce
fix: Enhance loading logic for company cards to improve clarity
fedirjh Jan 20, 2026
3a862a0
Merge remote-tracking branch 'upstream' into fix-company-cards-skeleton
fedirjh Jan 20, 2026
17e4ef4
Merge remote-tracking branch 'upstream' into fix-company-cards-skeleton
fedirjh Jan 20, 2026
268264d
Merge remote-tracking branch 'upstream' into fix-company-cards-skeleton
fedirjh Jan 21, 2026
ed02b47
Merge remote-tracking branch 'upstream' into fix-company-cards-skeleton
fedirjh Jan 27, 2026
f286caa
Merge remote-tracking branch 'upstream' into fix-company-cards-skeleton
fedirjh Jan 27, 2026
9a0fe26
fix: Update loading state logic for company cards table
fedirjh Jan 27, 2026
8baf54e
Merge branch 'main' into fix-company-cards-skeleton
fedirjh Jan 27, 2026
527c5b1
Refactor loading state logic in WorkspaceCompanyCardsTable to simplif…
fedirjh Jan 27, 2026
21f4527
Refactor isLoadingCards condition in WorkspaceCompanyCardsTable for i…
fedirjh Jan 28, 2026
308ee00
Refactor useCompanyCards hook to replace cardNames with cardNamesToEn…
fedirjh Jan 28, 2026
77c25fe
Remove unused import from useCompanyCards hook and clean up commented…
fedirjh Jan 28, 2026
b1b80af
Refactor tests for useCompanyCards to replace cardFeedType checks wit…
fedirjh Jan 28, 2026
a15ce52
Merge remote-tracking branch 'upstream' into fix-company-cards-skeleton
fedirjh Jan 28, 2026
cbd2a24
Enable ESLint naming convention rule for useCompanyCards test file to…
fedirjh Jan 28, 2026
f1ae7ef
Refactor useCompanyCards hook to improve feed loading logic and updat…
fedirjh Jan 28, 2026
b1308f4
Merge branch 'Expensify:main' into fix-company-cards-skeleton
fedirjh Jan 28, 2026
7a19a5d
Merge branch 'Expensify:main' into fix-company-cards-skeleton
fedirjh Jan 28, 2026
b639387
Merge branch 'main' into fix-company-cards-skeleton
fedirjh Jan 29, 2026
a43303c
Refactor cardNamesToEncryptedCardNumber to cardNamesToEncryptedCardNu…
fedirjh Jan 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 12 additions & 18 deletions src/hooks/useCompanyCards.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type {OnyxCollection, OnyxEntry, ResultMetadata} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import {getCompanyCardFeed, getCompanyFeeds, getPlaidInstitutionId, getSelectedFeed} from '@libs/CardUtils';
import {getCompanyCardFeed, getCompanyFeeds, getSelectedFeed} from '@libs/CardUtils';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {CardFeeds, CardList} from '@src/types/onyx';
Expand All @@ -12,21 +11,18 @@ import type {CombinedCardFeed} from './useCardFeeds';
import useCardsList from './useCardsList';
import useOnyx from './useOnyx';

type CardFeedType = ValueOf<typeof CONST.COMPANY_CARDS.FEED_TYPE>;

type UseCompanyCardsProps = {
policyID: string | undefined;
feedName?: CompanyCardFeedWithDomainID;
};

type UseCompanyCardsResult = Partial<{
cardFeedType: CardFeedType;
bankName: CompanyCardFeed;
feedName: CompanyCardFeedWithDomainID;
cardList: AssignableCardsList;
assignedCards: CardList;
cardNamesToEncryptedCardNumberMapping: Record<string, string>;
workspaceCardFeedsStatus: CardFeedsStatusByDomainID;
cardNames: string[];
allCardFeeds: CombinedCardFeeds;
companyCardFeeds: CompanyFeeds;
selectedFeed: CombinedCardFeed;
Expand Down Expand Up @@ -58,17 +54,16 @@ function useCompanyCards({policyID, feedName: feedNameProp}: UseCompanyCardsProp

const companyCardFeeds = getCompanyFeeds(allCardFeeds);
const selectedFeed = feedName && companyCardFeeds[feedName];
const isPlaidCardFeed = !!getPlaidInstitutionId(feedName);

// Direct feeds include Plaid feeds and OAuth feeds (like oauth.chase.com) that have accountList
const isDirectFeed = isPlaidCardFeed || !!selectedFeed?.accountList;
let cardFeedType: CardFeedType = 'customFeed';
if (isDirectFeed) {
cardFeedType = 'directFeed';
}

const {cardList, ...assignedCards} = cardsList ?? {};
const cardNames = cardFeedType === 'directFeed' ? (selectedFeed?.accountList ?? []) : Object.keys(cardList ?? {});
const cardNamesToEncryptedCardNumberMapping: Record<string, string> = {};

for (const cardName of selectedFeed?.accountList ?? []) {
cardNamesToEncryptedCardNumberMapping[cardName] = cardName;
}
for (const [cardName, encryptedCardNumber] of Object.entries(cardList ?? {})) {
cardNamesToEncryptedCardNumberMapping[cardName] = encryptedCardNumber;
}

const onyxMetadata = {
cardListMetadata,
Expand All @@ -79,7 +74,7 @@ function useCompanyCards({policyID, feedName: feedNameProp}: UseCompanyCardsProp
const isInitiallyLoadingFeeds = isLoadingOnyxValue(allCardFeedsMetadata);
const isNoFeed = !selectedFeed && !isInitiallyLoadingFeeds;
const isFeedPending = !!selectedFeed?.pending;
const isFeedAdded = !isLoadingOnyxValue(allCardFeedsMetadata) && !isFeedPending && !isNoFeed;
const isFeedAdded = !isInitiallyLoadingFeeds && !isFeedPending && !isNoFeed;

if (!policyID) {
return {onyxMetadata, isInitiallyLoadingFeeds, isNoFeed, isFeedPending, isFeedAdded};
Expand All @@ -91,11 +86,10 @@ function useCompanyCards({policyID, feedName: feedNameProp}: UseCompanyCardsProp
companyCardFeeds,
cardList,
assignedCards,
cardNamesToEncryptedCardNumberMapping,
workspaceCardFeedsStatus,
cardNames,
selectedFeed,
bankName,
cardFeedType,
onyxMetadata,
isInitiallyLoadingFeeds,
isNoFeed,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import useOnyx from '@hooks/useOnyx';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useThemeStyles from '@hooks/useThemeStyles';
import {resetFailedWorkspaceCompanyCardAssignment, resetFailedWorkspaceCompanyCardUnassignment} from '@libs/actions/CompanyCards';
import {getDefaultCardName} from '@libs/CardUtils';
import {getDefaultCardName, getPlaidInstitutionId} from '@libs/CardUtils';
import tokenizedSearch from '@libs/tokenizedSearch';
import WorkspaceCompanyCardPageEmptyState from '@pages/workspace/companyCards/WorkspaceCompanyCardPageEmptyState';
import WorkspaceCompanyCardsFeedAddedEmptyPage from '@pages/workspace/companyCards/WorkspaceCompanyCardsFeedAddedEmptyPage';
Expand Down Expand Up @@ -77,18 +77,15 @@ function WorkspaceCompanyCardsTable({
const {
feedName,
bankName,
cardList,
assignedCards,
cardNamesToEncryptedCardNumberMapping,
workspaceCardFeedsStatus,
cardNames,
cardFeedType,
selectedFeed,
isInitiallyLoadingFeeds,
isNoFeed,
isFeedPending,
onyxMetadata: {cardListMetadata, lastSelectedFeedMetadata},
} = companyCards;
const isDirectCardFeed = cardFeedType === 'directFeed';

const [countryByIp] = useOnyx(ONYXKEYS.COUNTRY, {canBeMissing: false});
const [personalDetails, personalDetailsMetadata] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: false});
Expand Down Expand Up @@ -117,7 +114,7 @@ function WorkspaceCompanyCardsTable({
}

const isLoadingFeed = (!feedName && isInitiallyLoadingFeeds) || !isPolicyLoaded || isLoadingOnyxValue(lastSelectedFeedMetadata) || !!selectedFeedStatus?.isLoading;
const isLoadingCards = cardFeedType === 'directFeed' ? selectedFeed?.accountList === undefined : isLoadingOnyxValue(cardListMetadata) || cardList === undefined;
const isLoadingCards = Object.keys(cardNamesToEncryptedCardNumberMapping ?? {}).length === 0 ? isLoadingOnyxValue(cardListMetadata) : false;
const isLoadingPage = !isOffline && (isLoadingFeed || isLoadingOnyxValue(personalDetailsMetadata) || areWorkspaceCardFeedsLoading);
const isLoading = isLoadingPage || isLoadingFeed;

Expand Down Expand Up @@ -154,9 +151,7 @@ function WorkspaceCompanyCardsTable({

const cardsData: WorkspaceCompanyCardTableItemData[] = isLoadingCards
? []
: (cardNames?.map((cardName) => {
// For direct feeds cardID equals cardName, for commercial feeds it's looked up from cardList
const encryptedCardNumber = isDirectCardFeed ? cardName : (cardList?.[cardName] ?? '');
: (Object.entries(cardNamesToEncryptedCardNumberMapping ?? {}).map(([cardName, encryptedCardNumber]) => {
const failedCompanyCardAssignment = failedCompanyCardAssignments?.[encryptedCardNumber];

if (failedCompanyCardAssignment) {
Expand Down Expand Up @@ -290,7 +285,7 @@ function WorkspaceCompanyCardsTable({
item={item}
policyID={policyID ?? String(CONST.DEFAULT_NUMBER_ID)}
CardFeedIcon={cardFeedIcon}
isPlaidCardFeed={isDirectCardFeed}
isPlaidCardFeed={!!getPlaidInstitutionId(feedName)}
onAssignCard={onAssignCard}
isAssigningCardDisabled={isAssigningCardDisabled}
shouldUseNarrowTableLayout={shouldUseNarrowTableLayout}
Expand Down
Loading
Loading