From 4b570f6092d1183ebb2ace9e979ae0c54e048a16 Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Fri, 19 Dec 2025 20:35:36 -0500 Subject: [PATCH 01/10] fix: invalid loading states --- src/hooks/useCompanyCards.ts | 10 +- ...orkspaceCompanyCardsTableHeaderButtons.tsx | 10 +- .../WorkspaceCompanyCardsTable/index.tsx | 121 +++++++++--------- 3 files changed, 70 insertions(+), 71 deletions(-) diff --git a/src/hooks/useCompanyCards.ts b/src/hooks/useCompanyCards.ts index 55c89cb84ab31..89f6542692c46 100644 --- a/src/hooks/useCompanyCards.ts +++ b/src/hooks/useCompanyCards.ts @@ -1,6 +1,6 @@ -import type {OnyxCollection, ResultMetadata} from 'react-native-onyx'; +import type {OnyxCollection, OnyxEntry, ResultMetadata} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; -import {getCompanyCardFeed, getCompanyFeeds, getPlaidInstitutionId} from '@libs/CardUtils'; +import {getCompanyCardFeed, getCompanyFeeds, getPlaidInstitutionId, getSelectedFeed} from '@libs/CardUtils'; import type CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {CardFeeds, CardList} from '@src/types/onyx'; @@ -27,14 +27,15 @@ type UsCompanyCardsResult = Partial<{ onyxMetadata: { cardListMetadata: ResultMetadata; allCardFeedsMetadata: ResultMetadata>; + lastSelectedFeedMetadata: ResultMetadata>; }; }; function useCompanyCards(policyID?: string): UsCompanyCardsResult { - const [lastSelectedFeed] = useOnyx(`${ONYXKEYS.COLLECTION.LAST_SELECTED_FEED}${policyID}`, {canBeMissing: true}); + const [lastSelectedFeed, lastSelectedFeedMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.LAST_SELECTED_FEED}${policyID}`, {canBeMissing: true}); const [allCardFeeds, allCardFeedsMetadata] = useCardFeeds(policyID); - const feedName = lastSelectedFeed; + const feedName = getSelectedFeed(lastSelectedFeed, allCardFeeds); const bankName = feedName ? getCompanyCardFeed(feedName) : undefined; const [cardsList, cardListMetadata] = useCardsList(feedName); @@ -54,6 +55,7 @@ function useCompanyCards(policyID?: string): UsCompanyCardsResult { const onyxMetadata = { cardListMetadata, allCardFeedsMetadata, + lastSelectedFeedMetadata, }; if (!policyID) { diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableHeaderButtons.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableHeaderButtons.tsx index d8b779b9e7728..b810e8ce7539b 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableHeaderButtons.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableHeaderButtons.tsx @@ -46,7 +46,7 @@ type WorkspaceCompanyCardsTableHeaderButtonsProps = { feedName: CompanyCardFeedWithDomainID | undefined; /** Whether the feed is loading */ - isLoadingFeed?: boolean; + isLoading?: boolean; /** Whether to show the table controls */ showTableControls: boolean; @@ -55,7 +55,7 @@ type WorkspaceCompanyCardsTableHeaderButtonsProps = { CardFeedIcon?: React.ReactNode; }; -function WorkspaceCompanyCardsTableHeaderButtons({policyID, feedName, isLoadingFeed, showTableControls, CardFeedIcon}: WorkspaceCompanyCardsTableHeaderButtonsProps) { +function WorkspaceCompanyCardsTableHeaderButtons({policyID, feedName, isLoading, showTableControls, CardFeedIcon}: WorkspaceCompanyCardsTableHeaderButtonsProps) { const styles = useThemeStyles(); const {shouldUseNarrowLayout, isMediumScreenWidth} = useResponsiveLayout(); @@ -118,7 +118,7 @@ function WorkspaceCompanyCardsTableHeaderButtons({policyID, feedName, isLoadingF !shouldShowNarrowLayout && [styles.flexColumn, styles.pv2, styles.flexRow, styles.alignItemsCenter, styles.justifyContentBetween], ]} > - {isLoadingFeed ? ( + {isLoading ? ( - {!isLoadingFeed && showTableControls && ( + {!isLoading && showTableControls && ( )} - {!isLoadingFeed && ( + {!isLoading && ( <> {showTableControls && } - ); - - const isLoadingFeed = !feedName || policy?.id === undefined; + const showCards = !isInitiallyLoadingFeeds && !isFeedPending && !isNoFeed && !isLoadingFeed; + const showTableControls = !(showCards && !!selectedFeed); - const isDirectCardFeed = cardFeedType === 'directFeed'; - const isLoadingDirectCardFeed = isDirectCardFeed && selectedFeed?.accountList === undefined; - const isLoadingCommercialCardFeed = !isDirectCardFeed && (isLoadingOnyxValue(cardListMetadata) || cardList === undefined); - const isLoadingCards = isLoadingOnyxValue(allCardFeedsMetadata) && (isLoadingDirectCardFeed || isLoadingCommercialCardFeed); - const isLoadingPersonalDetails = isLoadingOnyxValue(personalDetailsMetadata); - const isLoadingCardsTableData = isLoadingFeed || (!isOffline && isLoadingCards) || isLoadingPersonalDetails; + const isGB = countryByIp === CONST.COUNTRY.GB; + const shouldShowGBDisclaimer = isGB && isBetaEnabled(CONST.BETAS.PLAID_COMPANY_CARDS) && (isNoFeed || hasNoAssignedCard); // When we reach the medium screen width or the narrow layout is active, // we want to hide the table header and the middle column of the card rows, so that the content is not overlapping. @@ -120,9 +105,9 @@ function WorkspaceCompanyCardsTable({policy, onAssignCard, isAssigningCardDisabl }, ]; - const showCards = !isFeedPending && !isNoFeed && isFeedAdded; - const data: WorkspaceCompanyCardTableItemData[] = showCards - ? (cardNames?.map((cardName) => { + const cardsData: WorkspaceCompanyCardTableItemData[] = isLoadingCards + ? [] + : (cardNames?.map((cardName) => { const assignedCardPredicate = (card: Card) => (isDirectCardFeed ? card.cardName === cardName : isMaskedCardNumberEqual(card.cardName, cardName)); const assignedCard = Object.values(assignedCards ?? {}).find(assignedCardPredicate); @@ -138,23 +123,7 @@ function WorkspaceCompanyCardsTable({policy, onAssignCard, isAssigningCardDisabl const isAssigned = !!assignedCard; return {cardName, customCardName, isCardDeleted, isAssigned, assignedCard, cardholder, failedCompanyCardAssignment}; - }) ?? []) - : []; - - const renderItem = ({item, index}: ListRenderItemInfo) => ( - - ); + }) ?? []); const keyExtractor = (item: WorkspaceCompanyCardTableItemData, index: number) => `${item.cardName}_${index}`; @@ -240,6 +209,33 @@ function WorkspaceCompanyCardsTable({policy, onAssignCard, isAssigningCardDisabl }, }; + const cardFeedIcon = ( + + ); + + const renderItem = ({item, index}: ListRenderItemInfo) => ( + + ); + const [activeSortingInWideLayout, setActiveSortingInWideLayout] = useState | undefined>(undefined); const isNarrowLayoutRef = useRef(shouldUseNarrowTableLayout); @@ -266,14 +262,10 @@ function WorkspaceCompanyCardsTable({policy, onAssignCard, isAssigningCardDisabl tableRef.current?.updateSorting(activeSortingInWideLayout); }, [activeSortingInWideLayout, shouldUseNarrowTableLayout]); - const showTableControls = !(isFeedPending && !!selectedFeed); - - const ListEmptyComponent = showCards ? : ; - return ( : } > + {(showCards || isLoadingPage) && ( + + + + )} + + {isLoadingPage && } + {isFeedPending && ( @@ -300,15 +306,6 @@ function WorkspaceCompanyCardsTable({policy, onAssignCard, isAssigningCardDisabl {showCards && ( <> - - - {!shouldUseNarrowTableLayout && !isLoadingFeed && } From eb5ae437c1cc8d96ba819c04685bc3821005eb3a Mon Sep 17 00:00:00 2001 From: Christoph Pader Date: Fri, 19 Dec 2025 20:41:14 -0500 Subject: [PATCH 02/10] fix: assignCard button size --- .../WorkspaceCompanyCardsTableItem.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableItem.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableItem.tsx index 8540d310007b5..49e22f0b58eb5 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableItem.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable/WorkspaceCompanyCardsTableItem.tsx @@ -235,7 +235,7 @@ function WorkspaceCompanyCardTableItem({ ) : (