diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 0a17d3a1d2f7..7b6335ccf984 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -291,6 +291,7 @@ const ONYXKEYS = { PRIVATE_NOTES_FORM: 'privateNotesForm', I_KNOW_A_TEACHER_FORM: 'iKnowTeacherForm', INTRO_SCHOOL_PRINCIPAL_FORM: 'introSchoolPrincipalForm', + REPORT_VIRTUAL_CARD_FRAUD: 'reportVirtualCardFraudForm', }, } as const; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 21aaa55f099b..2069f773075b 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -75,6 +75,10 @@ export default { route: '/settings/wallet/card/:domain', getRoute: (domain: string) => `/settings/wallet/card/${domain}`, }, + SETTINGS_REPORT_FRAUD: { + route: '/settings/wallet/cards/:domain/report-virtual-fraud', + getRoute: (domain: string) => `/settings/wallet/cards/${domain}/report-virtual-fraud`, + }, SETTINGS_ADD_DEBIT_CARD: 'settings/wallet/add-debit-card', SETTINGS_ADD_BANK_ACCOUNT: 'settings/wallet/add-bank-account', SETTINGS_ENABLE_PAYMENTS: 'settings/wallet/enable-payments', diff --git a/src/languages/en.ts b/src/languages/en.ts index b4d83ac36217..f69f9ea4bedd 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -833,6 +833,7 @@ export default { availableSpend: 'Remaining spending power', virtualCardNumber: 'Virtual card number', physicalCardNumber: 'Physical card number', + reportFraud: 'Report virtual card fraud', cardDetails: { cardNumber: 'Virtual card number', expiration: 'Expiration', @@ -842,6 +843,12 @@ export default { copyCardNumber: 'Copy card number', }, }, + reportFraudPage: { + title: 'Report virtual card fraud', + description: 'If your virtual card details have been stolen or compromised, we’ll permanently deactivate your existing card and provide you with a new virtual card and number.', + deactivateCard: 'Deactivate card', + reportVirtualCardFraud: 'Report virtual card fraud', + }, activateCardPage: { activateCard: 'Activate card', pleaseEnterLastFour: 'Please enter the last four digits of your card.', diff --git a/src/languages/es.ts b/src/languages/es.ts index 0e87425f3dde..83e09b2a62c0 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -829,6 +829,7 @@ export default { availableSpend: 'Capacidad de gasto restante', virtualCardNumber: 'Número de la tarjeta virtual', physicalCardNumber: 'Número de la tarjeta física', + reportFraud: 'Reportar fraude con la tarjeta virtual', cardDetails: { cardNumber: 'Número de tarjeta virtual', expiration: 'Expiración', @@ -838,6 +839,13 @@ export default { copyCardNumber: 'Copiar número de la tarjeta', }, }, + reportFraudPage: { + title: 'Reportar fraude con la tarjeta virtual', + description: + 'Si los datos de tu tarjeta virtual han sido robados o se han visto comprometidos, desactivaremos permanentemente la tarjeta actual y le proporcionaremos una tarjeta virtual y un número nuevo.', + deactivateCard: 'Desactivar tarjeta', + reportVirtualCardFraud: 'Reportar fraude con la tarjeta virtual', + }, activateCardPage: { activateCard: 'Activar tarjeta', pleaseEnterLastFour: 'Introduce los cuatro últimos dígitos de la tarjeta.', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 3c307f78319d..c32120db2e45 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -142,6 +142,7 @@ const SettingsModalStackNavigator = createModalStackNavigator({ Settings_Lounge_Access: () => require('../../../pages/settings/Profile/LoungeAccessPage').default, Settings_Wallet: () => require('../../../pages/settings/Wallet/WalletPage').default, Settings_Wallet_DomainCards: () => require('../../../pages/settings/Wallet/ExpensifyCardPage').default, + Settings_Wallet_ReportVirtualCardFraud: () => require('../../../pages/settings/Wallet/ReportVirtualCardFraudPage').default, Settings_Wallet_Card_Activate: () => require('../../../pages/settings/Wallet/ActivatePhysicalCardPage').default, Settings_Wallet_Transfer_Balance: () => require('../../../pages/settings/Wallet/TransferBalancePage').default, Settings_Wallet_Choose_Transfer_Account: () => require('../../../pages/settings/Wallet/ChooseTransferAccountPage').default, diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 821b73268d0d..5616e8d63797 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -73,6 +73,10 @@ export default { path: ROUTES.SETTINGS_WALLET_DOMAINCARDS.route, exact: true, }, + Settings_Wallet_ReportVirtualCardFraud: { + path: ROUTES.SETTINGS_REPORT_FRAUD.route, + exact: true, + }, Settings_Wallet_EnablePayments: { path: ROUTES.SETTINGS_ENABLE_PAYMENTS, exact: true, diff --git a/src/libs/actions/Card.js b/src/libs/actions/Card.js index abfd5a6bba98..a060c1bc67fa 100644 --- a/src/libs/actions/Card.js +++ b/src/libs/actions/Card.js @@ -2,6 +2,47 @@ import Onyx from 'react-native-onyx'; import ONYXKEYS from '../../ONYXKEYS'; import * as API from '../API'; +/** + * @param {Number} cardID + */ +function reportVirtualExpensifyCardFraud(cardID) { + API.write( + 'ReportVirtualExpensifyCardFraud', + { + cardID, + }, + { + optimisticData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD, + value: { + isLoading: true, + }, + }, + ], + successData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD, + value: { + isLoading: false, + }, + }, + ], + failureData: [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD, + value: { + isLoading: false, + }, + }, + ], + }, + ); +} + /** * Activates the physical Expensify card based on the last four digits of the card number * @@ -60,4 +101,4 @@ function clearCardListErrors(cardID) { Onyx.merge(ONYXKEYS.CARD_LIST, {[cardID]: {errors: null, isLoading: false}}); } -export {activatePhysicalExpensifyCard, clearCardListErrors}; +export {reportVirtualExpensifyCardFraud, activatePhysicalExpensifyCard, clearCardListErrors}; diff --git a/src/pages/settings/Wallet/ExpensifyCardPage.js b/src/pages/settings/Wallet/ExpensifyCardPage.js index 19d589acb421..cfbd26133ced 100644 --- a/src/pages/settings/Wallet/ExpensifyCardPage.js +++ b/src/pages/settings/Wallet/ExpensifyCardPage.js @@ -14,6 +14,7 @@ import useLocalize from '../../../hooks/useLocalize'; import * as CurrencyUtils from '../../../libs/CurrencyUtils'; import Navigation from '../../../libs/Navigation/Navigation'; import styles from '../../../styles/styles'; +import * as Expensicons from '../../../components/Icon/Expensicons'; import * as CardUtils from '../../../libs/CardUtils'; import Button from '../../../components/Button'; import CardDetails from './WalletPage/CardDetails'; @@ -108,6 +109,13 @@ function ExpensifyCardPage({ } /> )} + Navigation.navigate(ROUTES.SETTINGS_REPORT_FRAUD.getRoute(domain))} + /> )} {!_.isEmpty(physicalCard) && ( @@ -115,7 +123,7 @@ function ExpensifyCardPage({ description={translate('cardPage.physicalCardNumber')} title={CardUtils.maskCard(physicalCard.lastFourPAN)} interactive={false} - titleStyle={styles.walletCardNumber} + titleStyle={styles.walletCardMenuItem} /> )} diff --git a/src/pages/settings/Wallet/ReportVirtualCardFraudPage.js b/src/pages/settings/Wallet/ReportVirtualCardFraudPage.js new file mode 100644 index 000000000000..2652494aa1c7 --- /dev/null +++ b/src/pages/settings/Wallet/ReportVirtualCardFraudPage.js @@ -0,0 +1,104 @@ +import React, {useEffect} from 'react'; +import _ from 'underscore'; +import {View} from 'react-native'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; +import ROUTES from '../../../ROUTES'; +import HeaderWithBackButton from '../../../components/HeaderWithBackButton'; +import ScreenWrapper from '../../../components/ScreenWrapper'; +import Navigation from '../../../libs/Navigation/Navigation'; +import styles from '../../../styles/styles'; +import Text from '../../../components/Text'; +import useLocalize from '../../../hooks/useLocalize'; +import * as Card from '../../../libs/actions/Card'; +import assignedCardPropTypes from './assignedCardPropTypes'; +import * as CardUtils from '../../../libs/CardUtils'; +import ONYXKEYS from '../../../ONYXKEYS'; +import NotFoundPage from '../../ErrorPage/NotFoundPage'; +import usePrevious from '../../../hooks/usePrevious'; +import FormAlertWithSubmitButton from '../../../components/FormAlertWithSubmitButton'; +import * as ErrorUtils from '../../../libs/ErrorUtils'; + +const propTypes = { + /* Onyx Props */ + formData: PropTypes.shape({ + isLoading: PropTypes.bool, + }), + cardList: PropTypes.objectOf(assignedCardPropTypes), + /** The parameters needed to authenticate with a short-lived token are in the URL */ + route: PropTypes.shape({ + /** Each parameter passed via the URL */ + params: PropTypes.shape({ + /** Domain string */ + domain: PropTypes.string, + }), + }).isRequired, +}; + +const defaultProps = { + cardList: {}, + formData: {}, +}; + +function ReportVirtualCardFraudPage({ + route: { + params: {domain}, + }, + cardList, + formData, +}) { + const {translate} = useLocalize(); + + const domainCards = CardUtils.getDomainCards(cardList)[domain]; + const virtualCard = _.find(domainCards, (card) => card.isVirtual) || {}; + const virtualCardError = ErrorUtils.getLatestErrorMessage(virtualCard) || ''; + + const prevIsLoading = usePrevious(formData.isLoading); + + useEffect(() => { + if (!prevIsLoading || formData.isLoading) { + return; + } + if (!_.isEmpty(virtualCard.errors)) { + return; + } + + Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARDS.getRoute(domain)); + }, [domain, formData.isLoading, prevIsLoading, virtualCard.errors]); + + if (_.isEmpty(virtualCard)) { + return ; + } + + return ( + + Navigation.goBack(ROUTES.SETTINGS_WALLET_DOMAINCARDS.getRoute(domain))} + /> + + {translate('reportFraudPage.description')} + Card.reportVirtualExpensifyCardFraud(virtualCard.cardID)} + message={virtualCardError} + isLoading={formData.isLoading} + buttonText={translate('reportFraudPage.deactivateCard')} + /> + + + ); +} + +ReportVirtualCardFraudPage.propTypes = propTypes; +ReportVirtualCardFraudPage.defaultProps = defaultProps; +ReportVirtualCardFraudPage.displayName = 'ReportVirtualCardFraudPage'; + +export default withOnyx({ + cardList: { + key: ONYXKEYS.CARD_LIST, + }, + formData: { + key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD, + }, +})(ReportVirtualCardFraudPage); diff --git a/src/styles/styles.js b/src/styles/styles.js index d4aacfff96aa..7cb4dab6e0d7 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -3770,7 +3770,7 @@ const styles = (theme) => ({ overflow: 'hidden', }, - walletCardNumber: { + walletCardMenuItem: { color: theme.text, fontSize: variables.fontSizeNormal, },