Skip to content

Commit

Permalink
Merge pull request #29017 from lukemorawski/22875-api_call_on_reveal_…
Browse files Browse the repository at this point in the history
…card_details

22875 Add API Calls when clicking “Reveal details” buttons
  • Loading branch information
marcaaron authored Oct 25, 2023
2 parents 3c9572d + 934344a commit 65d4e2b
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 9 deletions.
29 changes: 27 additions & 2 deletions src/libs/actions/Card.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Onyx from 'react-native-onyx';
import ONYXKEYS from '../../ONYXKEYS';
import * as API from '../API';

import CONST from '../../CONST';
/**
* @param {Number} cardID
*/
Expand Down Expand Up @@ -146,4 +146,29 @@ function clearCardListErrors(cardID) {
Onyx.merge(ONYXKEYS.CARD_LIST, {[cardID]: {errors: null, isLoading: false}});
}

export {requestReplacementExpensifyCard, activatePhysicalExpensifyCard, clearCardListErrors, reportVirtualExpensifyCardFraud};
/**
* Makes an API call to get virtual card details (pan, cvv, expiration date, address)
* This function purposefully uses `makeRequestWithSideEffects` method. For security reason
* card details cannot be persisted in Onyx and have to be asked for each time a user want's to
* reveal them.
*
* @param {String} cardID - virtual card ID
*
* @returns {Promise<Object>} - promise with card details object
*/
function revealVirtualCardDetails(cardID) {
return new Promise((resolve, reject) => {
// eslint-disable-next-line rulesdir/no-api-side-effects-method
API.makeRequestWithSideEffects('RevealVirtualCardDetails', {cardID})
.then((response) => {
if (response.jsonCode !== CONST.JSON_CODE.SUCCESS) {
reject();
return;
}
resolve(response);
})
.catch(reject);
});
}

export {requestReplacementExpensifyCard, activatePhysicalExpensifyCard, clearCardListErrors, reportVirtualExpensifyCardFraud, revealVirtualCardDetails};
53 changes: 46 additions & 7 deletions src/pages/settings/Wallet/ExpensifyCardPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ import * as Expensicons from '../../../components/Icon/Expensicons';
import * as CardUtils from '../../../libs/CardUtils';
import Button from '../../../components/Button';
import CardDetails from './WalletPage/CardDetails';
import * as Card from '../../../libs/actions/Card';
import MenuItem from '../../../components/MenuItem';
import CONST from '../../../CONST';
import assignedCardPropTypes from './assignedCardPropTypes';
import useNetwork from '../../../hooks/useNetwork';
import theme from '../../../styles/themes/default';
import DotIndicatorMessage from '../../../components/DotIndicatorMessage';
import * as Link from '../../../libs/actions/Link';
Expand Down Expand Up @@ -50,12 +52,14 @@ function ExpensifyCardPage({
params: {domain},
},
}) {
const {isOffline} = useNetwork();
const {translate} = useLocalize();
const domainCards = CardUtils.getDomainCards(cardList)[domain];
const virtualCard = _.find(domainCards, (card) => card.isVirtual) || {};
const physicalCard = _.find(domainCards, (card) => !card.isVirtual) || {};

const [shouldShowCardDetails, setShouldShowCardDetails] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [details, setDetails] = useState({});

if (_.isEmpty(virtualCard) && _.isEmpty(physicalCard)) {
return <NotFoundPage />;
Expand All @@ -64,7 +68,14 @@ function ExpensifyCardPage({
const formattedAvailableSpendAmount = CurrencyUtils.convertToDisplayString(physicalCard.availableSpend || virtualCard.availableSpend || 0);

const handleRevealDetails = () => {
setShouldShowCardDetails(true);
setIsLoading(true);
// We can't store the response in Onyx for security reasons.
// That is this action is handled manually and the response is stored in a local state
// Hence the eslint disable here.
// eslint-disable-next-line rulesdir/no-thenable-actions-in-views
Card.revealVirtualCardDetails(virtualCard.cardID)
.then(setDetails)
.finally(() => setIsLoading(false));
};

const hasDetectedDomainFraud = _.some(domainCards, (card) => card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.DOMAIN);
Expand Down Expand Up @@ -97,6 +108,32 @@ function ExpensifyCardPage({

{hasDetectedIndividualFraud && !hasDetectedDomainFraud ? (
<>
{details.pan ? (
<CardDetails
pan={details.pan}
expiration={details.expiration}
cvv={details.cvv}
privatePersonalDetails={{address: details.address}}
domain={domain}
/>
) : (
<MenuItemWithTopDescription
description={translate('cardPage.virtualCardNumber')}
title={CardUtils.maskCard(virtualCard.lastFourPAN)}
interactive={false}
titleStyle={styles.walletCardNumber}
shouldShowRightComponent
rightComponent={
<Button
medium
text={translate('cardPage.cardDetails.revealDetails')}
onPress={handleRevealDetails}
isDisabled={isLoading || isOffline}
isLoading={isLoading}
/>
}
/>
)}
<DangerCardSection
title={translate('cardPage.suspiciousBannerTitle')}
description={translate('cardPage.suspiciousBannerDescription')}
Expand All @@ -123,12 +160,12 @@ function ExpensifyCardPage({
/>
{!_.isEmpty(virtualCard) && (
<>
{shouldShowCardDetails ? (
{details.pan ? (
<CardDetails
// This is just a temporary mock, it will be replaced in this issue https://github.com/orgs/Expensify/projects/58?pane=issue&itemId=33286617
pan="1234123412341234"
expiration="11/02/2024"
cvv="321"
pan={details.pan}
expiration={details.expiration}
cvv={details.cvv}
privatePersonalDetails={{address: details.address}}
domain={domain}
/>
) : (
Expand All @@ -143,6 +180,8 @@ function ExpensifyCardPage({
medium
text={translate('cardPage.cardDetails.revealDetails')}
onPress={handleRevealDetails}
isDisabled={isLoading || isOffline}
isLoading={isLoading}
/>
}
/>
Expand Down
15 changes: 15 additions & 0 deletions src/types/onyx/Card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,19 @@ type Card = {
isLoading?: boolean;
};

type TCardDetails = {
pan: string;
expiration: string;
cvv: string;
address: {
street: string;
street2: string;
city: string;
state: string;
zip: string;
country: string;
};
};

export default Card;
export type {TCardDetails};

0 comments on commit 65d4e2b

Please sign in to comment.