diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 30f46d4cc9b8..905e0a4d9ba3 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -23,7 +23,7 @@ import type AssertTypesNotEqual from './types/utils/AssertTypesNotEqual'; type WorkspaceCompanyCardsAssignCardParams = { policyID: string; feed: string; - cardID?: string; + cardID: string; }; // This is a file containing constants for all the routes we want to be able to go to @@ -2192,10 +2192,7 @@ const ROUTES = { getRoute: (params: WorkspaceCompanyCardsAssignCardParams, backTo?: string) => // eslint-disable-next-line no-restricted-syntax -- Legacy route generation - getUrlWithBackToParam( - `workspaces/${params.policyID}/company-cards/${encodeURIComponent(params.feed)}/assign-card${params.cardID ? `/${encodeURIComponent(params.cardID)}` : ''}`, - backTo, - ), + getUrlWithBackToParam(`workspaces/${params.policyID}/company-cards/${encodeURIComponent(params.feed)}/assign-card/${params.cardID}`, backTo), }, WORKSPACE_COMPANY_CARD_DETAILS: { route: 'workspaces/:policyID/company-cards/:bank/:cardID', diff --git a/src/hooks/useAssignCard.ts b/src/hooks/useAssignCard.ts index cd70b6231b41..13e7fc28bf47 100644 --- a/src/hooks/useAssignCard.ts +++ b/src/hooks/useAssignCard.ts @@ -74,7 +74,7 @@ function useAssignCard({selectedFeed, policyID, setShouldShowOfflineModal}: UseA const isAssigningCardDisabled = !currentFeedData || !!currentFeedData?.pending || isSelectedFeedConnectionBroken || !isAllowedToIssueCompanyCard; - const assignCard = (cardID?: string) => { + const assignCard = (cardID: string) => { if (isAssigningCardDisabled) { return; } diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index eae5a1afb3fb..2684f5d399b3 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -196,8 +196,10 @@ function formatCardExpiration(expirationDateString: string) { * @returns collection of assigned cards grouped by domain */ function getDomainCards(cardList: OnyxEntry): Record { + const assignedCards = getAssignedCardFromCardList(cardList ?? {}); + // Check for domainName to filter out personal credit cards. - const activeCards = Object.values(cardList ?? {}).filter((card) => !!card?.domainName && CONST.EXPENSIFY_CARD.ACTIVE_STATES.some((element) => element === card.state)); + const activeCards = Object.values(assignedCards).filter((card) => !!card?.domainName && CONST.EXPENSIFY_CARD.ACTIVE_STATES.some((element) => element === card.state)); return groupBy(activeCards, (card) => card.domainName); } @@ -663,8 +665,21 @@ function getAllCardsForWorkspace( return cards; } -function isSmartLimitEnabled(cards: CardList) { - return Object.values(cards).some((card) => card.nameValuePairs?.limitType === CONST.EXPENSIFY_CARD.LIMIT_TYPES.SMART); +/** + * Get assigned cards from card list by extracting the list of assignable cards from the card list + * + * @param cardList the card list + * @returns the assigned cards + */ +function getAssignedCardFromCardList(cardList: CardList) { + const {cardList: assignableCards, ...assignedCards} = cardList; + return assignedCards; +} + +function isSmartLimitEnabled(cardList: CardList) { + const assignedCards = getAssignedCardFromCardList(cardList); + + return Object.values(assignedCards).some((card) => card.nameValuePairs?.limitType === CONST.EXPENSIFY_CARD.LIMIT_TYPES.SMART); } const CUSTOM_FEEDS = [CONST.COMPANY_CARD.FEED_BANK_NAME.MASTER_CARD, CONST.COMPANY_CARD.FEED_BANK_NAME.VISA, CONST.COMPANY_CARD.FEED_BANK_NAME.AMEX]; @@ -773,7 +788,8 @@ function isExpensifyCardPendingAction(card?: Card, privatePersonalDetails?: Priv } function hasPendingExpensifyCardAction(cards: CardList | undefined, privatePersonalDetails?: PrivatePersonalDetails) { - return Object.values(cards ?? {}).some((card) => isExpensifyCardPendingAction(card, privatePersonalDetails)); + const assignedCards = getAssignedCardFromCardList(cards ?? {}); + return Object.values(assignedCards).some((card) => isExpensifyCardPendingAction(card, privatePersonalDetails)); } const isCurrencySupportedForECards = (currency?: string) => { if (!currency) { @@ -941,6 +957,7 @@ export { COMPANY_CARD_BANK_ICON_NAMES, isMaskedCardNumberEqual, splitMaskedCardNumber, + getAssignedCardFromCardList, }; export type {CompanyCardFeedIcons, CompanyCardBankIcons}; diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx index 2de8af437685..8705c25820d3 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx @@ -52,7 +52,7 @@ function WorkspaceCompanyCardsPage({route}: WorkspaceCompanyCardsPageProps) { const isFeedPending = !!selectedFeedData?.pending; const isFeedAdded = !isFeedPending && !isNoFeed; const [shouldShowOfflineModal, setShouldShowOfflineModal] = useState(false); - const domainOrWorkspaceAccountID = getDomainOrWorkspaceAccountID(workspaceAccountID, selectedFeedData) + const domainOrWorkspaceAccountID = getDomainOrWorkspaceAccountID(workspaceAccountID, selectedFeedData); const {isOffline} = useNetwork({ onReconnect: () => openPolicyCompanyCardsPage(policyID, domainOrWorkspaceAccountID), diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable.tsx index d53c2d5eb323..5523275d62ae 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTable.tsx @@ -11,7 +11,7 @@ import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; -import {getCompanyFeeds, getPlaidInstitutionIconUrl, getPlaidInstitutionId, isCustomFeed, isMaskedCardNumberEqual} from '@libs/CardUtils'; +import {getCompanyFeeds, getPlaidInstitutionIconUrl, getPlaidInstitutionId, isMaskedCardNumberEqual} from '@libs/CardUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Card, CompanyCardFeedWithDomainID} from '@src/types/onyx'; @@ -58,7 +58,7 @@ function WorkspaceCompanyCardsTable({selectedFeed, policyID, onAssignCard, isAss const [cardFeeds] = useCardFeeds(policyID); const companyFeeds = getCompanyFeeds(cardFeeds); - const isPlaidCardFeed = !!companyFeeds?.[selectedFeed]?.accountList; + const isPlaidCardFeed = !!getPlaidInstitutionId(selectedFeed); const cards = isPlaidCardFeed ? (companyFeeds?.[selectedFeed]?.accountList ?? []) : Object.keys(cardList ?? {}); // When we reach the medium screen width or the narrow layout is active, @@ -81,30 +81,7 @@ function WorkspaceCompanyCardsTable({selectedFeed, policyID, onAssignCard, isAss const isAssigned = !!assignedCard; - // Calculate cardIdentifier for unassigned cards - let cardIdentifier: string | undefined; - if (!assignedCard) { - const isPlaid = !!getPlaidInstitutionId(selectedFeed); - const isCommercial = isCustomFeed(selectedFeed); - - if (isPlaid) { - cardIdentifier = cardName; - } else if (isCommercial) { - const cardValue = cardList?.[cardName] ?? cardName; - const digitsOnly = cardValue.replaceAll(/\D/g, ''); - if (digitsOnly.length >= 10) { - const first6 = digitsOnly.substring(0, 6); - const last4 = digitsOnly.substring(digitsOnly.length - 4); - cardIdentifier = `${first6}${last4}`; - } else { - cardIdentifier = cardValue; - } - } else { - cardIdentifier = cardList?.[cardName] ?? cardName; - } - } - - return {cardName, customCardName, isCardDeleted, isAssigned, assignedCard, cardholder, cardIdentifier}; + return {cardName, customCardName, isCardDeleted, isAssigned, assignedCard, cardholder}; }) ?? []; const renderItem = ({item, index}: ListRenderItemInfo) => ( @@ -115,7 +92,7 @@ function WorkspaceCompanyCardsTable({selectedFeed, policyID, onAssignCard, isAss selectedFeed={selectedFeed} plaidIconUrl={getPlaidInstitutionIconUrl(selectedFeed)} isPlaidCardFeed={isPlaidCardFeed} - onAssignCard={() => onAssignCard(item.cardIdentifier)} + onAssignCard={onAssignCard} isAssigningCardDisabled={isAssigningCardDisabled} shouldUseNarrowTableRowLayout={shouldShowNarrowLayout} /> diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTableItem.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTableItem.tsx index 384182b87d1f..c1c657a8516a 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsTableItem.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsTableItem.tsx @@ -40,9 +40,6 @@ type WorkspaceCompanyCardTableItemData = { /** Whether the card is assigned */ isAssigned: boolean; - - /** Card identifier for unassigned cards */ - cardIdentifier?: string; }; type WorkspaceCompanyCardTableItemProps = { @@ -68,7 +65,7 @@ type WorkspaceCompanyCardTableItemProps = { shouldUseNarrowTableRowLayout?: boolean; /** On assign card callback */ - onAssignCard: () => void; + onAssignCard: (cardID?: string) => void; }; function WorkspaceCompanyCardTableItem({ @@ -97,6 +94,8 @@ function WorkspaceCompanyCardTableItem({ const alternateLoginText = shouldUseNarrowTableRowLayout ? `${customCardName}${lastCardNumbers ? ` - ${lastCardNumbers}` : ''}` : (cardholder?.login ?? ''); + const assignCard = () => onAssignCard(cardName); + return ( { if (!assignedCard) { - onAssignCard(); + assignCard(); return; } @@ -213,7 +212,7 @@ function WorkspaceCompanyCardTableItem({ {!isAssigned && (