diff --git a/src/libs/API/parameters/OpenPolicyCompanyCardsFeedParams.ts b/src/libs/API/parameters/OpenPolicyCompanyCardsFeedParams.ts index e3a8653886b9..85c881baf55b 100644 --- a/src/libs/API/parameters/OpenPolicyCompanyCardsFeedParams.ts +++ b/src/libs/API/parameters/OpenPolicyCompanyCardsFeedParams.ts @@ -1,4 +1,5 @@ type OpenPolicyCompanyCardsFeedParams = { + domainAccountID?: number; policyID: string; feed: string; }; diff --git a/src/libs/actions/CompanyCards.ts b/src/libs/actions/CompanyCards.ts index 12c34592d191..44b33c29600c 100644 --- a/src/libs/actions/CompanyCards.ts +++ b/src/libs/actions/CompanyCards.ts @@ -744,8 +744,9 @@ function openPolicyCompanyCardsPage(policyID: string, workspaceAccountID: number API.read(READ_COMMANDS.OPEN_POLICY_COMPANY_CARDS_PAGE, params, {optimisticData, successData, failureData}); } -function openPolicyCompanyCardsFeed(policyID: string, feed: CompanyCardFeed) { +function openPolicyCompanyCardsFeed(domainAccountID: number, policyID: string, feed: CompanyCardFeed) { const parameters: OpenPolicyCompanyCardsFeedParams = { + domainAccountID, policyID, feed, }; diff --git a/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx b/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx index 49b74323a970..67addcf7b6d8 100644 --- a/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx +++ b/src/pages/workspace/companyCards/WorkspaceCompanyCardsPage.tsx @@ -5,6 +5,7 @@ import DecisionModal from '@components/DecisionModal'; import DelegateNoAccessModal from '@components/DelegateNoAccessModal'; import * as Illustrations from '@components/Icon/Illustrations'; import useCardFeeds from '@hooks/useCardFeeds'; +import useDefaultFundID from '@hooks/useDefaultFundID'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -75,6 +76,8 @@ function WorkspaceCompanyCardsPage({route}: WorkspaceCompanyCardsPageProps) { const {isOffline} = useNetwork({onReconnect: fetchCompanyCards}); const isLoading = !isOffline && (!cardFeeds || (!!cardFeeds.isLoading && isEmptyObject(cardsList))); + const defaultFundID = useDefaultFundID(policyID); + useEffect(() => { fetchCompanyCards(); }, [fetchCompanyCards]); @@ -84,8 +87,8 @@ function WorkspaceCompanyCardsPage({route}: WorkspaceCompanyCardsPageProps) { return; } - openPolicyCompanyCardsFeed(policyID, selectedFeed); - }, [selectedFeed, isLoading, policyID, isPending]); + openPolicyCompanyCardsFeed(defaultFundID, policyID, selectedFeed); + }, [selectedFeed, isLoading, policyID, isPending, defaultFundID]); const handleAssignCard = () => { if (isActingAsDelegate) { diff --git a/tests/unit/CardUtilsTest.ts b/tests/unit/CardUtilsTest.ts index a9581ec5bc2d..0bffc32ab0f9 100644 --- a/tests/unit/CardUtilsTest.ts +++ b/tests/unit/CardUtilsTest.ts @@ -22,8 +22,9 @@ import { isExpensifyCardFullySetUp, lastFourNumbersFromCardName, maskCardNumber, + sortCardsByCardholderName, } from '@src/libs/CardUtils'; -import type {CardFeeds, CardList, CompanyCardFeed, ExpensifyCardSettings, Policy, WorkspaceCardsList} from '@src/types/onyx'; +import type {CardFeeds, CardList, CompanyCardFeed, ExpensifyCardSettings, PersonalDetailsList, Policy, WorkspaceCardsList} from '@src/types/onyx'; import type {CompanyCardFeedWithNumber} from '@src/types/onyx/CardFeeds'; const shortDate = '0924'; @@ -857,4 +858,138 @@ describe('CardUtils', () => { expect(cards).toEqual({}); }); }); + + describe('sortCardsByCardholderName', () => { + const mockPersonalDetails: PersonalDetailsList = { + 1: { + accountID: 1, + login: 'john@example.com', + displayName: 'John Doe', + firstName: 'John', + lastName: 'Doe', + }, + 2: { + accountID: 2, + login: 'jane@example.com', + displayName: 'Jane Smith', + firstName: 'Jane', + lastName: 'Smith', + }, + 3: { + accountID: 3, + login: 'unknown@example.com', + // No displayName or firstName/lastName + }, + }; + + const mockCards: WorkspaceCardsList = { + '1': { + cardID: 1, + accountID: 1, + cardName: 'Card 1', + bank: 'expensify', + domainName: 'expensify-policya7f617b9fe23d2f1.exfy', + fraud: 'none', + lastFourPAN: '', + lastScrape: '', + lastUpdated: '', + state: 2, + }, + '2': { + cardID: 2, + accountID: 2, + bank: 'expensify', + cardName: 'Card 2', + domainName: 'expensify-policya7f617b9fe23d2f1.exfy', + fraud: 'none', + lastFourPAN: '', + lastScrape: '', + lastUpdated: '', + state: 2, + }, + '3': { + cardID: 3, + accountID: 3, + bank: 'expensify', + cardName: 'Card 3', + domainName: 'expensify-policya7f617b9fe23d2f1.exfy', + fraud: 'none', + lastFourPAN: '', + lastScrape: '', + lastUpdated: '', + state: 2, + }, + }; + + it('should sort cards by cardholder name in ascending order', () => { + const policyMembersAccountIDs = [1, 2, 3]; + const sortedCards = sortCardsByCardholderName(mockCards, mockPersonalDetails, policyMembersAccountIDs); + + expect(sortedCards).toHaveLength(3); + expect(sortedCards.at(0)?.cardID).toBe(2); + expect(sortedCards.at(1)?.cardID).toBe(1); + expect(sortedCards.at(2)?.cardID).toBe(3); + }); + + it('should filter out cards that are not associated with policy members', () => { + const policyMembersAccountIDs = [1, 2]; // Exclude accountID 3 + const sortedCards = sortCardsByCardholderName(mockCards, mockPersonalDetails, policyMembersAccountIDs); + + expect(sortedCards).toHaveLength(2); + expect(sortedCards.at(0)?.cardID).toBe(2); + expect(sortedCards.at(1)?.cardID).toBe(1); + }); + + it('should handle undefined cardsList', () => { + const policyMembersAccountIDs = [1, 2, 3]; + const sortedCards = sortCardsByCardholderName(undefined, mockPersonalDetails, policyMembersAccountIDs); + + expect(sortedCards).toHaveLength(0); + }); + + it('should handle undefined personalDetails', () => { + const policyMembersAccountIDs = [1, 2, 3]; + const sortedCards = sortCardsByCardholderName(mockCards, undefined, policyMembersAccountIDs); + + expect(sortedCards).toHaveLength(3); + // All cards should be sorted with default names + expect(sortedCards.at(0)?.cardID).toBe(1); + expect(sortedCards.at(1)?.cardID).toBe(2); + expect(sortedCards.at(2)?.cardID).toBe(3); + }); + + it('should handle cards with missing accountID', () => { + const cardsWithMissingAccountID: WorkspaceCardsList = { + '1': { + cardID: 1, + accountID: 1, + cardName: 'Card 1', + bank: 'expensify', + domainName: 'expensify-policya7f617b9fe23d2f1.exfy', + fraud: 'none', + lastFourPAN: '', + lastScrape: '', + lastUpdated: '', + state: 2, + }, + '2': { + cardID: 2, + cardName: 'Card 2', + bank: 'expensify', + domainName: 'expensify-policya7f617b9fe23d2f1.exfy', + fraud: 'none', + lastFourPAN: '', + lastScrape: '', + lastUpdated: '', + state: 2, + }, + }; + + const policyMembersAccountIDs = [1, 2]; + const sortedCards = sortCardsByCardholderName(cardsWithMissingAccountID, mockPersonalDetails, policyMembersAccountIDs); + + expect(sortedCards).toHaveLength(1); + expect(sortedCards.at(0)?.cardID).toBe(1); + }); + }); });