Skip to content
Closed
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
2 changes: 0 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ import HybridAppHandler from './HybridAppHandler';
import OnyxUpdateManager from './libs/actions/OnyxUpdateManager';
import './libs/HybridApp';
import {AttachmentModalContextProvider} from './pages/media/AttachmentModalScreen/AttachmentModalContext';
import ExpensifyCardContextProvider from './pages/settings/Wallet/ExpensifyCardPage/ExpensifyCardContextProvider';
import './setup/backgroundTask';
import './setup/fraudProtection';
import './setup/hybridApp';
Expand Down Expand Up @@ -122,7 +121,6 @@ function App() {
FullScreenBlockingViewContextProvider,
FullScreenLoaderContextProvider,
SidePanelContextProvider,
ExpensifyCardContextProvider,
]}
>
<CustomStatusBarAndBackground />
Expand Down
4 changes: 0 additions & 4 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,10 +259,6 @@ const ROUTES = {
route: 'settings/wallet/card/:cardID?',
getRoute: (cardID: string) => `settings/wallet/card/${cardID}` as const,
},
SETTINGS_WALLET_DOMAIN_CARD_CONFIRM_MAGIC_CODE: {
route: 'settings/wallet/card/:cardID/confirm-magic-code',
getRoute: (cardID: string) => `settings/wallet/card/${cardID}/confirm-magic-code` as const,
},
SETTINGS_DOMAIN_CARD_DETAIL: {
route: 'settings/card/:cardID?',
getRoute: (cardID: string) => `settings/card/${cardID}` as const,
Expand Down
1 change: 0 additions & 1 deletion src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ const SCREENS = {
ROOT: 'Settings_Wallet',
VERIFY_ACCOUNT: 'Settings_Wallet_VerifyAccount',
DOMAIN_CARD: 'Settings_Wallet_DomainCard',
DOMAIN_CARD_CONFIRM_MAGIC_CODE: 'Settings_Wallet_DomainCard_ConfirmMagicCode',
TRANSFER_BALANCE: 'Settings_Wallet_Transfer_Balance',
CHOOSE_TRANSFER_ACCOUNT: 'Settings_Wallet_Choose_Transfer_Account',
ENABLE_PAYMENTS: 'Settings_Wallet_EnablePayments',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ const ExpensifyCardModalStackNavigator = createModalStackNavigator({
});

const DomainCardModalStackNavigator = createModalStackNavigator({
[SCREENS.DOMAIN_CARD.DOMAIN_CARD_DETAIL]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ExpensifyCardPage/index').default,
[SCREENS.DOMAIN_CARD.DOMAIN_CARD_DETAIL]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ExpensifyCardPage').default,
[SCREENS.DOMAIN_CARD.DOMAIN_CARD_REPORT_FRAUD]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ReportVirtualCardFraudPage').default,
});

Expand Down Expand Up @@ -352,9 +352,7 @@ const SettingsModalStackNavigator = createModalStackNavigator<SettingsNavigatorP
[SCREENS.SETTINGS.SHARE_LOG]: () => require<ReactComponentModule>('../../../../pages/settings/AboutPage/ShareLogPage').default,
[SCREENS.SETTINGS.WALLET.CARDS_DIGITAL_DETAILS_UPDATE_ADDRESS]: () => require<ReactComponentModule>('../../../../pages/settings/Profile/PersonalDetails/PersonalAddressPage').default,
[SCREENS.SETTINGS.WALLET.VERIFY_ACCOUNT]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/VerifyAccountPage').default,
[SCREENS.SETTINGS.WALLET.DOMAIN_CARD]: () => require<ReactComponentModule>('../../../../pages/settings/Wallet/ExpensifyCardPage/index').default,
[SCREENS.SETTINGS.WALLET.DOMAIN_CARD_CONFIRM_MAGIC_CODE]: () =>
require<ReactComponentModule>('../../../../pages/settings/Wallet/ExpensifyCardPage/ExpensifyCardVerifyAccountPage').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_CONFIRM_MAGIC_CODE]: () =>
require<ReactComponentModule>('../../../../pages/settings/Wallet/ReportVirtualCardFraudVerifyAccountPage').default,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ const SETTINGS_TO_RHP: Partial<Record<keyof SettingsSplitNavigatorParamList, str
],
[SCREENS.SETTINGS.WALLET.ROOT]: [
SCREENS.SETTINGS.WALLET.DOMAIN_CARD,
SCREENS.SETTINGS.WALLET.DOMAIN_CARD_CONFIRM_MAGIC_CODE,
SCREENS.SETTINGS.WALLET.VERIFY_ACCOUNT,
SCREENS.SETTINGS.WALLET.TRANSFER_BALANCE,
SCREENS.SETTINGS.WALLET.CHOOSE_TRANSFER_ACCOUNT,
Expand Down
4 changes: 0 additions & 4 deletions src/libs/Navigation/linkingConfig/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,6 @@ const config: LinkingOptions<RootNavigatorParamList>['config'] = {
path: ROUTES.SETTINGS_WALLET_DOMAIN_CARD.route,
exact: true,
},
[SCREENS.SETTINGS.WALLET.DOMAIN_CARD_CONFIRM_MAGIC_CODE]: {
path: ROUTES.SETTINGS_WALLET_DOMAIN_CARD_CONFIRM_MAGIC_CODE.route,
exact: true,
},
[SCREENS.SETTINGS.WALLET.VERIFY_ACCOUNT]: {
path: ROUTES.SETTINGS_WALLET_VERIFY_ACCOUNT,
exact: true,
Expand Down
4 changes: 0 additions & 4 deletions src/libs/Navigation/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,6 @@ type SettingsNavigatorParamList = {
/** cardID of selected card */
cardID: string;
};
[SCREENS.SETTINGS.WALLET.DOMAIN_CARD_CONFIRM_MAGIC_CODE]: {
/** cardID of selected card */
cardID: string;
};
[SCREENS.SETTINGS.WALLET.REPORT_VIRTUAL_CARD_FRAUD]: {
/** cardID of selected card */
cardID: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,35 @@ import MenuItem from '@components/MenuItem';
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
import ValidateCodeActionModal from '@components/ValidateCodeActionModal';
import useBeforeRemove from '@hooks/useBeforeRemove';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useOnyx from '@hooks/useOnyx';
import useThemeStyles from '@hooks/useThemeStyles';
import {resetValidateActionCodeSent} from '@libs/actions/User';
import {requestValidateCodeAction, resetValidateActionCodeSent} from '@libs/actions/User';
import {formatCardExpiration, getDomainCards, maskCard, maskPin} from '@libs/CardUtils';
import {convertToDisplayString, getCurrencyKeyByCountryCode} from '@libs/CurrencyUtils';
import {getMicroSecondOnyxErrorWithTranslationKey} 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 {buildCannedSearchQuery} from '@libs/SearchQueryUtils';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
import RedDotCardSection from '@pages/settings/Wallet/RedDotCardSection';
import CardDetails from '@pages/settings/Wallet/WalletPage/CardDetails';
import {clearActivatedCardPin} from '@userActions/Card';
import {clearActivatedCardPin, revealVirtualCardDetails} from '@userActions/Card';
import {openOldDotLink} from '@userActions/Link';
import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type SCREENS from '@src/SCREENS';
import type {CurrencyList} from '@src/types/onyx';
import type {ExpensifyCardDetails} from '@src/types/onyx/Card';
import type {Errors} from '@src/types/onyx/OnyxCommon';
import {getEmptyObject} from '@src/types/utils/EmptyObject';
import useExpensifyCardContext from './useExpensifyCardContext';
import RedDotCardSection from './RedDotCardSection';
import CardDetails from './WalletPage/CardDetails';

type ExpensifyCardPageProps = PlatformStackScreenProps<SettingsNavigatorParamList, typeof SCREENS.SETTINGS.WALLET.DOMAIN_CARD>;

Expand Down Expand Up @@ -73,6 +76,8 @@ function ExpensifyCardPage({
const styles = useThemeStyles();
const {isOffline} = useNetwork();
const {translate} = useLocalize();
const [isValidateCodeActionModalVisible, setIsValidateCodeActionModalVisible] = useState(false);
const [currentCardID, setCurrentCardID] = useState<number>(-1);
const isTravelCard = cardList?.[cardID]?.nameValuePairs?.isTravelCard;
const shouldDisplayCardDomain = !isTravelCard && (!cardList?.[cardID]?.nameValuePairs?.issuedBy || !cardList?.[cardID]?.nameValuePairs?.isVirtual);
const domain = cardList?.[cardID]?.domainName ?? '';
Expand All @@ -88,6 +93,8 @@ function ExpensifyCardPage({
return [cardList?.[cardID]];
}, [shouldDisplayCardDomain, cardList, cardID, domain]);

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

useEffect(() => {
return () => {
if (!pin) {
Expand All @@ -111,15 +118,52 @@ function ExpensifyCardPage({
const cardToAdd = useMemo(() => {
return virtualCards?.at(0);
}, [virtualCards]);
const [cardsDetails, setCardsDetails] = useState<Record<number, ExpensifyCardDetails | null>>({});
const [isCardDetailsLoading, setIsCardDetailsLoading] = useState<Record<number, boolean>>({});
const [cardsDetailsErrors, setCardsDetailsErrors] = useState<Record<number, string>>({});
const [validateError, setValidateError] = useState<Errors>({});
const {isAccountLocked, showLockedAccountModal} = useContext(LockedAccountContext);

const {cardsDetails, setCardsDetails, isCardDetailsLoading, cardsDetailsErrors} = useExpensifyCardContext();
const openValidateCodeModal = (revealedCardID: number) => {
setCurrentCardID(revealedCardID);
setIsValidateCodeActionModalVisible(true);
};

// This resets card details when we exit the page.
useBeforeRemove(() => {
setCardsDetails((oldCardDetails) => ({...oldCardDetails, [cardID]: null}));
});

const {isAccountLocked, showLockedAccountModal} = useContext(LockedAccountContext);
const handleRevealDetails = (validateCode: string) => {
setIsCardDetailsLoading((prevState: Record<number, boolean>) => ({
...prevState,
[currentCardID]: true,
}));
// We can't store the response in Onyx for security reasons.
// That is why this action is handled manually and the response is stored in a local state
// Hence eslint disable here.
// eslint-disable-next-line rulesdir/no-thenable-actions-in-views
revealVirtualCardDetails(currentCardID, validateCode)
.then((value) => {
setCardsDetails((prevState: Record<number, ExpensifyCardDetails | null>) => ({...prevState, [currentCardID]: value}));
setCardsDetailsErrors((prevState) => ({
...prevState,
[currentCardID]: '',
}));
setIsValidateCodeActionModalVisible(false);
})
.catch((error: string) => {
// Displaying magic code errors is handled in the modal, no need to set it on the card
// TODO: remove setValidateError once backend deploys https://github.com/Expensify/Web-Expensify/pull/46007
if (error === 'validateCodeForm.error.incorrectMagicCode') {
setValidateError(() => getMicroSecondOnyxErrorWithTranslationKey('validateCodeForm.error.incorrectMagicCode'));
return;
}
setCardsDetailsErrors((prevState) => ({
...prevState,
[currentCardID]: error,
}));
setIsValidateCodeActionModalVisible(false);
})
.finally(() => {
setIsCardDetailsLoading((prevState: Record<number, boolean>) => ({...prevState, [currentCardID]: false}));
});
};

const hasDetectedDomainFraud = cardsToShow?.some((card) => card?.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.DOMAIN);
const hasDetectedIndividualFraud = cardsToShow?.some((card) => card?.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.INDIVIDUAL);
Expand All @@ -132,6 +176,7 @@ function ExpensifyCardPage({
const formattedAvailableSpendAmount = convertToDisplayString(cardsToShow?.at(0)?.availableSpend, currency);
const {limitNameKey, limitTitleKey} = getLimitTypeTranslationKeys(cardsToShow?.at(0)?.nameValuePairs?.limitType);

const primaryLogin = account?.primaryLogin ?? '';
const isSignedInAsDelegate = !!account?.delegatedAccess?.delegate || false;

if (isNotFound) {
Expand Down Expand Up @@ -216,7 +261,7 @@ function ExpensifyCardPage({
showLockedAccountModal();
return;
}
Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAIN_CARD_CONFIRM_MAGIC_CODE.getRoute(cardID));
openValidateCodeModal(card.cardID);
}}
isDisabled={isCardDetailsLoading[card.cardID] || isOffline}
isLoading={isCardDetailsLoading[card.cardID]}
Expand Down Expand Up @@ -268,7 +313,7 @@ function ExpensifyCardPage({
!isSignedInAsDelegate ? (
<Button
text={translate('cardPage.cardDetails.revealCvv')}
onPress={() => Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAIN_CARD_CONFIRM_MAGIC_CODE.getRoute(cardID))}
onPress={() => openValidateCodeModal(card.cardID)}
isDisabled={isCardDetailsLoading[card.cardID] || isOffline}
isLoading={isCardDetailsLoading[card.cardID]}
/>
Expand Down Expand Up @@ -363,6 +408,20 @@ function ExpensifyCardPage({
style={[styles.mh5, styles.mb5]}
/>
)}
<ValidateCodeActionModal
handleSubmitForm={handleRevealDetails}
clearError={() => setValidateError({})}
validateError={validateError}
validateCodeActionErrorField="revealExpensifyCardDetails"
sendValidateCode={() => requestValidateCodeAction()}
onClose={() => {
setIsValidateCodeActionModalVisible(false);
resetValidateActionCodeSent();
}}
isVisible={isValidateCodeActionModalVisible}
title={translate('cardPage.validateCardTitle')}
descriptionPrimary={translate('cardPage.enterMagicCode', {contactMethod: primaryLogin})}
/>
</ScreenWrapper>
);
}
Expand Down

This file was deleted.

Loading
Loading