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
5 changes: 5 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {UpperCaseCharacters} from 'type-fest/source/internal';
import type {SearchFilterKey, SearchQueryString, UserFriendlyKey} from './components/Search/types';
import type CONST from './CONST';
import type {IOUAction, IOUType} from './CONST';
import type {ReplacementReason} from './libs/actions/Card';
import type {IOURequestType} from './libs/actions/IOU';
import Log from './libs/Log';
import type {RootNavigatorParamList} from './libs/Navigation/types';
Expand Down Expand Up @@ -341,6 +342,10 @@ const ROUTES = {
route: 'settings/wallet/card/:cardID/report-card-lost-or-damaged',
getRoute: (cardID: string) => `settings/wallet/card/${cardID}/report-card-lost-or-damaged` as const,
},
SETTINGS_WALLET_REPORT_CARD_LOST_OR_DAMAGED_CONFIRM_MAGIC_CODE: {
route: 'settings/wallet/card/:cardID/report-card-lost-or-damaged/:reason/confirm-magic-code',
getRoute: (cardID: string, reason: ReplacementReason) => `settings/wallet/card/${cardID}/report-card-lost-or-damaged/${reason}/confirm-magic-code` as const,
},
SETTINGS_WALLET_CARD_ACTIVATE: {
route: 'settings/wallet/card/:cardID/activate',
getRoute: (cardID: string) => `settings/wallet/card/${cardID}/activate` 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 @@ -110,6 +110,7 @@ const SCREENS = {
ADD_BANK_ACCOUNT_SELECT_COUNTRY_VERIFY_ACCOUNT: 'Settings_Add_Bank_Account_Select_Country_Verify_Account',
CLOSE: 'Settings_Close',
REPORT_CARD_LOST_OR_DAMAGED: 'Settings_ReportCardLostOrDamaged',
REPORT_CARD_LOST_OR_DAMAGED_CONFIRM_MAGIC_CODE: 'Settings_ReportCardLostOrDamaged_ConfirmMagicCode',
TROUBLESHOOT: 'Settings_Troubleshoot',
CONSOLE: 'Settings_Console',
SHARE_LOG: 'Share_Log',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.REIMBURSEMENT_ACCOUNT_VERIFY_ACCOUNT]: () => require<ReactComponentModule>('../../../../pages/ReimbursementAccount/ReimbursementAccountVerifyAccountPage').default,
[SCREENS.REIMBURSEMENT_ACCOUNT_ENTER_SIGNER_INFO]: () => require<ReactComponentModule>('../../../../pages/ReimbursementAccount/EnterSignerInfo').default,
[SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ReportCardLostPage').default,
[SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED_CONFIRM_MAGIC_CODE]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ReportCardLostConfirmMagicCodePage').default,
[SCREENS.KEYBOARD_SHORTCUTS]: () => require<ReactComponentModule>('../../../../pages/KeyboardShortcutsPage').default,
[SCREENS.SETTINGS.EXIT_SURVEY.REASON]: () => require<ReactComponentModule>('../../../../pages/settings/ExitSurvey/ExitSurveyReasonPage').default,
[SCREENS.SETTINGS.EXIT_SURVEY.CONFIRM]: () => require<ReactComponentModule>('../../../../pages/settings/ExitSurvey/ExitSurveyConfirmPage').default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const SETTINGS_TO_RHP: Partial<Record<keyof SettingsSplitNavigatorParamList, str
SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD_CONFIRMATION,
SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS,
SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED,
SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED_CONFIRM_MAGIC_CODE,
SCREENS.SETTINGS.ADD_BANK_ACCOUNT_VERIFY_ACCOUNT,
],
[SCREENS.SETTINGS.SECURITY]: [
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 @@ -271,6 +271,10 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
path: ROUTES.SETTINGS_WALLET_REPORT_CARD_LOST_OR_DAMAGED.route,
exact: true,
},
[SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED_CONFIRM_MAGIC_CODE]: {
path: ROUTES.SETTINGS_WALLET_REPORT_CARD_LOST_OR_DAMAGED_CONFIRM_MAGIC_CODE.route,
exact: true,
},
[SCREENS.SETTINGS.WALLET.CARD_ACTIVATE]: {
path: ROUTES.SETTINGS_WALLET_CARD_ACTIVATE.route,
exact: true,
Expand Down
8 changes: 8 additions & 0 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
import type {TupleToUnion, ValueOf} from 'type-fest';
import type {UpperCaseCharacters} from 'type-fest/source/internal';
import type {SearchQueryString} from '@components/Search/types';
import type {ReplacementReason} from '@libs/actions/Card';
import type {IOURequestType} from '@libs/actions/IOU';
import type {SaveSearchParams} from '@libs/API/parameters';
import type {ReimbursementAccountStepToOpen} from '@libs/ReimbursementAccountUtils';
Expand Down Expand Up @@ -1084,6 +1085,13 @@ type SettingsNavigatorParamList = {
/** cardID of selected card */
cardID: string;
};
[SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED_CONFIRM_MAGIC_CODE]: {
/** cardID of selected card */
cardID: string;

/** Reason for replacing the card */
reason: ReplacementReason;
};
[SCREENS.KEYBOARD_SHORTCUTS]: {
// eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md
backTo: Routes;
Expand Down
6 changes: 1 addition & 5 deletions src/pages/settings/Wallet/ExpensifyCardPage/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,10 +119,6 @@ function ExpensifyCardPage({route}: ExpensifyCardPageProps) {
setIsNotFound(!currentCard);
}, [cardList, cardsToShow, currentCard]);

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

const virtualCards = useMemo(() => cardsToShow?.filter((card) => card?.nameValuePairs?.isVirtual && !card?.nameValuePairs?.isTravelCard), [cardsToShow]);
const travelCards = useMemo(() => cardsToShow?.filter((card) => card?.nameValuePairs?.isVirtual && card?.nameValuePairs?.isTravelCard), [cardsToShow]);
const physicalCards = useMemo(() => cardsToShow?.filter((card) => !card?.nameValuePairs?.isVirtual), [cardsToShow]);
Expand Down Expand Up @@ -247,7 +243,7 @@ function ExpensifyCardPage({route}: ExpensifyCardPageProps) {
Navigation.navigate(ROUTES.SETTINGS_WALLET_CARD_MISSING_DETAILS.getRoute(String(card.cardID)));
return;
}

resetValidateActionCodeSent();
if (route.name === SCREENS.DOMAIN_CARD.DOMAIN_CARD_DETAIL) {
Navigation.navigate(ROUTES.SETTINGS_DOMAIN_CARD_CONFIRM_MAGIC_CODE.getRoute(String(card.cardID)));
return;
Expand Down
105 changes: 105 additions & 0 deletions src/pages/settings/Wallet/ReportCardLostConfirmMagicCodePage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import {deepEqual} from 'fast-equals';
import React, {useCallback, useEffect, useState} from 'react';
import ScreenWrapper from '@components/ScreenWrapper';
import ValidateCodeActionContent from '@components/ValidateCodeActionModal/ValidateCodeActionContent';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import usePrevious from '@hooks/usePrevious';
import {clearCardListErrors, requestReplacementExpensifyCard} from '@libs/actions/Card';
import {setErrors} from '@libs/actions/FormActions';
import {requestValidateCodeAction, resetValidateActionCodeSent} from '@libs/actions/User';
import {getLatestErrorMessageField} from '@libs/ErrorUtils';
import Navigation from '@libs/Navigation/Navigation';
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
import type {SettingsNavigatorParamList} from '@libs/Navigation/types';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import SuccessReportCardLost from './SuccessReportCardLost';

type ReportCardLostConfirmMagicCodePageProps = PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED_CONFIRM_MAGIC_CODE>;

function ReportCardLostConfirmMagicCodePage({
route: {
params: {cardID = '', reason = 'damaged'},
Copy link
Contributor

Choose a reason for hiding this comment

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

Where do these default params come from?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

cardID = '' is widely used in all other pages, reason = 'damaged' there are 2 of them, just picked one

},
}: ReportCardLostConfirmMagicCodePageProps) {
const {translate} = useLocalize();
const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: false});
const [formData] = useOnyx(ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM, {canBeMissing: true});

const primaryLogin = account?.primaryLogin ?? '';
const [cardList] = useOnyx(ONYXKEYS.CARD_LIST, {canBeMissing: true});
const physicalCard = cardList?.[cardID];
const [newCardID, setNewCardID] = useState<string>('');
const previousCardList = usePrevious(cardList);
const validateError = getLatestErrorMessageField(physicalCard);

useEffect(() => {
const newID = Object.keys(cardList ?? {}).find((cardKey) => cardList?.[cardKey]?.cardID && !(cardKey in (previousCardList ?? {})));
if (!newID || physicalCard?.cardID) {
return;
}
setNewCardID(newID);
}, [cardList, physicalCard?.cardID, previousCardList]);

useEffect(() => {
if (formData?.isLoading) {
return;
}

const newErrors = physicalCard?.errors ?? {};
// Only update if errors have actually changed to prevent additional rerender
if (deepEqual(newErrors, formData?.errors ?? {})) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The reload didn't happen before without using deepEqual.
Why do you think this happened after migration and are forced to use deep compare?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far as I could reproduce it updating errors was causing the reload, so was hoping checking weather they actually changed will solve it. And I couldn't reproduce reload on my side after.

But looking @ your comment below it may be that I just get API response that code has beed issued fast enough that I cannot get into the state before.

return;
}
setErrors(ONYXKEYS.FORMS.REPORT_PHYSICAL_CARD_FORM, newErrors);
}, [formData?.isLoading, formData?.errors, physicalCard?.errors]);

const handleValidateCodeEntered = useCallback(
(validateCode: string) => {
if (!physicalCard) {
return;
}
requestReplacementExpensifyCard(physicalCard.cardID, reason, validateCode);
},
[physicalCard, reason],
);

if (newCardID) {
return (
<ScreenWrapper
includeSafeAreaPaddingBottom
testID={ReportCardLostConfirmMagicCodePage.displayName}
>
<SuccessReportCardLost cardID={newCardID} />
</ScreenWrapper>
);
}

return (
<ValidateCodeActionContent
validateCodeActionErrorField="replaceLostCard"
handleSubmitForm={handleValidateCodeEntered}
isLoading={formData?.isLoading}
title={translate('cardPage.validateCardTitle')}
descriptionPrimary={translate('cardPage.enterMagicCode', {contactMethod: primaryLogin})}
sendValidateCode={() => requestValidateCodeAction()}
validateError={validateError}
clearError={() => {
if (!physicalCard?.cardID) {
return;
}
clearCardListErrors(physicalCard?.cardID);
}}
onClose={() => {
resetValidateActionCodeSent();
Navigation.goBack(ROUTES.SETTINGS_WALLET_REPORT_CARD_LOST_OR_DAMAGED.getRoute(cardID));
}}
/>
);
}

ReportCardLostConfirmMagicCodePage.displayName = 'ReportCardLostConfirmMagicCodePage';

export default ReportCardLostConfirmMagicCodePage;
Loading
Loading