From 83ff58284dabcad52cdf464ae0c3c1aa4e506b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Thu, 27 Nov 2025 15:21:38 +0100 Subject: [PATCH 1/4] Migrate ExpensifyCard/ConfirmationPage to Navigation-Based Validation --- src/ROUTES.ts | 6 ++ src/SCREENS.ts | 1 + .../ModalStackNavigators/index.tsx | 2 + .../RELATIONS/WORKSPACE_TO_RHP.ts | 1 + src/libs/Navigation/linkingConfig/config.ts | 3 + src/libs/Navigation/types.ts | 5 ++ .../issueNew/ConfirmationStep.tsx | 71 +++---------------- .../IssueNewCardConfirmMagicCodePage.tsx | 70 ++++++++++++++++++ 8 files changed, 99 insertions(+), 60 deletions(-) create mode 100644 src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 5c9b2faacd532..303319a4e594e 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -2210,6 +2210,12 @@ const ROUTES = { // eslint-disable-next-line no-restricted-syntax -- Legacy route generation getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`workspaces/${policyID}/expensify-card/issue-new`, backTo), }, + WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW_CONFIRM_MAGIC_CODE: { + route: 'workspaces/:policyID/expensify-card/issue-new/confirm-magic-code', + + // eslint-disable-next-line no-restricted-syntax -- Legacy route generation + getRoute: (policyID: string, backTo?: string) => getUrlWithBackToParam(`workspaces/${policyID}/expensify-card/issue-new/confirm-magic-code`, backTo), + }, WORKSPACE_EXPENSIFY_CARD_BANK_ACCOUNT: { route: 'workspaces/:policyID/expensify-card/choose-bank-account', getRoute: (policyID: string | undefined) => { diff --git a/src/SCREENS.ts b/src/SCREENS.ts index a713e3e51cef3..a88d4da05868c 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -583,6 +583,7 @@ const SCREENS = { EXPENSIFY_CARD_DETAILS: 'Workspace_ExpensifyCard_Details', EXPENSIFY_CARD_LIMIT: 'Workspace_ExpensifyCard_Limit', EXPENSIFY_CARD_ISSUE_NEW: 'Workspace_ExpensifyCard_New', + EXPENSIFY_CARD_ISSUE_NEW_CONFIRM_MAGIC_CODE: 'Workspace_ExpensifyCard_New_Confirm_Magic_Code', EXPENSIFY_CARD_NAME: 'Workspace_ExpensifyCard_Name', EXPENSIFY_CARD_SELECT_FEED: 'Workspace_ExpensifyCard_Select_Feed', EXPENSIFY_CARD_LIMIT_TYPE: 'Workspace_ExpensifyCard_LimitType', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 1b55a8080a8e5..43369b38a652b 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -702,6 +702,8 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/workspace/companyCards/WorkspaceCompanyCardEditCardNamePage').default, [SCREENS.WORKSPACE.COMPANY_CARD_EXPORT]: () => require('../../../../pages/workspace/companyCards/WorkspaceCompanyCardAccountSelectCardPage').default, [SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW]: () => require('../../../../pages/workspace/expensifyCard/issueNew/IssueNewCardPage').default, + [SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW_CONFIRM_MAGIC_CODE]: () => + require('../../../../pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage').default, [SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS]: () => require('../../../../pages/workspace/expensifyCard/WorkspaceCardSettingsPage').default, [SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_ACCOUNT]: () => require('../../../../pages/workspace/expensifyCard/WorkspaceSettlementAccountPage').default, [SCREENS.WORKSPACE.EXPENSIFY_CARD_SETTINGS_FREQUENCY]: () => require('../../../../pages/workspace/expensifyCard/WorkspaceSettlementFrequencyPage').default, diff --git a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts index 3bb9ceba4f8b5..c5db65fadd366 100755 --- a/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts +++ b/src/libs/Navigation/linkingConfig/RELATIONS/WORKSPACE_TO_RHP.ts @@ -245,6 +245,7 @@ const WORKSPACE_TO_RHP: Partial['config'] = { [SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW]: { path: ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.route, }, + [SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW_CONFIRM_MAGIC_CODE]: { + path: ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW_CONFIRM_MAGIC_CODE.route, + }, [SCREENS.WORKSPACE.EXPENSIFY_CARD_NAME]: { path: ROUTES.WORKSPACE_EXPENSIFY_CARD_NAME.route, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 962dcff253ce5..efeafecca4c66 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -1153,6 +1153,11 @@ type SettingsNavigatorParamList = { // 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; }; + [SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW_CONFIRM_MAGIC_CODE]: { + policyID: string; + // 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; + }; [SCREENS.WORKSPACE.EXPENSIFY_CARD_BANK_ACCOUNT]: { policyID: string; }; diff --git a/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx b/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx index 9126b0469dde1..53a1d23e05ac2 100644 --- a/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/ConfirmationStep.tsx @@ -1,37 +1,30 @@ -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React, {useEffect, useRef} from 'react'; import {View} from 'react-native'; import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton'; import InteractiveStepWrapper from '@components/InteractiveStepWrapper'; import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; import ScrollView from '@components/ScrollView'; import Text from '@components/Text'; -import ValidateCodeActionModal from '@components/ValidateCodeActionModal'; -import useDefaultFundID from '@hooks/useDefaultFundID'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; -import usePermissions from '@hooks/usePermissions'; import useThemeStyles from '@hooks/useThemeStyles'; -import {clearIssueNewCardError, clearIssueNewCardFlow, issueExpensifyCard, setIssueNewCardStepAndData} from '@libs/actions/Card'; -import {requestValidateCodeAction, resetValidateActionCodeSent} from '@libs/actions/User'; +import {setIssueNewCardStepAndData} from '@libs/actions/Card'; +import {resetValidateActionCodeSent} from '@libs/actions/User'; import {getTranslationKeyForLimitType} from '@libs/CardUtils'; import {convertToShortDisplayString} from '@libs/CurrencyUtils'; -import {getLatestErrorMessage, getLatestErrorMessageField} from '@libs/ErrorUtils'; +import {getLatestErrorMessage} from '@libs/ErrorUtils'; import {getUserNameByEmail} from '@libs/PersonalDetailsUtils'; import Navigation from '@navigation/Navigation'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {Route} from '@src/ROUTES'; import type {IssueNewCardStep} from '@src/types/onyx/Card'; type ConfirmationStepProps = { /** ID of the policy that the card will be issued under */ policyID: string | undefined; - /** Route to navigate to */ - backTo?: Route; - /** Array of step names */ stepNames: readonly string[]; @@ -39,19 +32,13 @@ type ConfirmationStepProps = { startStepIndex: number; }; -function ConfirmationStep({policyID, backTo, stepNames, startStepIndex}: ConfirmationStepProps) { +function ConfirmationStep({policyID, stepNames, startStepIndex}: ConfirmationStepProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const {isOffline} = useNetwork(); - const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: true}); const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true}); const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: true}); - const validateError = getLatestErrorMessageField(issueNewCard); - const [isValidateCodeActionModalVisible, setIsValidateCodeActionModalVisible] = useState(false); const data = issueNewCard?.data; - const isSuccessful = issueNewCard?.isSuccessful; - const defaultFundID = useDefaultFundID(policyID); - const {isBetaEnabled} = usePermissions(); const hasApprovalError = !!policy?.errorFields?.approvalMode; const isAddApprovalEnabled = policy?.approvalMode !== CONST.POLICY.APPROVAL_MODE.OPTIONAL && !hasApprovalError; const shouldDisableSubmitButton = !isAddApprovalEnabled && data?.limitType === CONST.EXPENSIFY_CARD.LIMIT_TYPES.SMART; @@ -63,18 +50,6 @@ function ConfirmationStep({policyID, backTo, stepNames, startStepIndex}: Confirm resetValidateActionCodeSent(); }, []); - useEffect(() => { - if (!isSuccessful) { - return; - } - setIsValidateCodeActionModalVisible(false); - }, [isSuccessful]); - - const submit = (validateCode: string) => { - // NOTE: For Expensify Card UK/EU, the backend will automatically detect the correct feedCountry to use - issueExpensifyCard(defaultFundID, policyID, isBetaEnabled(CONST.BETAS.EXPENSIFY_CARD_EU_UK) ? '' : CONST.COUNTRY.US, validateCode, data); - }; - const errorMessage = getLatestErrorMessage(issueNewCard) || (shouldDisableSubmitButton ? translate('workspace.card.issueNewCard.disabledApprovalForSmartLimitError') : ''); const editStep = (step: IssueNewCardStep) => { @@ -87,19 +62,6 @@ function ConfirmationStep({policyID, backTo, stepNames, startStepIndex}: Confirm const translationForLimitType = getTranslationKeyForLimitType(data?.limitType); - const onRedirect = useCallback(() => { - if (!isSuccessful) { - return; - } - if (backTo) { - Navigation.goBack(backTo); - } else { - Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID)); - } - - clearIssueNewCardFlow(policyID); - }, [backTo, policyID, isSuccessful]); - return ( setIsValidateCodeActionModalVisible(true)} + onSubmit={() => { + if (!policyID) { + return; + } + Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW_CONFIRM_MAGIC_CODE.getRoute(policyID, ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID))); + }} buttonText={translate('workspace.card.issueCard')} /> - {!!issueNewCard && ( - clearIssueNewCardError(policyID)} - onClose={() => setIsValidateCodeActionModalVisible(false)} - isVisible={isValidateCodeActionModalVisible} - title={translate('cardPage.validateCardTitle')} - descriptionPrimary={translate('cardPage.enterMagicCode', {contactMethod: account?.primaryLogin ?? ''})} - onModalHide={onRedirect} - disableAnimation - /> - )} ); } diff --git a/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx b/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx new file mode 100644 index 0000000000000..223d197e6ebf1 --- /dev/null +++ b/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx @@ -0,0 +1,70 @@ +import React, {useEffect, useState} from 'react'; +import ValidateCodeActionContent from '@components/ValidateCodeActionModal/ValidateCodeActionContent'; +import useDefaultFundID from '@hooks/useDefaultFundID'; +import useLocalize from '@hooks/useLocalize'; +import useOnyx from '@hooks/useOnyx'; +import usePermissions from '@hooks/usePermissions'; +import {clearIssueNewCardFlow, issueExpensifyCard} from '@libs/actions/Card'; +import {requestValidateCodeAction, resetValidateActionCodeSent} from '@libs/actions/User'; +import Navigation from '@libs/Navigation/Navigation'; +import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types'; +import type {SettingsNavigatorParamList} from '@libs/Navigation/types'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; + +type IssueNewCardConfirmMagicCodePageProps = PlatformStackScreenProps; + +function IssueNewCardConfirmMagicCodePage({route}: IssueNewCardConfirmMagicCodePageProps) { + const {translate} = useLocalize(); + const policyID = route.params.policyID; + const backTo = route.params.backTo; + const [validateError, setValidateError] = useState({}); + const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: false}); + const primaryLogin = account?.primaryLogin ?? ''; + const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true}); + const data = issueNewCard?.data; + const isSuccessful = issueNewCard?.isSuccessful; + const defaultFundID = useDefaultFundID(policyID); + const {isBetaEnabled} = usePermissions(); + + useEffect(() => { + if (!isSuccessful) { + return; + } + if (backTo) { + Navigation.goBack(backTo); + } else { + Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID)); + } + clearIssueNewCardFlow(policyID); + }, [backTo, isSuccessful, policyID]); + + const handleSubmit = (validateCode: string) => { + // NOTE: For Expensify Card UK/EU, the backend will automatically detect the correct feedCountry to use + issueExpensifyCard(defaultFundID, policyID, isBetaEnabled(CONST.BETAS.EXPENSIFY_CARD_EU_UK) ? '' : CONST.COUNTRY.US, validateCode, data); + }; + + return ( + requestValidateCodeAction()} + validateCodeActionErrorField={data?.cardType === CONST.EXPENSIFY_CARD.CARD_TYPE.PHYSICAL ? 'createExpensifyCard' : 'createAdminIssuedVirtualCard'} + handleSubmitForm={handleSubmit} + validateError={validateError} + clearError={() => setValidateError({})} + onClose={() => { + resetValidateActionCodeSent(); + Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.getRoute(policyID, backTo)); + }} + /> + ); +} + +IssueNewCardConfirmMagicCodePage.displayName = 'ExpensifyCardVerifyAccountPage'; + +export default IssueNewCardConfirmMagicCodePage; From cbf16881865c1677e4bacc505b33a889807684ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Thu, 27 Nov 2025 18:45:00 +0100 Subject: [PATCH 2/4] fix typecheck & backTo redirect --- .../issueNew/IssueNewCardConfirmMagicCodePage.tsx | 9 ++++++--- .../expensifyCard/issueNew/IssueNewCardPage.tsx | 4 ---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx b/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx index 223d197e6ebf1..5c035c2501aa0 100644 --- a/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx @@ -1,6 +1,7 @@ import React, {useEffect, useState} from 'react'; import ValidateCodeActionContent from '@components/ValidateCodeActionModal/ValidateCodeActionContent'; import useDefaultFundID from '@hooks/useDefaultFundID'; +import useInitial from '@hooks/useInitial'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePermissions from '@hooks/usePermissions'; @@ -29,18 +30,20 @@ function IssueNewCardConfirmMagicCodePage({route}: IssueNewCardConfirmMagicCodeP const isSuccessful = issueNewCard?.isSuccessful; const defaultFundID = useDefaultFundID(policyID); const {isBetaEnabled} = usePermissions(); + const firstAssigneeEmail = useInitial(issueNewCard?.data?.assigneeEmail); + const shouldUseBackToParam = !firstAssigneeEmail || firstAssigneeEmail === issueNewCard?.data?.assigneeEmail; useEffect(() => { if (!isSuccessful) { return; } - if (backTo) { + if (backTo && shouldUseBackToParam) { Navigation.goBack(backTo); } else { - Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID)); + Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD.getRoute(policyID), {forceReplace: true}); } clearIssueNewCardFlow(policyID); - }, [backTo, isSuccessful, policyID]); + }, [backTo, isSuccessful, policyID, shouldUseBackToParam]); const handleSubmit = (validateCode: string) => { // NOTE: For Expensify Card UK/EU, the backend will automatically detect the correct feedCountry to use diff --git a/src/pages/workspace/expensifyCard/issueNew/IssueNewCardPage.tsx b/src/pages/workspace/expensifyCard/issueNew/IssueNewCardPage.tsx index 80c9c5465e0fb..ae0c6187c51ee 100644 --- a/src/pages/workspace/expensifyCard/issueNew/IssueNewCardPage.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/IssueNewCardPage.tsx @@ -3,7 +3,6 @@ import React, {useEffect, useMemo} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import DelegateNoAccessWrapper from '@components/DelegateNoAccessWrapper'; import ScreenWrapper from '@components/ScreenWrapper'; -import useInitial from '@hooks/useInitial'; import useOnyx from '@hooks/useOnyx'; import {startIssueNewCardFlow} from '@libs/actions/Card'; import Navigation from '@libs/Navigation/Navigation'; @@ -50,8 +49,6 @@ function IssueNewCardPage({policy, route}: IssueNewCardPageProps) { const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true}); const {currentStep} = issueNewCard ?? {}; const backTo = route?.params?.backTo; - const firstAssigneeEmail = useInitial(issueNewCard?.data?.assigneeEmail); - const shouldUseBackToParam = !firstAssigneeEmail || firstAssigneeEmail === issueNewCard?.data?.assigneeEmail; const [isActingAsDelegate] = useOnyx(ONYXKEYS.ACCOUNT, {selector: isActingAsDelegateSelector, canBeMissing: true}); const stepNames = issueNewCard?.isChangeAssigneeDisabled ? CONST.EXPENSIFY_CARD.ASSIGNEE_EXCLUDED_STEP_NAMES : CONST.EXPENSIFY_CARD.STEP_NAMES; const startStepIndex = useMemo(() => getStartStepIndex(issueNewCard), [issueNewCard]); @@ -107,7 +104,6 @@ function IssueNewCardPage({policy, route}: IssueNewCardPageProps) { return ( From fc7ca93f52b6d345ca63973994a5b0916e5b6ae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Tue, 2 Dec 2025 11:42:12 +0100 Subject: [PATCH 3/4] add useCallbacks --- .../IssueNewCardConfirmMagicCodePage.tsx | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx b/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx index 5c035c2501aa0..b3b3107b72a0d 100644 --- a/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx @@ -1,4 +1,4 @@ -import React, {useEffect, useState} from 'react'; +import React, {useCallback, useEffect, useState} from 'react'; import ValidateCodeActionContent from '@components/ValidateCodeActionModal/ValidateCodeActionContent'; import useDefaultFundID from '@hooks/useDefaultFundID'; import useInitial from '@hooks/useInitial'; @@ -45,10 +45,18 @@ function IssueNewCardConfirmMagicCodePage({route}: IssueNewCardConfirmMagicCodeP clearIssueNewCardFlow(policyID); }, [backTo, isSuccessful, policyID, shouldUseBackToParam]); - const handleSubmit = (validateCode: string) => { - // NOTE: For Expensify Card UK/EU, the backend will automatically detect the correct feedCountry to use - issueExpensifyCard(defaultFundID, policyID, isBetaEnabled(CONST.BETAS.EXPENSIFY_CARD_EU_UK) ? '' : CONST.COUNTRY.US, validateCode, data); - }; + const handleSubmit = useCallback( + (validateCode: string) => { + // NOTE: For Expensify Card UK/EU, the backend will automatically detect the correct feedCountry to use + issueExpensifyCard(defaultFundID, policyID, isBetaEnabled(CONST.BETAS.EXPENSIFY_CARD_EU_UK) ? '' : CONST.COUNTRY.US, validateCode, data); + }, + [isBetaEnabled, data, defaultFundID, policyID], + ); + + const handleClose = useCallback(() => { + resetValidateActionCodeSent(); + Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.getRoute(policyID, backTo)); + }, [policyID, backTo]); return ( setValidateError({})} - onClose={() => { - resetValidateActionCodeSent(); - Navigation.navigate(ROUTES.WORKSPACE_EXPENSIFY_CARD_ISSUE_NEW.getRoute(policyID, backTo)); - }} + onClose={handleClose} /> ); } From a40dca02f128e1a1bb0093096145b868905562d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Musia=C5=82?= Date: Fri, 5 Dec 2025 12:06:10 +0100 Subject: [PATCH 4/4] get error from global card state --- .../issueNew/IssueNewCardConfirmMagicCodePage.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx b/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx index b3b3107b72a0d..9971896ff353f 100644 --- a/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx +++ b/src/pages/workspace/expensifyCard/issueNew/IssueNewCardConfirmMagicCodePage.tsx @@ -1,12 +1,13 @@ -import React, {useCallback, useEffect, useState} from 'react'; +import React, {useCallback, useEffect} from 'react'; import ValidateCodeActionContent from '@components/ValidateCodeActionModal/ValidateCodeActionContent'; import useDefaultFundID from '@hooks/useDefaultFundID'; import useInitial from '@hooks/useInitial'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePermissions from '@hooks/usePermissions'; -import {clearIssueNewCardFlow, issueExpensifyCard} from '@libs/actions/Card'; +import {clearIssueNewCardError, clearIssueNewCardFlow, issueExpensifyCard} from '@libs/actions/Card'; 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'; @@ -14,7 +15,6 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import type {Errors} from '@src/types/onyx/OnyxCommon'; type IssueNewCardConfirmMagicCodePageProps = PlatformStackScreenProps; @@ -22,10 +22,10 @@ function IssueNewCardConfirmMagicCodePage({route}: IssueNewCardConfirmMagicCodeP const {translate} = useLocalize(); const policyID = route.params.policyID; const backTo = route.params.backTo; - const [validateError, setValidateError] = useState({}); const [account] = useOnyx(ONYXKEYS.ACCOUNT, {canBeMissing: false}); const primaryLogin = account?.primaryLogin ?? ''; const [issueNewCard] = useOnyx(`${ONYXKEYS.COLLECTION.ISSUE_NEW_EXPENSIFY_CARD}${policyID}`, {canBeMissing: true}); + const validateError = getLatestErrorMessageField(issueNewCard); const data = issueNewCard?.data; const isSuccessful = issueNewCard?.isSuccessful; const defaultFundID = useDefaultFundID(policyID); @@ -67,7 +67,7 @@ function IssueNewCardConfirmMagicCodePage({route}: IssueNewCardConfirmMagicCodeP validateCodeActionErrorField={data?.cardType === CONST.EXPENSIFY_CARD.CARD_TYPE.PHYSICAL ? 'createExpensifyCard' : 'createAdminIssuedVirtualCard'} handleSubmitForm={handleSubmit} validateError={validateError} - clearError={() => setValidateError({})} + clearError={() => clearIssueNewCardError(policyID)} onClose={handleClose} /> );