Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add report fraud confirmation page when getting new virtual card #55278

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5029dd3
basic fraud report confirmation modal added
burczu Jan 14, 2025
5ac68f4
navigation back + preventing showing 404 page
burczu Jan 15, 2025
f8a76ad
Merge branch 'main' into fix/53996-wallet-its-not-here-error
burczu Jan 15, 2025
01c94a4
modal content and styles added
burczu Jan 15, 2025
f6c1c27
unnecessary condition removed
burczu Jan 15, 2025
3d65b28
linter errors fixed
burczu Jan 15, 2025
3148d2d
another linter error fixed
burczu Jan 16, 2025
6d8ae98
Merge branch 'main' into fix/53996-wallet-its-not-here-error
burczu Jan 21, 2025
97951e0
cherry pick from other PR
burczu Jan 21, 2025
6f3bb57
adjustments after cherry pick
burczu Jan 21, 2025
533fd17
unnecessary commented line removed
burczu Jan 21, 2025
f2856c7
storing previous virtual card fixed
burczu Jan 21, 2025
8d32b27
translations introduced
burczu Jan 21, 2025
f7f1630
jamiegpt translations added
burczu Jan 21, 2025
4f285fc
modal title translated
burczu Jan 21, 2025
b7bbab5
Merge branch 'main' into fix/53996-wallet-its-not-here-error
burczu Jan 21, 2025
d469ca4
Merge branch 'main' into fix/53996-wallet-its-not-here-error
burczu Jan 21, 2025
7ac64e0
Merge branch 'main' into fix/53996-wallet-its-not-here-error
burczu Jan 22, 2025
bcee6ae
navigate as an side effect to fix behaviour on mobile
burczu Jan 23, 2025
abb7f9c
Merge branch 'main' into fix/53996-wallet-its-not-here-error
burczu Jan 23, 2025
d197b71
unnecessary props removed
burczu Jan 23, 2025
e69eac5
Merge branch 'main' into fix/53996-wallet-its-not-here-error
burczu Jan 28, 2025
e8bbcaa
switched from confirmation modal to standalone page
burczu Jan 28, 2025
6fc26fc
eslint fix
burczu Jan 28, 2025
2cecae4
redirecting to fixed page from card details page fixing redirect loop
burczu Jan 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions assets/images/magnifying-glass-spy-mouth-closed.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ const ROUTES = {
route: 'settings/wallet/card/:cardID/report-virtual-fraud',
getRoute: (cardID: string) => `settings/wallet/card/${cardID}/report-virtual-fraud` as const,
},
SETTINGS_REPORT_FRAUD_CONFIRMATION: {
route: 'settings/wallet/card/:cardID/report-virtual-fraud-confirm',
getRoute: (cardID: string) => `settings/wallet/card/${cardID}/report-virtual-fraud-confirm` as const,
},
SETTINGS_DOMAINCARD_REPORT_FRAUD: {
route: 'settings/card/:cardID/report-virtual-fraud',
getRoute: (cardID: string) => `settings/card/${cardID}/report-virtual-fraud` as const,
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ const SCREENS = {
ENABLE_PAYMENTS: 'Settings_Wallet_EnablePayments',
CARD_ACTIVATE: 'Settings_Wallet_Card_Activate',
REPORT_VIRTUAL_CARD_FRAUD: 'Settings_Wallet_ReportVirtualCardFraud',
REPORT_VIRTUAL_CARD_FRAUD_CONFIRMATION: 'Settings_Wallet_ReportVirtualCardFraudConfirmation',
CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS: 'Settings_Wallet_Cards_Digital_Details_Update_Address',
VERIFY_ACCOUNT: 'Settings_Wallet_Verify_Account',
},
Expand Down
2 changes: 2 additions & 0 deletions src/components/Icon/Expensicons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ import Link from '@assets/images/link.svg';
import Location from '@assets/images/location.svg';
import Lock from '@assets/images/lock.svg';
import Luggage from '@assets/images/luggage.svg';
import MagnifyingGlassSpyMouthClosed from '@assets/images/magnifying-glass-spy-mouth-closed.svg';
import MagnifyingGlass from '@assets/images/magnifying-glass.svg';
import Mail from '@assets/images/mail.svg';
import MakeAdmin from '@assets/images/make-admin.svg';
Expand Down Expand Up @@ -422,4 +423,5 @@ export {
GalleryNotFound,
Train,
boltSlash,
MagnifyingGlassSpyMouthClosed,
};
5 changes: 5 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1614,6 +1614,11 @@ const translations = {
deactivateCard: 'Deactivate card',
reportVirtualCardFraud: 'Report virtual card fraud',
},
reportFraudConfirmationPage: {
title: 'Card fraud reported',
description: 'We’ve permanently deactivated your existing card. When you go back to view your card details, you’ll have a new virtual card available.',
buttonText: 'Got it, thanks!',
},
activateCardPage: {
activateCard: 'Activate card',
pleaseEnterLastFour: 'Please enter the last four digits of your card.',
Expand Down
5 changes: 5 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1616,6 +1616,11 @@ const translations = {
deactivateCard: 'Desactivar tarjeta',
reportVirtualCardFraud: 'Reportar fraude con la tarjeta virtual',
},
reportFraudConfirmationPage: {
title: 'Fraude con tarjeta reportado',
description: 'Hemos desactivado permanentemente tu tarjeta existente. Cuando vuelvas a ver los detalles de tu tarjeta, tendrás una nueva tarjeta virtual disponible.',
buttonText: 'Entendido, ¡gracias!',
},
activateCardPage: {
activateCard: 'Activar tarjeta',
pleaseEnterLastFour: 'Introduce los cuatro últimos dígitos de la tarjeta.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PersonalDetails/PersonalAddressPage').default,
[SCREENS.SETTINGS.WALLET.DOMAIN_CARD]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ExpensifyCardPage').default,
[SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ReportVirtualCardFraudPage').default,
[SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD_CONFIRMATION]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ReportVirtualCardFraudConfirmationPage').default,
[SCREENS.SETTINGS.WALLET.CARD_ACTIVATE]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ActivatePhysicalCardPage').default,
[SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.NAME]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/Card/GetPhysicalCardName').default,
[SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.PHONE]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/Card/GetPhysicalCardPhone').default,
Expand Down
4 changes: 4 additions & 0 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ const config: LinkingOptions<RootStackParamList>['config'] = {
path: ROUTES.SETTINGS_REPORT_FRAUD.route,
exact: true,
},
[SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD_CONFIRMATION]: {
path: ROUTES.SETTINGS_REPORT_FRAUD_CONFIRMATION.route,
exact: true,
},
[SCREENS.SETTINGS.WALLET.CARD_GET_PHYSICAL.NAME]: {
path: ROUTES.SETTINGS_WALLET_CARD_GET_PHYSICAL_NAME.route,
exact: true,
Expand Down
4 changes: 4 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ type SettingsNavigatorParamList = {
/** cardID of selected card */
cardID: string;
};
[SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD_CONFIRMATION]: {
/** cardID of selected card */
cardID: string;
};
[SCREENS.SETTINGS.WALLET.CARD_ACTIVATE]: {
/** cardID of selected card */
cardID: string;
Expand Down
6 changes: 6 additions & 0 deletions src/libs/actions/Card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function reportVirtualExpensifyCardFraud(card: Card, validateCode: string) {
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
value: {
cardID,
isLoading: true,
errors: null,
},
Expand Down Expand Up @@ -225,6 +226,10 @@ function clearCardListErrors(cardID: number) {
Onyx.merge(ONYXKEYS.CARD_LIST, {[cardID]: {errors: null, isLoading: false}});
}

function clearReportVirtualCardFraudForm() {
Onyx.merge(ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD, {cardID: null, isLoading: false, errors: null});
}

/**
* Makes an API call to get virtual card details (pan, cvv, expiration date, address)
* This function purposefully uses `makeRequestWithSideEffects` method. For security reason
Expand Down Expand Up @@ -896,6 +901,7 @@ export {
requestReplacementExpensifyCard,
activatePhysicalExpensifyCard,
clearCardListErrors,
clearReportVirtualCardFraudForm,
clearIssueNewCardError,
reportVirtualExpensifyCardFraud,
revealVirtualCardDetails,
Expand Down
2 changes: 1 addition & 1 deletion src/pages/settings/Wallet/ExpensifyCardPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ function ExpensifyCardPage({
<ScreenWrapper testID={ExpensifyCardPage.displayName}>
<HeaderWithBackButton
title={pageTitle}
onBackButtonPress={() => Navigation.goBack()}
onBackButtonPress={() => Navigation.navigate(ROUTES.SETTINGS_WALLET)}
/>
<ScrollView>
<View style={[styles.flex1, styles.mb9, styles.mt9]}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, {useCallback} from 'react';
import {View} from 'react-native';
import Button from '@components/Button';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Expensicons from '@components/Icon/Expensicons';
import ImageSVG from '@components/ImageSVG';
import ScreenWrapper from '@components/ScreenWrapper';
import Text from '@components/Text';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@navigation/Navigation';
import type {PlatformStackScreenProps} from '@navigation/PlatformStackNavigation/types';
import type {SettingsNavigatorParamList} from '@navigation/types';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';

type ReportVirtualCardFraudConfirmationPageProps = PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD_CONFIRMATION>;

function ReportVirtualCardFraudConfirmationPage({
route: {
params: {cardID = ''},
},
}: ReportVirtualCardFraudConfirmationPageProps) {
const themeStyles = useThemeStyles();
const {translate} = useLocalize();

const close = useCallback(() => {
Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARD.getRoute(cardID));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commenting for reference: This changes caused regression #56026

}, [cardID]);

return (
<ScreenWrapper
includeSafeAreaPaddingBottom
includePaddingTop
shouldEnableMaxHeight
testID={ReportVirtualCardFraudConfirmationPage.displayName}
offlineIndicatorStyle={themeStyles.mtAuto}
>
<HeaderWithBackButton
title={translate('reportFraudConfirmationPage.title')}
onBackButtonPress={close}
/>

<View style={[themeStyles.ph5, themeStyles.mt3, themeStyles.mb5, themeStyles.flex1]}>
<View style={[themeStyles.justifyContentCenter, themeStyles.flex1]}>
<ImageSVG
contentFit="contain"
src={Expensicons.MagnifyingGlassSpyMouthClosed}
style={themeStyles.alignSelfCenter}
width={184}
height={290}
/>

<Text style={[themeStyles.textHeadlineH1, themeStyles.alignSelfCenter, themeStyles.mt5]}>{translate('reportFraudConfirmationPage.title')}</Text>
<Text style={[themeStyles.textSupporting, themeStyles.alignSelfCenter, themeStyles.mt2, themeStyles.textAlignCenter]}>
{translate('reportFraudConfirmationPage.description')}
</Text>
</View>

<Button
text={translate('reportFraudConfirmationPage.buttonText')}
onPress={close}
style={themeStyles.justifyContentEnd}
success
large
/>
</View>
</ScreenWrapper>
);
}

ReportVirtualCardFraudConfirmationPage.displayName = 'ReportVirtualCardFraudConfirmationPage';

export default ReportVirtualCardFraudConfirmationPage;
18 changes: 11 additions & 7 deletions src/pages/settings/Wallet/ReportVirtualCardFraudPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
import {clearCardListErrors, reportVirtualExpensifyCardFraud} from '@userActions/Card';
import {clearCardListErrors, clearReportVirtualCardFraudForm, reportVirtualExpensifyCardFraud} from '@userActions/Card';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
Expand All @@ -42,14 +42,17 @@ function ReportVirtualCardFraudPage({
const latestIssuedVirtualCardID = Object.keys(cardList ?? {})?.pop();
const virtualCardError = getLatestErrorMessage(virtualCard);
const validateError = getLatestErrorMessageField(virtualCard);
const prevVirtualCard = usePrevious(virtualCard);

const [isValidateCodeActionModalVisible, setIsValidateCodeActionModalVisible] = useState(false);

const prevIsLoading = usePrevious(formData?.isLoading);

useBeforeRemove(() => setIsValidateCodeActionModalVisible(false));

useEffect(() => {
clearReportVirtualCardFraudForm();
}, []);

useEffect(() => {
if (!prevIsLoading || formData?.isLoading) {
return;
Expand All @@ -59,17 +62,18 @@ function ReportVirtualCardFraudPage({
}

if (latestIssuedVirtualCardID) {
Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARD.getRoute(latestIssuedVirtualCardID));
Navigation.navigate(ROUTES.SETTINGS_REPORT_FRAUD_CONFIRMATION.getRoute(latestIssuedVirtualCardID));
setIsValidateCodeActionModalVisible(false);
}
}, [cardID, formData?.isLoading, prevIsLoading, virtualCard?.errors, latestIssuedVirtualCardID]);
}, [formData?.isLoading, latestIssuedVirtualCardID, prevIsLoading, virtualCard?.errors]);

const handleValidateCodeEntered = useCallback(
(validateCode: string) => {
if (!virtualCard) {
return;
}

reportVirtualExpensifyCardFraud(virtualCard, validateCode);
setIsValidateCodeActionModalVisible(false);
},
[virtualCard],
);
Expand All @@ -86,7 +90,7 @@ function ReportVirtualCardFraudPage({
setIsValidateCodeActionModalVisible(true);
}, [setIsValidateCodeActionModalVisible]);

if (isEmptyObject(virtualCard) && isEmptyObject(prevVirtualCard)) {
if (isEmptyObject(virtualCard) && !formData?.cardID) {
return <NotFoundPage />;
}

Expand All @@ -102,7 +106,6 @@ function ReportVirtualCardFraudPage({
isAlertVisible={!!virtualCardError}
onSubmit={handleSubmit}
message={virtualCardError}
isLoading={formData?.isLoading}
buttonText={translate('reportFraudPage.deactivateCard')}
containerStyles={[styles.m5]}
/>
Expand All @@ -121,6 +124,7 @@ function ReportVirtualCardFraudPage({
title={translate('cardPage.validateCardTitle')}
descriptionPrimary={translate('cardPage.enterMagicCode', {contactMethod: primaryLogin})}
hasMagicCodeBeenSent={!!loginData?.validateCodeSent}
isLoading={formData?.isLoading}
/>
</View>
</ScreenWrapper>
Expand Down