diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts index c4d67adcd54a..9e3a7f66131a 100644 --- a/src/libs/CardUtils.ts +++ b/src/libs/CardUtils.ts @@ -127,7 +127,7 @@ function maskCard(lastFour = ''): string { * @returns a physical card object (or undefined if none is found) */ function findPhysicalCard(cards: Card[]) { - return cards.find((card) => !card.isVirtual); + return cards.find((card) => !card.nameValuePairs?.isVirtual); } /** diff --git a/src/libs/migrateOnyx.ts b/src/libs/migrateOnyx.ts index 412a8e00f052..3b0829ad9ba3 100644 --- a/src/libs/migrateOnyx.ts +++ b/src/libs/migrateOnyx.ts @@ -4,6 +4,7 @@ import KeyReportActionsDraftByReportActionID from './migrations/KeyReportActions import NVPMigration from './migrations/NVPMigration'; import PronounsMigration from './migrations/PronounsMigration'; import RemoveEmptyReportActionsDrafts from './migrations/RemoveEmptyReportActionsDrafts'; +import RenameCardIsVirtual from './migrations/RenameCardIsVirtual'; import RenameReceiptFilename from './migrations/RenameReceiptFilename'; import TransactionBackupsToCollection from './migrations/TransactionBackupsToCollection'; @@ -14,6 +15,7 @@ export default function () { return new Promise((resolve) => { // Add all migrations to an array so they are executed in order const migrationPromises = [ + RenameCardIsVirtual, CheckForPreviousReportActionID, RenameReceiptFilename, KeyReportActionsDraftByReportActionID, diff --git a/src/libs/migrations/RenameCardIsVirtual.ts b/src/libs/migrations/RenameCardIsVirtual.ts new file mode 100644 index 000000000000..4d03a9687a70 --- /dev/null +++ b/src/libs/migrations/RenameCardIsVirtual.ts @@ -0,0 +1,52 @@ +import Onyx from 'react-native-onyx'; +import type {NullishDeep, OnyxEntry} from 'react-native-onyx'; +import Log from '@libs/Log'; +import ONYXKEYS from '@src/ONYXKEYS'; +import type {Card} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; + +type OldCard = Card & {isVirtual?: boolean}; + +// This migration changes the property name on each card from card list from isVirtual to nameValuePairs.isVirtual +export default function () { + return new Promise((resolve) => { + const connectionID = Onyx.connect({ + key: ONYXKEYS.CARD_LIST, + callback: (cardList: OnyxEntry>) => { + Onyx.disconnect(connectionID); + + if (!cardList || isEmptyObject(cardList)) { + Log.info('[Migrate Onyx] Skipped migration RenameCardIsVirtual because there are no cards linked to the account'); + return resolve(); + } + const cardsWithIsVirtualProp = Object.values(cardList).filter((card) => card.isVirtual !== undefined); + if (!cardsWithIsVirtualProp.length) { + Log.info('[Migrate Onyx] Skipped migration RenameCardIsVirtual because there were no cards with the isVirtual property'); + return resolve(); + } + + Log.info('[Migrate Onyx] Running RenameCardIsVirtual migration'); + const dataToSave: Record> = cardsWithIsVirtualProp.reduce((result, card) => { + if (!card) { + return result; + } + return { + ...result, + [card.cardID]: { + nameValuePairs: { + isVirtual: card.isVirtual, + }, + isVirtual: undefined, + }, + }; + }, {}); + + // eslint-disable-next-line rulesdir/prefer-actions-set-data + Onyx.merge(ONYXKEYS.CARD_LIST, dataToSave).then(() => { + Log.info(`[Migrate Onyx] Ran migration RenameCardIsVirtual and renamed ${Object.keys(dataToSave)?.length} properties`); + resolve(); + }); + }, + }); + }); +} diff --git a/src/pages/settings/Wallet/ActivatePhysicalCardPage.tsx b/src/pages/settings/Wallet/ActivatePhysicalCardPage.tsx index d5b1230fd216..a031cf6363f4 100644 --- a/src/pages/settings/Wallet/ActivatePhysicalCardPage.tsx +++ b/src/pages/settings/Wallet/ActivatePhysicalCardPage.tsx @@ -56,7 +56,7 @@ function ActivatePhysicalCardPage({ const [lastPressedDigit, setLastPressedDigit] = useState(''); const domainCards = CardUtils.getDomainCards(cardList)[domain] ?? []; - const physicalCard = domainCards.find((card) => !card.isVirtual); + const physicalCard = domainCards.find((card) => !card.nameValuePairs?.isVirtual); const cardID = physicalCard?.cardID ?? 0; const cardError = ErrorUtils.getLatestErrorMessage(physicalCard ?? {}); diff --git a/src/pages/settings/Wallet/Card/BaseGetPhysicalCard.tsx b/src/pages/settings/Wallet/Card/BaseGetPhysicalCard.tsx index bcd1c1096b0e..9498b116cda9 100644 --- a/src/pages/settings/Wallet/Card/BaseGetPhysicalCard.tsx +++ b/src/pages/settings/Wallet/Card/BaseGetPhysicalCard.tsx @@ -115,7 +115,7 @@ function BaseGetPhysicalCard({ } const domainCards = CardUtils.getDomainCards(cardList)[domain] || []; - const physicalCard = domainCards.find((card) => !card?.isVirtual); + const physicalCard = domainCards.find((card) => !card?.nameValuePairs?.isVirtual); // When there are no cards for the specified domain, user is redirected to the wallet page if (domainCards.length === 0) { @@ -148,7 +148,7 @@ function BaseGetPhysicalCard({ // If the current step of the get physical card flow is the confirmation page if (isConfirmation) { const domainCards = CardUtils.getDomainCards(cardList)[domain]; - const physicalCard = domainCards.find((card) => !card?.isVirtual); + const physicalCard = domainCards.find((card) => !card?.nameValuePairs?.isVirtual); const cardID = physicalCard?.cardID ?? 0; Wallet.requestPhysicalExpensifyCard(cardID, session?.authToken ?? '', updatedPrivatePersonalDetails); diff --git a/src/pages/settings/Wallet/ExpensifyCardPage.tsx b/src/pages/settings/Wallet/ExpensifyCardPage.tsx index 4c8b02eabdc6..d96574063ac7 100644 --- a/src/pages/settings/Wallet/ExpensifyCardPage.tsx +++ b/src/pages/settings/Wallet/ExpensifyCardPage.tsx @@ -64,8 +64,8 @@ function ExpensifyCardPage({ const {isOffline} = useNetwork(); const {translate} = useLocalize(); const domainCards = useMemo(() => cardList && CardUtils.getDomainCards(cardList)[domain], [cardList, domain]); - const virtualCard = useMemo(() => domainCards?.find((card) => card.isVirtual), [domainCards]); - const physicalCard = useMemo(() => domainCards?.find((card) => !card.isVirtual), [domainCards]); + const virtualCard = useMemo(() => domainCards?.find((card) => card.nameValuePairs?.isVirtual), [domainCards]); + const physicalCard = useMemo(() => domainCards?.find((card) => !card.nameValuePairs?.isVirtual), [domainCards]); const [isLoading, setIsLoading] = useState(false); const [isNotFound, setIsNotFound] = useState(false); diff --git a/src/pages/settings/Wallet/PaymentMethodList.tsx b/src/pages/settings/Wallet/PaymentMethodList.tsx index 2bbc73355d68..c897f07ce853 100644 --- a/src/pages/settings/Wallet/PaymentMethodList.tsx +++ b/src/pages/settings/Wallet/PaymentMethodList.tsx @@ -197,7 +197,7 @@ function PaymentMethodList({ if (shouldShowAssignedCards) { const assignedCards = Object.values(cardList ?? {}) // Filter by physical, active cards associated with a domain - .filter((card) => !card.isVirtual && !!card.domainName && CONST.EXPENSIFY_CARD.ACTIVE_STATES.includes(card.state ?? 0)); + .filter((card) => !card.nameValuePairs?.isVirtual && !!card.domainName && CONST.EXPENSIFY_CARD.ACTIVE_STATES.includes(card.state ?? 0)); const numberPhysicalExpensifyCards = assignedCards.filter((card) => CardUtils.isExpensifyCard(card.cardID)).length; diff --git a/src/pages/settings/Wallet/ReportVirtualCardFraudPage.tsx b/src/pages/settings/Wallet/ReportVirtualCardFraudPage.tsx index 40a3eacb4ed9..7a6460029a8e 100644 --- a/src/pages/settings/Wallet/ReportVirtualCardFraudPage.tsx +++ b/src/pages/settings/Wallet/ReportVirtualCardFraudPage.tsx @@ -44,7 +44,7 @@ function ReportVirtualCardFraudPage({ const {translate} = useLocalize(); const domainCards = CardUtils.getDomainCards(cardList)[domain]; - const virtualCard = domainCards?.find((card) => card.isVirtual); + const virtualCard = domainCards?.find((card) => card.nameValuePairs?.isVirtual); const virtualCardError = ErrorUtils.getLatestErrorMessage(virtualCard?.errors ?? {}); const prevIsLoading = usePrevious(formData?.isLoading); diff --git a/src/types/onyx/Card.ts b/src/types/onyx/Card.ts index 11cc8dc26b4c..50403b982c0d 100644 --- a/src/types/onyx/Card.ts +++ b/src/types/onyx/Card.ts @@ -9,7 +9,6 @@ type Card = { availableSpend: number; domainName: string; lastFourPAN?: string; - isVirtual: boolean; // Deprecating, use nameValuePairs.isVirtual fraud: ValueOf; errors?: OnyxCommon.Errors; isLoading?: boolean;