Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
"Bushwick",
"CARDFROZEN",
"CARDUNFROZEN",
"CARDDEACTIVATED",
"CAROOT",
"CCDQCAMM",
"CFPB",
Expand Down
1 change: 1 addition & 0 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1485,6 +1485,7 @@ const CONST = {
CARD_ASSIGNED: 'CARDASSIGNED',
CARD_FROZEN: 'CARDFROZEN',
CARD_UNFROZEN: 'CARDUNFROZEN',
CARD_DEACTIVATED: 'CARDDEACTIVATED',
PERSONAL_CARD_CONNECTION_BROKEN: 'PERSONALCARDCONNECTIONBROKEN',
CHANGE_FIELD: 'CHANGEFIELD', // OldDot Action
CHANGE_POLICY: 'CHANGEPOLICY',
Expand Down
1 change: 1 addition & 0 deletions src/languages/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2696,6 +2696,7 @@ ${amount} für ${merchant} – ${date}`,
reportFraudConfirmationPage: {
title: 'Kartenbetrug gemeldet',
description: 'Wir haben Ihre bestehende Karte dauerhaft deaktiviert. Wenn Sie Ihre Kartendetails erneut aufrufen, steht Ihnen eine neue virtuelle Karte zur Verfügung.',
descriptionCardNotReplaced: 'Deine Karte wurde dauerhaft deaktiviert. Bitte kontaktiere einen Administrator, um eine neue Karte auszustellen.',
buttonText: 'Verstanden, danke!',
},
activateCardPage: {
Expand Down
1 change: 1 addition & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2752,6 +2752,7 @@ const translations = {
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.',
descriptionCardNotReplaced: 'Your card was permanently deactivated. Please contact an admin to issue a new card.',
buttonText: 'Got it, thanks!',
},
activateCardPage: {
Expand Down
1 change: 1 addition & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2565,6 +2565,7 @@ ${amount} para ${merchant} - ${date}`,
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.',
descriptionCardNotReplaced: 'Tu tarjeta fue desactivada permanentemente. Por favor, contacta a un administrador para emitir una nueva tarjeta.',
buttonText: 'Entendido, ¡gracias!',
},
activateCardPage: {
Expand Down
1 change: 1 addition & 0 deletions src/languages/fr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2704,6 +2704,7 @@ ${amount} pour ${merchant} - ${date}`,
reportFraudConfirmationPage: {
title: 'Fraude à la carte signalée',
description: 'Nous avons définitivement désactivé votre carte actuelle. Lorsque vous retournerez consulter les détails de votre carte, une nouvelle carte virtuelle sera disponible.',
descriptionCardNotReplaced: 'Votre carte a été désactivée définitivement. Veuillez contacter un administrateur pour émettre une nouvelle carte.',
buttonText: 'Compris, merci !',
},
activateCardPage: {
Expand Down
1 change: 1 addition & 0 deletions src/languages/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2692,6 +2692,7 @@ ${amount} per ${merchant} - ${date}`,
reportFraudConfirmationPage: {
title: 'Frode della carta segnalata',
description: 'Abbiamo disattivato definitivamente la tua carta esistente. Quando tornerai a visualizzare i dettagli della carta, avrai a disposizione una nuova carta virtuale.',
descriptionCardNotReplaced: 'La tua carta è stata disattivata permanentemente. Contatta un amministratore per emettere una nuova carta.',
buttonText: 'Ricevuto, grazie!',
},
activateCardPage: {
Expand Down
1 change: 1 addition & 0 deletions src/languages/ja.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2665,6 +2665,7 @@ ${date} の ${merchant} への ${amount}`,
reportFraudConfirmationPage: {
title: 'カード不正利用を報告済み',
description: '既存のカードは永久に無効化しました。カードの詳細画面に戻ると、新しいバーチャルカードが利用可能になっています。',
descriptionCardNotReplaced: 'カードは完全に無効化されました。新しいカードを発行するには管理者に連絡してください。',
buttonText: '了解しました、ありがとうございます!',
},
activateCardPage: {
Expand Down
1 change: 1 addition & 0 deletions src/languages/nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2689,6 +2689,7 @@ ${amount} voor ${merchant} - ${date}`,
reportFraudConfirmationPage: {
title: 'Kaartfraude gemeld',
description: 'We hebben je bestaande kaart permanent gedeactiveerd. Wanneer je teruggaat om je kaartgegevens te bekijken, heb je een nieuwe virtuele kaart beschikbaar.',
descriptionCardNotReplaced: 'Je kaart is permanent gedeactiveerd. Neem contact op met een beheerder om een nieuwe kaart uit te geven.',
buttonText: 'Begrepen, dank je!',
},
activateCardPage: {
Expand Down
1 change: 1 addition & 0 deletions src/languages/pl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2683,6 +2683,7 @@ ${amount} dla ${merchant} - ${date}`,
reportFraudConfirmationPage: {
title: 'Zgłoszono oszustwo kartowe',
description: 'Trwale dezaktywowaliśmy Twoją dotychczasową kartę. Gdy wrócisz do szczegółów karty, będzie tam dostępna nowa wirtualna karta.',
descriptionCardNotReplaced: 'Twoja karta została trwale dezaktywowana. Skontaktuj się z administratorem, aby wydać nową kartę.',
buttonText: 'Jasne, dzięki!',
},
activateCardPage: {
Expand Down
1 change: 1 addition & 0 deletions src/languages/pt-BR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2683,6 +2683,7 @@ ${amount} para ${merchant} - ${date}`,
reportFraudConfirmationPage: {
title: 'Fraude no cartão reportada',
description: 'Desativamos permanentemente seu cartão atual. Quando você voltar para ver os detalhes do cartão, um novo cartão virtual estará disponível.',
descriptionCardNotReplaced: 'Seu cartão foi desativado permanentemente. Entre em contato com um administrador para emitir um novo cartão.',
buttonText: 'Entendido, obrigado!',
},
activateCardPage: {
Expand Down
1 change: 1 addition & 0 deletions src/languages/zh-hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2609,6 +2609,7 @@ ${amount},商户:${merchant} - 日期:${date}`,
reportFraudConfirmationPage: {
title: '已报告卡片欺诈',
description: '我们已永久停用你的现有卡片。当你返回查看卡片详情时,你将会看到一张新的虚拟卡片可用。',
descriptionCardNotReplaced: '您的卡已被永久停用。请联系管理员以发行新卡。',
buttonText: '明白了,谢谢!',
},
activateCardPage: {
Expand Down
14 changes: 12 additions & 2 deletions src/libs/actions/Card.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ type CardListUpdateData = Omit<PartialDeep<Card>, 'errors'> & {

function reportVirtualExpensifyCardFraud(card: Card, validateCode: string) {
const cardID = card?.cardID ?? CONST.DEFAULT_NUMBER_ID;
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD | typeof ONYXKEYS.ACCOUNT>> = [
const optimisticData: Array<OnyxUpdate<typeof ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD | typeof ONYXKEYS.ACCOUNT | typeof ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
Expand All @@ -85,6 +85,11 @@ function reportVirtualExpensifyCardFraud(card: Card, validateCode: string) {
key: ONYXKEYS.ACCOUNT,
value: {isLoading: true},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM,
value: {cardTerminatedWithoutReplacement: null},
},
];

const successData: Array<OnyxUpdate<typeof ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD | typeof ONYXKEYS.ACCOUNT>> = [
Expand All @@ -102,7 +107,7 @@ function reportVirtualExpensifyCardFraud(card: Card, validateCode: string) {
},
];

const failureData: Array<OnyxUpdate<typeof ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD | typeof ONYXKEYS.ACCOUNT>> = [
const failureData: Array<OnyxUpdate<typeof ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD | typeof ONYXKEYS.ACCOUNT | typeof ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM>> = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
Expand All @@ -115,6 +120,11 @@ function reportVirtualExpensifyCardFraud(card: Card, validateCode: string) {
key: ONYXKEYS.ACCOUNT,
value: {isLoading: false},
},
{
onyxMethod: Onyx.METHOD.MERGE,
key: ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM,
value: {cardTerminatedWithoutReplacement: null},
},
];

const parameters: ReportVirtualExpensifyCardFraudParams = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,11 @@ function ActionContentRouter({
/>
);
}
if (action.actionName === CONST.REPORT.ACTIONS.TYPE.CARD_FROZEN || action.actionName === CONST.REPORT.ACTIONS.TYPE.CARD_UNFROZEN) {
if (
action.actionName === CONST.REPORT.ACTIONS.TYPE.CARD_FROZEN ||
action.actionName === CONST.REPORT.ACTIONS.TYPE.CARD_UNFROZEN ||
action.actionName === CONST.REPORT.ACTIONS.TYPE.CARD_DEACTIVATED
) {
return (
<ReportActionItemBasicMessage message="">
<RenderHTML html={`<comment><muted-text>${getReportActionHtml(action)}</muted-text></comment>`} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import ScrollView from '@components/ScrollView';
import Text from '@components/Text';
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import useThemeStyles from '@hooks/useThemeStyles';
import Navigation from '@navigation/Navigation';
import type {PlatformStackScreenProps} from '@navigation/PlatformStackNavigation/types';
import type {SettingsNavigatorParamList} from '@navigation/types';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';

Expand All @@ -25,10 +27,18 @@ function ReportVirtualCardFraudConfirmationPage({
const themeStyles = useThemeStyles();
const {translate} = useLocalize();
const expensifyIcons = useMemoizedLazyExpensifyIcons(['MagnifyingGlassSpyMouthClosed']);
const [physicalCardForm] = useOnyx(ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM);
const isCardTerminatedWithoutReplacement = !!physicalCardForm?.cardTerminatedWithoutReplacement;
const description = isCardTerminatedWithoutReplacement ? 'reportFraudConfirmationPage.descriptionCardNotReplaced' : 'reportFraudConfirmationPage.description';

const close = useCallback(() => {
if (isCardTerminatedWithoutReplacement) {
Navigation.goBack(ROUTES.SETTINGS_WALLET);
return;
}

Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAIN_CARD.getRoute(cardID));
}, [cardID]);
}, [cardID, isCardTerminatedWithoutReplacement]);

return (
<ScreenWrapper
Expand All @@ -53,9 +63,7 @@ function ReportVirtualCardFraudConfirmationPage({
/>

<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>
<Text style={[themeStyles.textSupporting, themeStyles.alignSelfCenter, themeStyles.mt2, themeStyles.textAlignCenter]}>{translate(description)}</Text>
</ScrollView>
<Button
text={translate('reportFraudConfirmationPage.buttonText')}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, {useEffect} from 'react';
import ValidateCodeActionContent from '@components/ValidateCodeActionModal/ValidateCodeActionContent';
import useInitialOnyxValue from '@hooks/useInitialOnyxValue';
import useLocalize from '@hooks/useLocalize';
import useNonPersonalCardList from '@hooks/useNonPersonalCardList';
import useOnyx from '@hooks/useOnyx';
Expand Down Expand Up @@ -29,7 +30,9 @@ function ReportVirtualCardFraudVerifyAccountPage({
const {translate} = useLocalize();
const [validateCodeAction] = useOnyx(ONYXKEYS.VALIDATE_ACTION_CODE);
const [formData] = useOnyx(ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD);
const latestIssuedVirtualCardID = Object.keys(cardList ?? {})?.pop();
const [physicalCardForm] = useOnyx(ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM);
const initialCardList = useInitialOnyxValue(ONYXKEYS.CARD_LIST);
const replacementCardID = Object.keys(cardList ?? {}).find((key) => !Object.hasOwn(initialCardList ?? {}, key) && cardList?.[key]?.cardID) ?? '';

const primaryLogin = usePrimaryContactMethod();
const cardError = getLatestErrorFieldForAnyField(virtualCard);
Expand All @@ -44,11 +47,12 @@ function ReportVirtualCardFraudVerifyAccountPage({
return;
}

if (latestIssuedVirtualCardID) {
if (replacementCardID || physicalCardForm?.cardTerminatedWithoutReplacement) {
const confirmationCardID = replacementCardID || cardID;
Navigation.removeScreenFromNavigationState(SCREENS.SETTINGS.WALLET.DOMAIN_CARD);
Navigation.goBack(ROUTES.SETTINGS_REPORT_FRAUD_CONFIRMATION.getRoute(latestIssuedVirtualCardID));
Navigation.goBack(ROUTES.SETTINGS_REPORT_FRAUD_CONFIRMATION.getRoute(confirmationCardID));
}
}, [formData?.isLoading, latestIssuedVirtualCardID, cardError, codeError, prevIsLoading]);
}, [cardError, cardID, codeError, formData?.isLoading, physicalCardForm?.cardTerminatedWithoutReplacement, prevIsLoading, replacementCardID]);

const handleValidateCodeEntered = (validateCode: string) => {
if (!virtualCard) {
Expand Down
5 changes: 4 additions & 1 deletion src/types/form/ReportPhysicalCardForm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import type Form from './Form';

type ReportPhysicalCardForm = Form;
type ReportPhysicalCardForm = Form & {
/** Whether the card was terminated without replacement */
cardTerminatedWithoutReplacement?: boolean;
};

// eslint-disable-next-line import/prefer-default-export
export type {ReportPhysicalCardForm};
15 changes: 15 additions & 0 deletions src/types/onyx/OriginalMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1372,6 +1372,20 @@ type OriginalMessageCardFrozen = {
lastModified?: string;
};

/**
* Model of CARDDEACTIVATED action
*/
type OriginalMessageCardDeactivated = {
/** HTML content of the system message */
html: string;

/** Whether the action was generated by NewDot */
isNewDot?: boolean;

/** When the action was last modified */
lastModified?: string;
};

/**
* Model of PERSONAL_CARD_CONNECTION_BROKEN action
*/
Expand Down Expand Up @@ -1553,6 +1567,7 @@ type OriginalMessageMap = {
[CONST.REPORT.ACTIONS.TYPE.CARD_ASSIGNED]: OriginalMessageCard;
[CONST.REPORT.ACTIONS.TYPE.CARD_FROZEN]: OriginalMessageCardFrozen;
[CONST.REPORT.ACTIONS.TYPE.CARD_UNFROZEN]: OriginalMessageCardFrozen;
[CONST.REPORT.ACTIONS.TYPE.CARD_DEACTIVATED]: OriginalMessageCardDeactivated;
[CONST.REPORT.ACTIONS.TYPE.PERSONAL_CARD_CONNECTION_BROKEN]: OriginalPersonalCard;
[CONST.REPORT.ACTIONS.TYPE.INTEGRATION_SYNC_FAILED]: OriginalMessageIntegrationSyncFailed;
[CONST.REPORT.ACTIONS.TYPE.DELETED_TRANSACTION]: OriginalMessageDeletedTransaction;
Expand Down
Loading