Skip to content

Commit 56ff757

Browse files
authored
Merge pull request Expensify#85419 from Expensify/rodrigo-fix-whichcard
2 parents deb3519 + 98af278 commit 56ff757

6 files changed

Lines changed: 68 additions & 88 deletions

File tree

src/libs/TravelInvoicingUtils.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type {OnyxEntry} from 'react-native-onyx';
22
import type {LocalizedTranslate} from '@components/LocaleContextProvider';
33
import CONST from '@src/CONST';
44
import ONYXKEYS from '@src/ONYXKEYS';
5-
import type {BankAccountList, Card, WorkspaceCardsList} from '@src/types/onyx';
5+
import type {BankAccountList, Card, CardList} from '@src/types/onyx';
66
import type {ExpensifyCardSettingsBase} from '@src/types/onyx/ExpensifyCardSettings';
77
import addEncryptedAuthTokenToURL from './addEncryptedAuthTokenToURL';
88
import {getLastFourDigits} from './BankAccountUtils';
@@ -165,17 +165,12 @@ function downloadTravelInvoiceStatementPDF(
165165
* Gets the user's Travel Invoicing card from the card list.
166166
* Returns the first card with feedCountry set to PROGRAM_TRAVEL_US.
167167
*/
168-
function getTravelInvoicingCard(cardList: Record<string, WorkspaceCardsList | undefined> | undefined) {
168+
function getTravelInvoicingCard(cardList: OnyxEntry<CardList>) {
169169
if (!cardList) {
170170
return undefined;
171171
}
172172

173-
// Flatten all WorkspaceCardsList into a single array of Cards
174-
// Filter out cardList entries (which are string values) to only get actual Card objects
175-
const allCards = Object.values(cardList)
176-
.filter((workspaceCards): workspaceCards is WorkspaceCardsList => !!workspaceCards)
177-
.flatMap((workspaceCards) => Object.values(workspaceCards))
178-
.filter((card): card is Card => typeof card !== 'string' && typeof card?.cardID === 'number');
173+
const allCards = Object.values(cardList).filter((card): card is Card => !!card && typeof card?.cardID === 'number');
179174
const travelCard = allCards.find((card) => card.nameValuePairs?.feedCountry === CONST.TRAVEL.PROGRAM_TRAVEL_US);
180175
// If no travel card is found and testing is enabled, return the first available card
181176
if (!travelCard && isTravelCVVTestingEnabled()) {
@@ -189,7 +184,7 @@ function getTravelInvoicingCard(cardList: Record<string, WorkspaceCardsList | un
189184
* Checks if user is eligible to see Travel CVV in Wallet.
190185
* Requires: TRAVEL_INVOICING beta AND having a travel card.
191186
*/
192-
function isTravelCVVEligible(isTravelInvoicingBetaEnabled: boolean, cardList: Record<string, WorkspaceCardsList | undefined> | undefined): boolean {
187+
function isTravelCVVEligible(isTravelInvoicingBetaEnabled: boolean, cardList: OnyxEntry<CardList>): boolean {
193188
const hasTravelCard = !!getTravelInvoicingCard(cardList);
194189
return isTravelInvoicingBetaEnabled && hasTravelCard;
195190
}

src/pages/settings/Wallet/PaymentMethodList.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,6 @@ function PaymentMethodList({
175175
const expensifyIcons = useMemoizedLazyExpensifyIcons(['Plus', 'ThreeDots', 'LuggageWithLines'] as const);
176176
const illustrations = useThemeIllustrations();
177177
const companyCardFeedIcons = useCompanyCardFeedIcons();
178-
const [workspaceCardList] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST);
179-
180178
const [isUserValidated] = useOnyx(ONYXKEYS.ACCOUNT, {
181179
selector: isUserValidatedSelector,
182180
});
@@ -382,8 +380,8 @@ function PaymentMethodList({
382380
}
383381

384382
const travelCardGrouped: PaymentMethodItem[] = [];
385-
const travelCard = getTravelInvoicingCard(workspaceCardList);
386-
if (isTravelCVVEligible(isBetaEnabled(CONST.BETAS.TRAVEL_INVOICING), workspaceCardList) && travelCard) {
383+
const travelCard = getTravelInvoicingCard(cardList);
384+
if (isTravelCVVEligible(isBetaEnabled(CONST.BETAS.TRAVEL_INVOICING), cardList) && travelCard) {
387385
travelCardGrouped.push({
388386
title: translate('walletPage.travelCVV.title'),
389387
description: translate('walletPage.travelCVV.subtitle'),
@@ -478,7 +476,6 @@ function PaymentMethodList({
478476
filterCurrency,
479477
isLoadingCardList,
480478
cardList,
481-
workspaceCardList,
482479
isBetaEnabled,
483480
onPress,
484481
policiesForAssignedCards,

src/pages/settings/Wallet/TravelCVVPage/TravelCVVPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ function TravelCVVPage() {
3636

3737
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
3838
const [privatePersonalDetails] = useOnyx(ONYXKEYS.PRIVATE_PERSONAL_DETAILS);
39-
const [cardList] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST);
39+
const [cardList] = useOnyx(ONYXKEYS.CARD_LIST);
4040
const {isAccountLocked} = useLockedAccountState();
4141
const {showLockedAccountModal} = useLockedAccountActions();
4242

src/pages/settings/Wallet/TravelCVVPage/TravelCVVVerifyAccountPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import {useTravelCVVActions, useTravelCVVState} from './TravelCVVContextProvider
1919
function TravelCVVVerifyAccountPage() {
2020
const {translate} = useLocalize();
2121
const [account] = useOnyx(ONYXKEYS.ACCOUNT);
22-
const [cardList] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST);
22+
const [cardList] = useOnyx(ONYXKEYS.CARD_LIST);
2323

2424
const {isLoading, validateError} = useTravelCVVState();
2525
const {setCvv, setIsLoading, setValidateError} = useTravelCVVActions();

src/pages/settings/Wallet/TravelCVVPage/WalletTravelCVVSection.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function WalletTravelCVVSection() {
2323
const icons = useMemoizedLazyExpensifyIcons(['LuggageWithLines']);
2424
const {isBetaEnabled} = usePermissions();
2525

26-
const [cardList] = useOnyx(ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST);
26+
const [cardList] = useOnyx(ONYXKEYS.CARD_LIST);
2727

2828
const travelCard = getTravelInvoicingCard(cardList);
2929

tests/unit/TravelInvoicingUtilsTest.ts

Lines changed: 59 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
hasTravelInvoicingSettlementAccount,
1313
isTravelCVVEligible,
1414
} from '@src/libs/TravelInvoicingUtils';
15-
import type {BankAccountList, WorkspaceCardsList} from '@src/types/onyx';
15+
import type {BankAccountList, CardList} from '@src/types/onyx';
1616
import type {ExpensifyCardSettingsBase} from '@src/types/onyx/ExpensifyCardSettings';
1717

1818
jest.mock('@src/libs/Environment/Environment', () => ({
@@ -242,64 +242,58 @@ describe('TravelInvoicingUtils', () => {
242242

243243
it('Should return undefined when no travel card exists', () => {
244244
const cardList = {
245-
workspaceCards: {
246-
// eslint-disable-next-line @typescript-eslint/naming-convention
247-
'1234': {
248-
cardID: 1234,
249-
state: 3,
250-
nameValuePairs: {
251-
isVirtual: true,
252-
feedCountry: 'OTHER_COUNTRY',
253-
},
245+
// eslint-disable-next-line @typescript-eslint/naming-convention
246+
'1234': {
247+
cardID: 1234,
248+
state: 3,
249+
nameValuePairs: {
250+
isVirtual: true,
251+
feedCountry: 'OTHER_COUNTRY',
254252
},
255253
},
256-
} as unknown as Record<string, WorkspaceCardsList>;
254+
} as unknown as CardList;
257255
const result = getTravelInvoicingCard(cardList);
258256
expect(result).toBeUndefined();
259257
});
260258

261259
it('Should return the travel card when feedCountry is PROGRAM_TRAVEL_US', () => {
262260
const cardList = {
263-
workspaceCards: {
264-
// eslint-disable-next-line @typescript-eslint/naming-convention
265-
'1234': {
266-
cardID: 1234,
267-
state: 3,
268-
nameValuePairs: {
269-
isVirtual: true,
270-
feedCountry: CONST.TRAVEL.PROGRAM_TRAVEL_US,
271-
},
261+
// eslint-disable-next-line @typescript-eslint/naming-convention
262+
'1234': {
263+
cardID: 1234,
264+
state: 3,
265+
nameValuePairs: {
266+
isVirtual: true,
267+
feedCountry: CONST.TRAVEL.PROGRAM_TRAVEL_US,
272268
},
273269
},
274-
} as unknown as Record<string, WorkspaceCardsList>;
270+
} as unknown as CardList;
275271
const result = getTravelInvoicingCard(cardList);
276272
expect(result).toBeDefined();
277273
expect(result?.cardID).toBe(1234);
278274
});
279275

280276
it('Should return first travel card when multiple cards exist', () => {
281277
const cardList = {
282-
workspaceCards: {
283-
// eslint-disable-next-line @typescript-eslint/naming-convention
284-
'1111': {
285-
cardID: 1111,
286-
state: 3,
287-
nameValuePairs: {
288-
isVirtual: true,
289-
feedCountry: 'OTHER_COUNTRY',
290-
},
278+
// eslint-disable-next-line @typescript-eslint/naming-convention
279+
'1111': {
280+
cardID: 1111,
281+
state: 3,
282+
nameValuePairs: {
283+
isVirtual: true,
284+
feedCountry: 'OTHER_COUNTRY',
291285
},
292-
// eslint-disable-next-line @typescript-eslint/naming-convention
293-
'2222': {
294-
cardID: 2222,
295-
state: 3,
296-
nameValuePairs: {
297-
isVirtual: true,
298-
feedCountry: CONST.TRAVEL.PROGRAM_TRAVEL_US,
299-
},
286+
},
287+
// eslint-disable-next-line @typescript-eslint/naming-convention
288+
'2222': {
289+
cardID: 2222,
290+
state: 3,
291+
nameValuePairs: {
292+
isVirtual: true,
293+
feedCountry: CONST.TRAVEL.PROGRAM_TRAVEL_US,
300294
},
301295
},
302-
} as unknown as Record<string, WorkspaceCardsList>;
296+
} as unknown as CardList;
303297
const result = getTravelInvoicingCard(cardList);
304298
expect(result).toBeDefined();
305299
expect(result?.nameValuePairs?.feedCountry).toBe(CONST.TRAVEL.PROGRAM_TRAVEL_US);
@@ -308,19 +302,17 @@ describe('TravelInvoicingUtils', () => {
308302
isDevelopmentSpy.mockReturnValue(true);
309303

310304
const cardList = {
311-
workspaceCards: {
312-
// eslint-disable-next-line @typescript-eslint/naming-convention
313-
'9999': {
314-
cardID: 9999,
315-
state: 3,
316-
bank: 'Expensify Card',
317-
nameValuePairs: {
318-
isVirtual: true,
319-
feedCountry: 'OTHER_COUNTRY',
320-
},
305+
// eslint-disable-next-line @typescript-eslint/naming-convention
306+
'9999': {
307+
cardID: 9999,
308+
state: 3,
309+
bank: 'Expensify Card',
310+
nameValuePairs: {
311+
isVirtual: true,
312+
feedCountry: 'OTHER_COUNTRY',
321313
},
322314
},
323-
} as unknown as Record<string, WorkspaceCardsList>;
315+
} as unknown as CardList;
324316

325317
const result = getTravelInvoicingCard(cardList);
326318
expect(result).toBeDefined();
@@ -330,33 +322,29 @@ describe('TravelInvoicingUtils', () => {
330322

331323
describe('isTravelCVVEligible', () => {
332324
const mockTravelCardList = {
333-
workspaceCards: {
334-
// eslint-disable-next-line @typescript-eslint/naming-convention
335-
'1234': {
336-
cardID: 1234,
337-
state: 3,
338-
nameValuePairs: {
339-
isVirtual: true,
340-
feedCountry: CONST.TRAVEL.PROGRAM_TRAVEL_US,
341-
},
325+
// eslint-disable-next-line @typescript-eslint/naming-convention
326+
'1234': {
327+
cardID: 1234,
328+
state: 3,
329+
nameValuePairs: {
330+
isVirtual: true,
331+
feedCountry: CONST.TRAVEL.PROGRAM_TRAVEL_US,
342332
},
343333
},
344-
} as unknown as Record<string, WorkspaceCardsList>;
334+
} as unknown as CardList;
345335

346336
const mockNonTravelCardList = {
347-
workspaceCards: {
348-
// eslint-disable-next-line @typescript-eslint/naming-convention
349-
'5678': {
350-
cardID: 5678,
351-
state: 3,
352-
bank: 'Expensify Card',
353-
nameValuePairs: {
354-
isVirtual: true,
355-
feedCountry: 'OTHER_COUNTRY',
356-
},
337+
// eslint-disable-next-line @typescript-eslint/naming-convention
338+
'5678': {
339+
cardID: 5678,
340+
state: 3,
341+
bank: 'Expensify Card',
342+
nameValuePairs: {
343+
isVirtual: true,
344+
feedCountry: 'OTHER_COUNTRY',
357345
},
358346
},
359-
} as unknown as Record<string, WorkspaceCardsList>;
347+
} as unknown as CardList;
360348

361349
it('Should return false when beta is false', () => {
362350
const result = isTravelCVVEligible(false, mockTravelCardList);

0 commit comments

Comments
 (0)