From 087f2fdc39c329567a24061fb52c37b78599db6d Mon Sep 17 00:00:00 2001 From: Getabalew Date: Fri, 30 Aug 2024 00:33:53 +0300 Subject: [PATCH 01/11] feat: validate new contact method action --- src/ONYXKEYS.ts | 3 + src/ROUTES.ts | 1 + src/SCREENS.ts | 1 + .../parameters/AddNewContactMethodParams.ts | 2 +- src/libs/API/types.ts | 1 + .../ModalStackNavigators/index.tsx | 1 + .../CENTRAL_PANE_TO_RHP_MAPPING.ts | 1 + src/libs/Navigation/linkingConfig/config.ts | 3 + src/libs/actions/User.ts | 87 ++++++++++++++++++- .../Profile/Contacts/NewContactMethodPage.tsx | 10 ++- .../ValidateCodeForm/BaseValidateCodeForm.tsx | 41 ++++++--- .../Contacts/ValidateContactActionPage.tsx | 66 ++++++++++++++ src/types/onyx/PendingContactAction.ts | 21 +++++ src/types/onyx/index.ts | 2 + 14 files changed, 222 insertions(+), 18 deletions(-) create mode 100644 src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx create mode 100644 src/types/onyx/PendingContactAction.ts diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 6a1fc8a629ed..a52e0d1ddeee 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -102,6 +102,8 @@ const ONYXKEYS = { /** Contains metadata (partner, login, validation date) for all of the user's logins */ LOGIN_LIST: 'loginList', + PENDING_CONTACT_ACTION: 'pendingContactAction', + /** Information about the current session (authToken, accountID, email, loading, error) */ SESSION: 'session', STASHED_SESSION: 'stashedSession', @@ -811,6 +813,7 @@ type OnyxValuesMapping = { [ONYXKEYS.USER]: OnyxTypes.User; [ONYXKEYS.USER_LOCATION]: OnyxTypes.UserLocation; [ONYXKEYS.LOGIN_LIST]: OnyxTypes.LoginList; + [ONYXKEYS.PENDING_CONTACT_ACTION]: OnyxTypes.PendingContactAction; [ONYXKEYS.SESSION]: OnyxTypes.Session; [ONYXKEYS.USER_METADATA]: OnyxTypes.UserMetadata; [ONYXKEYS.STASHED_SESSION]: OnyxTypes.Session; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 97a86d272530..e6f583e11f45 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -195,6 +195,7 @@ const ROUTES = { route: 'settings/profile/contact-methods/:contactMethod/details', getRoute: (contactMethod: string, backTo?: string) => getUrlWithBackToParam(`settings/profile/contact-methods/${encodeURIComponent(contactMethod)}/details`, backTo), }, + SETINGS_CONTACT_METHOD_VALIDATE_ACTION: 'settings/profile/contact-methods/validate-action', SETTINGS_NEW_CONTACT_METHOD: { route: 'settings/profile/contact-methods/new', getRoute: (backTo?: string) => getUrlWithBackToParam('settings/profile/contact-methods/new', backTo), diff --git a/src/SCREENS.ts b/src/SCREENS.ts index 9634cc1b02ac..dfe422e55f2e 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -72,6 +72,7 @@ const SCREENS = { DISPLAY_NAME: 'Settings_Display_Name', CONTACT_METHODS: 'Settings_ContactMethods', CONTACT_METHOD_DETAILS: 'Settings_ContactMethodDetails', + CONTACT_METHOD_ACTION: 'Settings_VerifyContactMethodAction', NEW_CONTACT_METHOD: 'Settings_NewContactMethod', STATUS_CLEAR_AFTER: 'Settings_Status_Clear_After', STATUS_CLEAR_AFTER_DATE: 'Settings_Status_Clear_After_Date', diff --git a/src/libs/API/parameters/AddNewContactMethodParams.ts b/src/libs/API/parameters/AddNewContactMethodParams.ts index f5cd7824c191..d362ca2db977 100644 --- a/src/libs/API/parameters/AddNewContactMethodParams.ts +++ b/src/libs/API/parameters/AddNewContactMethodParams.ts @@ -1,3 +1,3 @@ -type AddNewContactMethodParams = {partnerUserID: string}; +type AddNewContactMethodParams = {partnerUserID: string; validateCode: string}; export default AddNewContactMethodParams; diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 457eeb7c9b03..1022f0fd88c3 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -90,6 +90,7 @@ const WRITE_COMMANDS = { CONNECT_BANK_ACCOUNT_WITH_PLAID: 'ConnectBankAccountWithPlaid', ADD_PERSONAL_BANK_ACCOUNT: 'AddPersonalBankAccount', RESTART_BANK_ACCOUNT_SETUP: 'RestartBankAccountSetup', + RESEND_VALIDATE_CODE: 'ResendValidateCode', OPT_IN_TO_PUSH_NOTIFICATIONS: 'OptInToPushNotifications', OPT_OUT_OF_PUSH_NOTIFICATIONS: 'OptOutOfPushNotifications', READ_NEWEST_ACTION: 'ReadNewestAction', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 187e71df4d98..559d7f147d13 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -191,6 +191,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Profile/PersonalDetails/StateSelectionPage').default, [SCREENS.SETTINGS.PROFILE.CONTACT_METHODS]: () => require('../../../../pages/settings/Profile/Contacts/ContactMethodsPage').default, [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS]: () => require('../../../../pages/settings/Profile/Contacts/ContactMethodDetailsPage').default, + [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_ACTION]: () => require('../../../../pages/settings/Profile/Contacts/ValidateContactActionPage').default, [SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD]: () => require('../../../../pages/settings/Profile/Contacts/NewContactMethodPage').default, [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE]: () => require('../../../../pages/settings/Preferences/PriorityModePage').default, [SCREENS.WORKSPACE.ACCOUNTING.ROOT]: () => require('../../../../pages/workspace/accounting/PolicyAccountingPage').default, diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts index 8a4a53e0f705..6af8aafdf9d8 100755 --- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -6,6 +6,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, SCREENS.SETTINGS.PROFILE.CONTACT_METHODS, SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS, + SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_ACTION, SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD, SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER, SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 6ee3b14b64ed..1eeb524bc849 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -251,6 +251,9 @@ const config: LinkingOptions['config'] = { [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS]: { path: ROUTES.SETTINGS_CONTACT_METHOD_DETAILS.route, }, + [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_ACTION]: { + path: ROUTES.SETINGS_CONTACT_METHOD_VALIDATE_ACTION, + }, [SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD]: { path: ROUTES.SETTINGS_NEW_CONTACT_METHOD.route, exact: true, diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index 773cc0c9373c..2a43abaf21ed 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -288,11 +288,64 @@ function resetContactMethodValidateCodeSentState(contactMethod: string) { }, }); } +/** + * Validates the action to add secondary contact method + */ +function saveNewContactMethodAndValidateAction(contactMethod: string) { + const optimisticData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PENDING_CONTACT_ACTION, + value: { + contactMethod: contactMethod, + errorFields: { + actionVerified: null, + }, + pendingFields: { + actionVerified: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + }, + } + ]; + + const successData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PENDING_CONTACT_ACTION, + value: { + validateCodeSent: true, + errorFields: { + actionVerified: null, + }, + pendingFields: { + actionVerified: null, + }, + }, + } + ]; + + const failureData: OnyxUpdate[] = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PENDING_CONTACT_ACTION, + value: { + errorFields: { + actionVerified: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('contacts.genericFailureMessages.requestContactMethodValidateCode'), + }, + pendingFields: { + actionVerified: null, + }, + }, + } + ]; + + API.write(WRITE_COMMANDS.RESEND_VALIDATE_CODE, {}, {optimisticData, successData, failureData}); +} /** * Adds a secondary login to a user's account */ -function addNewContactMethodAndNavigate(contactMethod: string, backTo?: string) { +function addNewContactMethodAndNavigate(contactMethod: string, validateCode = '') { const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -310,6 +363,11 @@ function addNewContactMethodAndNavigate(contactMethod: string, backTo?: string) }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ACCOUNT, + value: {isLoading: true}, + }, ]; const successData: OnyxUpdate[] = [ { @@ -323,6 +381,23 @@ function addNewContactMethodAndNavigate(contactMethod: string, backTo?: string) }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PENDING_CONTACT_ACTION, + value: { + errorFields: { + actionVerified: null, + }, + pendingFields: { + actionVerified: null, + }, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ACCOUNT, + value: {isLoading: false}, + }, ]; const failureData: OnyxUpdate[] = [ { @@ -339,12 +414,17 @@ function addNewContactMethodAndNavigate(contactMethod: string, backTo?: string) }, }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.ACCOUNT, + value: {isLoading: false}, + }, ]; - const parameters: AddNewContactMethodParams = {partnerUserID: contactMethod}; + const parameters: AddNewContactMethodParams = {partnerUserID: contactMethod, validateCode}; API.write(WRITE_COMMANDS.ADD_NEW_CONTACT_METHOD, parameters, {optimisticData, successData, failureData}); - Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo)); + // Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS.route); } /** @@ -1144,4 +1224,5 @@ export { updateDraftCustomStatus, clearDraftCustomStatus, requestRefund, + saveNewContactMethodAndValidateAction, }; diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx index 3380766d0ecf..7413c2ad64d0 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx @@ -24,17 +24,18 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/NewContactMethodForm'; -import type {LoginList} from '@src/types/onyx'; +import type {Account, LoginList} from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; type NewContactMethodPageOnyxProps = { /** Login list for the user that is signed in */ loginList: OnyxEntry; + account: OnyxEntry; }; type NewContactMethodPageProps = NewContactMethodPageOnyxProps & StackScreenProps; -function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { +function NewContactMethodPage({loginList, route, account}: NewContactMethodPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const loginInputRef = useRef(null); @@ -47,7 +48,8 @@ function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { const validateIfnumber = LoginUtils.validateNumber(phoneLogin); const submitDetail = (validateIfnumber || values.phoneOrEmail).trim().toLowerCase(); - User.addNewContactMethodAndNavigate(submitDetail, route.params?.backTo); + User.saveNewContactMethodAndValidateAction(submitDetail); + Navigation.navigate(ROUTES.SETINGS_CONTACT_METHOD_VALIDATE_ACTION); }, [route.params?.backTo], ); @@ -105,7 +107,6 @@ function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { onSubmit={addNewContactMethod} submitButtonText={translate('common.add')} style={[styles.flexGrow1, styles.mh5]} - enabledWhenOffline > {translate('common.pleaseEnterEmailOrPhoneNumber')} @@ -131,4 +132,5 @@ NewContactMethodPage.displayName = 'NewContactMethodPage'; export default withOnyx({ loginList: {key: ONYXKEYS.LOGIN_LIST}, + account: {key: ONYXKEYS.ACCOUNT}, })(NewContactMethodPage); diff --git a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx index e0b7a23d5df3..ba9ff4d53235 100644 --- a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx +++ b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -23,7 +23,7 @@ import * as User from '@userActions/User'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; -import type {Account, LoginList} from '@src/types/onyx'; +import type {Account, LoginList, PendingContactAction} from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; type ValidateCodeFormHandle = { @@ -45,21 +45,36 @@ type ValidateCodeFormProps = { contactMethod: string; /** If the magic code has been resent previously */ - hasMagicCodeBeenSent: boolean; + hasMagicCodeBeenSent?: boolean; /** Login list for the user that is signed in */ - loginList: LoginList; + loginList?: LoginList; /** Specifies autocomplete hints for the system, so it can provide autofill */ autoComplete?: AutoCompleteVariant; /** Forwarded inner ref */ innerRef?: ForwardedRef; + + /**Whether we are validating the action taken to add the magic code */ + isValidatingAction?: boolean; + + /**The contact that's going to be added after the validation */ + pendingContact?: PendingContactAction; }; type BaseValidateCodeFormProps = BaseValidateCodeFormOnyxProps & ValidateCodeFormProps; -function BaseValidateCodeForm({account = {}, contactMethod, hasMagicCodeBeenSent, loginList, autoComplete = 'one-time-code', innerRef = () => {}}: BaseValidateCodeFormProps) { +function BaseValidateCodeForm({ + account = {}, + contactMethod, + hasMagicCodeBeenSent, + loginList, + autoComplete = 'one-time-code', + innerRef = () => {}, + isValidatingAction = false, + pendingContact, +}: BaseValidateCodeFormProps) { const {translate} = useLocalize(); const {isOffline} = useNetwork(); const theme = useTheme(); @@ -67,7 +82,7 @@ function BaseValidateCodeForm({account = {}, contactMethod, hasMagicCodeBeenSent const StyleUtils = useStyleUtils(); const [formError, setFormError] = useState({}); const [validateCode, setValidateCode] = useState(''); - const loginData = loginList[contactMethod]; + const loginData = loginList?.[pendingContact?.contactMethod ?? contactMethod]; const inputValidateCodeRef = useRef(null); const validateLoginError = ErrorUtils.getEarliestErrorField(loginData, 'validateLogin'); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- nullish coalescing doesn't achieve the same result in this case @@ -166,6 +181,12 @@ function BaseValidateCodeForm({account = {}, contactMethod, hasMagicCodeBeenSent } setFormError({}); + + if (!!pendingContact?.contactMethod && isValidatingAction) { + User.addNewContactMethodAndNavigate(pendingContact?.contactMethod, validateCode); + return; + } + User.validateSecondaryLogin(loginList, contactMethod, validateCode); }, [loginList, validateCode, contactMethod]); @@ -183,8 +204,8 @@ function BaseValidateCodeForm({account = {}, contactMethod, hasMagicCodeBeenSent autoFocus={false} /> User.clearContactMethodErrors(contactMethod, 'validateCodeSent')} > @@ -201,18 +222,18 @@ function BaseValidateCodeForm({account = {}, contactMethod, hasMagicCodeBeenSent > {translate('validateCodeForm.magicCodeNotReceived')} - {hasMagicCodeBeenSent && ( + {(hasMagicCodeBeenSent || !!pendingContact?.validateCodeSent) && ( )} User.clearContactMethodErrors(contactMethod, 'validateLogin')} diff --git a/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx b/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx new file mode 100644 index 000000000000..63b4527e682b --- /dev/null +++ b/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx @@ -0,0 +1,66 @@ +import React, {useEffect, useMemo, useRef} from 'react'; +import {View} from 'react-native'; +import {useOnyx} from 'react-native-onyx'; +import DotIndicatorMessage from '@components/DotIndicatorMessage'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import useLocalize from '@hooks/useLocalize'; +import usePrevious from '@hooks/usePrevious'; +import useThemeStyles from '@hooks/useThemeStyles'; +import Navigation from '@libs/Navigation/Navigation'; +import {ValidateCodeFormHandle} from '@pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import ValidateCodeForm from './ValidateCodeForm'; + +function ValidateContactActionPage() { + const [account] = useOnyx(ONYXKEYS.ACCOUNT); + const themeStyles = useThemeStyles(); + const {translate} = useLocalize(); + const validateCodeFormRef = useRef(null); + const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); + + const [pendingContactAction] = useOnyx(ONYXKEYS.PENDING_CONTACT_ACTION); + const loginData = loginList?.[pendingContactAction?.contactMethod ?? ''] + + useEffect(() => { + if(!loginData || !!loginData.pendingFields?.addedLogin) { + return; + } + + // Navigate to methods page on successful magic code verification + Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS.route); + }, [loginData?.pendingFields, loginList]); + + return ( + + Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.route)} + /> + + + + + + ); +} + +ValidateContactActionPage.displayName = 'ValidateContactActionPage'; + +export default ValidateContactActionPage; diff --git a/src/types/onyx/PendingContactAction.ts b/src/types/onyx/PendingContactAction.ts new file mode 100644 index 000000000000..300938fcb495 --- /dev/null +++ b/src/types/onyx/PendingContactAction.ts @@ -0,0 +1,21 @@ +import type * as OnyxCommon from './OnyxCommon'; + +type ContactAction = OnyxCommon.OnyxValueWithOfflineFeedback< + { + /** Phone/Email associated with user */ + contactMethod?: string; + + /** Whether the user validation code was sent */ + validateCodeSent?: boolean; + + /** Field-specific server side errors keyed by microtime */ + errorFields?: OnyxCommon.ErrorFields; + }, + 'actionVerified' +>; + +/** Record of user login data, indexed by partnerUserID */ +type PendingContactAction = ContactAction; + +export default ContactAction; +export type {PendingContactAction}; diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts index 54ee7fe25892..d5e2a7fa61f5 100644 --- a/src/types/onyx/index.ts +++ b/src/types/onyx/index.ts @@ -1,3 +1,4 @@ +import type {PendingContactAction} from '@src/types/onyx/PendingContactAction'; import type Account from './Account'; import type AccountData from './AccountData'; import type {ApprovalWorkflowOnyx} from './ApprovalWorkflow'; @@ -130,6 +131,7 @@ export type { Locale, Login, LoginList, + PendingContactAction, MapboxAccessToken, Modal, Network, From 74ec327cea2ba495d59d37e05108fcdc4d1776e1 Mon Sep 17 00:00:00 2001 From: Getabalew Date: Fri, 30 Aug 2024 12:38:14 +0300 Subject: [PATCH 02/11] refactor: remove unnecessary code --- src/libs/actions/User.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index 2a43abaf21ed..d3a3c90bec06 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -424,7 +424,6 @@ function addNewContactMethodAndNavigate(contactMethod: string, validateCode = '' const parameters: AddNewContactMethodParams = {partnerUserID: contactMethod, validateCode}; API.write(WRITE_COMMANDS.ADD_NEW_CONTACT_METHOD, parameters, {optimisticData, successData, failureData}); - // Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS.route); } /** From 650f47f5b62e1c12563fabef71e836545c283a78 Mon Sep 17 00:00:00 2001 From: Getabalew Date: Fri, 30 Aug 2024 16:54:45 +0300 Subject: [PATCH 03/11] refactor: improve action state handling and naming --- src/ONYXKEYS.ts | 1 + src/SCREENS.ts | 2 +- .../ModalStackNavigators/index.tsx | 2 +- .../CENTRAL_PANE_TO_RHP_MAPPING.ts | 2 +- src/libs/Navigation/linkingConfig/config.ts | 2 +- src/libs/actions/User.ts | 32 ++++++++++++++++--- .../Profile/Contacts/NewContactMethodPage.tsx | 18 ++++++++--- .../ValidateCodeForm/BaseValidateCodeForm.tsx | 6 ++-- .../Contacts/ValidateContactActionPage.tsx | 2 +- 9 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index a52e0d1ddeee..3c585a939283 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -102,6 +102,7 @@ const ONYXKEYS = { /** Contains metadata (partner, login, validation date) for all of the user's logins */ LOGIN_LIST: 'loginList', + /** Object containing contact method that's going to be added */ PENDING_CONTACT_ACTION: 'pendingContactAction', /** Information about the current session (authToken, accountID, email, loading, error) */ diff --git a/src/SCREENS.ts b/src/SCREENS.ts index dfe422e55f2e..dd19fc04adbf 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -72,7 +72,7 @@ const SCREENS = { DISPLAY_NAME: 'Settings_Display_Name', CONTACT_METHODS: 'Settings_ContactMethods', CONTACT_METHOD_DETAILS: 'Settings_ContactMethodDetails', - CONTACT_METHOD_ACTION: 'Settings_VerifyContactMethodAction', + CONTACT_METHOD_VALIDATE_ACTION: 'Settings_ValidateContactMethodAction', NEW_CONTACT_METHOD: 'Settings_NewContactMethod', STATUS_CLEAR_AFTER: 'Settings_Status_Clear_After', STATUS_CLEAR_AFTER_DATE: 'Settings_Status_Clear_After_Date', diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx index 559d7f147d13..d6e10af2e55e 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx @@ -191,7 +191,7 @@ const SettingsModalStackNavigator = createModalStackNavigator require('../../../../pages/settings/Profile/PersonalDetails/StateSelectionPage').default, [SCREENS.SETTINGS.PROFILE.CONTACT_METHODS]: () => require('../../../../pages/settings/Profile/Contacts/ContactMethodsPage').default, [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS]: () => require('../../../../pages/settings/Profile/Contacts/ContactMethodDetailsPage').default, - [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_ACTION]: () => require('../../../../pages/settings/Profile/Contacts/ValidateContactActionPage').default, + [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_VALIDATE_ACTION]: () => require('../../../../pages/settings/Profile/Contacts/ValidateContactActionPage').default, [SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD]: () => require('../../../../pages/settings/Profile/Contacts/NewContactMethodPage').default, [SCREENS.SETTINGS.PREFERENCES.PRIORITY_MODE]: () => require('../../../../pages/settings/Preferences/PriorityModePage').default, [SCREENS.WORKSPACE.ACCOUNTING.ROOT]: () => require('../../../../pages/workspace/accounting/PolicyAccountingPage').default, diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts index 6af8aafdf9d8..3896d1744121 100755 --- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts +++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts @@ -6,7 +6,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> = SCREENS.SETTINGS.PROFILE.DISPLAY_NAME, SCREENS.SETTINGS.PROFILE.CONTACT_METHODS, SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS, - SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_ACTION, + SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_VALIDATE_ACTION, SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD, SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER, SCREENS.SETTINGS.PROFILE.STATUS_CLEAR_AFTER_DATE, diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts index 1eeb524bc849..71d2c5d9a84f 100644 --- a/src/libs/Navigation/linkingConfig/config.ts +++ b/src/libs/Navigation/linkingConfig/config.ts @@ -251,7 +251,7 @@ const config: LinkingOptions['config'] = { [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_DETAILS]: { path: ROUTES.SETTINGS_CONTACT_METHOD_DETAILS.route, }, - [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_ACTION]: { + [SCREENS.SETTINGS.PROFILE.CONTACT_METHOD_VALIDATE_ACTION]: { path: ROUTES.SETINGS_CONTACT_METHOD_VALIDATE_ACTION, }, [SCREENS.SETTINGS.PROFILE.NEW_CONTACT_METHOD]: { diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index d3a3c90bec06..4d83c8ea48b1 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -291,7 +291,7 @@ function resetContactMethodValidateCodeSentState(contactMethod: string) { /** * Validates the action to add secondary contact method */ -function saveNewContactMethodAndValidateAction(contactMethod: string) { +function saveNewContactMethodAndRequestValidationCode(contactMethod: string) { const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -305,6 +305,11 @@ function saveNewContactMethodAndValidateAction(contactMethod: string) { actionVerified: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM, + value: {isLoading: true} } ]; @@ -320,7 +325,12 @@ function saveNewContactMethodAndValidateAction(contactMethod: string) { pendingFields: { actionVerified: null, }, - }, + } + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM, + value: {isLoading: false} } ]; @@ -329,6 +339,7 @@ function saveNewContactMethodAndValidateAction(contactMethod: string) { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PENDING_CONTACT_ACTION, value: { + validateCodeSent: null, errorFields: { actionVerified: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('contacts.genericFailureMessages.requestContactMethodValidateCode'), }, @@ -336,6 +347,16 @@ function saveNewContactMethodAndValidateAction(contactMethod: string) { actionVerified: null, }, }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM, + value: { + isLoading: false, + errorFields: { + ctionVerified: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('contacts.genericFailureMessages.requestContactMethodValidateCode'), + } + } } ]; @@ -345,7 +366,7 @@ function saveNewContactMethodAndValidateAction(contactMethod: string) { /** * Adds a secondary login to a user's account */ -function addNewContactMethodAndNavigate(contactMethod: string, validateCode = '') { +function addNewContactMethod(contactMethod: string, validateCode = '') { const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, @@ -385,6 +406,7 @@ function addNewContactMethodAndNavigate(contactMethod: string, validateCode = '' onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PENDING_CONTACT_ACTION, value: { + validateCodeSent: null, errorFields: { actionVerified: null, }, @@ -1202,7 +1224,7 @@ export { updateNewsletterSubscription, deleteContactMethod, clearContactMethodErrors, - addNewContactMethodAndNavigate, + addNewContactMethod, validateLogin, validateSecondaryLogin, isBlockedFromConcierge, @@ -1223,5 +1245,5 @@ export { updateDraftCustomStatus, clearDraftCustomStatus, requestRefund, - saveNewContactMethodAndValidateAction, + saveNewContactMethodAndRequestValidationCode, }; diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx index 7413c2ad64d0..cfb3d7a990aa 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx @@ -1,9 +1,9 @@ import type {StackScreenProps} from '@react-navigation/stack'; import {Str} from 'expensify-common'; -import React, {useCallback, useRef} from 'react'; +import React, {useCallback, useEffect, useRef} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx, withOnyx} from 'react-native-onyx'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormOnyxValues} from '@components/Form/types'; @@ -30,6 +30,8 @@ import type {Errors} from '@src/types/onyx/OnyxCommon'; type NewContactMethodPageOnyxProps = { /** Login list for the user that is signed in */ loginList: OnyxEntry; + + /** The details about the account that the user signed in with */ account: OnyxEntry; }; @@ -39,6 +41,7 @@ function NewContactMethodPage({loginList, route, account}: NewContactMethodPageP const styles = useThemeStyles(); const {translate} = useLocalize(); const loginInputRef = useRef(null); + const [pendingContactAction] = useOnyx(ONYXKEYS.PENDING_CONTACT_ACTION); const navigateBackTo = route?.params?.backTo ?? ROUTES.SETTINGS_PROFILE; @@ -48,12 +51,19 @@ function NewContactMethodPage({loginList, route, account}: NewContactMethodPageP const validateIfnumber = LoginUtils.validateNumber(phoneLogin); const submitDetail = (validateIfnumber || values.phoneOrEmail).trim().toLowerCase(); - User.saveNewContactMethodAndValidateAction(submitDetail); - Navigation.navigate(ROUTES.SETINGS_CONTACT_METHOD_VALIDATE_ACTION); + User.saveNewContactMethodAndRequestValidationCode(submitDetail); }, [route.params?.backTo], ); + useEffect(() => { + if (!pendingContactAction?.validateCodeSent) { + return; + } + + Navigation.navigate(ROUTES.SETINGS_CONTACT_METHOD_VALIDATE_ACTION); + }, [pendingContactAction]); + const validate = React.useCallback( (values: FormOnyxValues): Errors => { const phoneLogin = LoginUtils.getPhoneLogin(values.phoneOrEmail); diff --git a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx index ba9ff4d53235..dc8f093ec775 100644 --- a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx +++ b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -56,10 +56,10 @@ type ValidateCodeFormProps = { /** Forwarded inner ref */ innerRef?: ForwardedRef; - /**Whether we are validating the action taken to add the magic code */ + /** Whether we are validating the action taken to add the magic code */ isValidatingAction?: boolean; - /**The contact that's going to be added after the validation */ + /** The contact that's going to be added after successful validation */ pendingContact?: PendingContactAction; }; @@ -183,7 +183,7 @@ function BaseValidateCodeForm({ setFormError({}); if (!!pendingContact?.contactMethod && isValidatingAction) { - User.addNewContactMethodAndNavigate(pendingContact?.contactMethod, validateCode); + User.addNewContactMethod(pendingContact?.contactMethod, validateCode); return; } diff --git a/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx b/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx index 63b4527e682b..99f92d0626cb 100644 --- a/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx +++ b/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx @@ -21,7 +21,7 @@ function ValidateContactActionPage() { const [loginList] = useOnyx(ONYXKEYS.LOGIN_LIST); const [pendingContactAction] = useOnyx(ONYXKEYS.PENDING_CONTACT_ACTION); - const loginData = loginList?.[pendingContactAction?.contactMethod ?? ''] + const loginData = loginList?.[pendingContactAction?.contactMethod ?? '']; useEffect(() => { if(!loginData || !!loginData.pendingFields?.addedLogin) { From c11acac999e281fc270cdf51ab1b8cc393b6002b Mon Sep 17 00:00:00 2001 From: Getabalew Date: Fri, 30 Aug 2024 17:13:15 +0300 Subject: [PATCH 04/11] fix: lint and tscheck --- src/libs/API/types.ts | 1 + src/libs/actions/User.ts | 20 ++++++++-------- .../Profile/Contacts/NewContactMethodPage.tsx | 23 +++++++------------ .../ValidateCodeForm/BaseValidateCodeForm.tsx | 4 ++-- .../Contacts/ValidateContactActionPage.tsx | 9 ++++---- src/types/onyx/PendingContactAction.ts | 1 + src/types/onyx/index.ts | 2 +- 7 files changed, 27 insertions(+), 33 deletions(-) diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 1022f0fd88c3..b41376d54156 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -428,6 +428,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.ADD_PERSONAL_BANK_ACCOUNT]: Parameters.AddPersonalBankAccountParams; [WRITE_COMMANDS.RESTART_BANK_ACCOUNT_SETUP]: Parameters.RestartBankAccountSetupParams; [WRITE_COMMANDS.OPT_IN_TO_PUSH_NOTIFICATIONS]: Parameters.OptInOutToPushNotificationsParams; + [WRITE_COMMANDS.RESEND_VALIDATE_CODE]: null, [WRITE_COMMANDS.OPT_OUT_OF_PUSH_NOTIFICATIONS]: Parameters.OptInOutToPushNotificationsParams; [WRITE_COMMANDS.READ_NEWEST_ACTION]: Parameters.ReadNewestActionParams; [WRITE_COMMANDS.MARK_AS_UNREAD]: Parameters.MarkAsUnreadParams; diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index 4d83c8ea48b1..a0d2654a8ea5 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -297,7 +297,7 @@ function saveNewContactMethodAndRequestValidationCode(contactMethod: string) { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PENDING_CONTACT_ACTION, value: { - contactMethod: contactMethod, + contactMethod, errorFields: { actionVerified: null, }, @@ -309,8 +309,8 @@ function saveNewContactMethodAndRequestValidationCode(contactMethod: string) { { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM, - value: {isLoading: true} - } + value: {isLoading: true}, + }, ]; const successData: OnyxUpdate[] = [ @@ -325,13 +325,13 @@ function saveNewContactMethodAndRequestValidationCode(contactMethod: string) { pendingFields: { actionVerified: null, }, - } + }, }, { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM, - value: {isLoading: false} - } + value: {isLoading: false}, + }, ]; const failureData: OnyxUpdate[] = [ @@ -355,12 +355,12 @@ function saveNewContactMethodAndRequestValidationCode(contactMethod: string) { isLoading: false, errorFields: { ctionVerified: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('contacts.genericFailureMessages.requestContactMethodValidateCode'), - } - } - } + }, + }, + }, ]; - API.write(WRITE_COMMANDS.RESEND_VALIDATE_CODE, {}, {optimisticData, successData, failureData}); + API.write(WRITE_COMMANDS.RESEND_VALIDATE_CODE, null, {optimisticData, successData, failureData}); } /** diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx index cfb3d7a990aa..a1eb3e3747ce 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx @@ -24,20 +24,17 @@ import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/NewContactMethodForm'; -import type {Account, LoginList} from '@src/types/onyx'; +import type {LoginList} from '@src/types/onyx'; import type {Errors} from '@src/types/onyx/OnyxCommon'; type NewContactMethodPageOnyxProps = { /** Login list for the user that is signed in */ loginList: OnyxEntry; - - /** The details about the account that the user signed in with */ - account: OnyxEntry; }; type NewContactMethodPageProps = NewContactMethodPageOnyxProps & StackScreenProps; -function NewContactMethodPage({loginList, route, account}: NewContactMethodPageProps) { +function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const loginInputRef = useRef(null); @@ -45,16 +42,13 @@ function NewContactMethodPage({loginList, route, account}: NewContactMethodPageP const navigateBackTo = route?.params?.backTo ?? ROUTES.SETTINGS_PROFILE; - const addNewContactMethod = useCallback( - (values: FormOnyxValues) => { - const phoneLogin = LoginUtils.getPhoneLogin(values.phoneOrEmail); - const validateIfnumber = LoginUtils.validateNumber(phoneLogin); - const submitDetail = (validateIfnumber || values.phoneOrEmail).trim().toLowerCase(); + const addNewContactMethod = useCallback((values: FormOnyxValues) => { + const phoneLogin = LoginUtils.getPhoneLogin(values.phoneOrEmail); + const validateIfnumber = LoginUtils.validateNumber(phoneLogin); + const submitDetail = (validateIfnumber || values.phoneOrEmail).trim().toLowerCase(); - User.saveNewContactMethodAndRequestValidationCode(submitDetail); - }, - [route.params?.backTo], - ); + User.saveNewContactMethodAndRequestValidationCode(submitDetail); + }, []); useEffect(() => { if (!pendingContactAction?.validateCodeSent) { @@ -142,5 +136,4 @@ NewContactMethodPage.displayName = 'NewContactMethodPage'; export default withOnyx({ loginList: {key: ONYXKEYS.LOGIN_LIST}, - account: {key: ONYXKEYS.ACCOUNT}, })(NewContactMethodPage); diff --git a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx index dc8f093ec775..dabc9d1e8865 100644 --- a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx +++ b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -188,7 +188,7 @@ function BaseValidateCodeForm({ } User.validateSecondaryLogin(loginList, contactMethod, validateCode); - }, [loginList, validateCode, contactMethod]); + }, [loginList, validateCode, contactMethod, isValidatingAction, pendingContact?.contactMethod]); return ( <> @@ -222,7 +222,7 @@ function BaseValidateCodeForm({ > {translate('validateCodeForm.magicCodeNotReceived')} - {(hasMagicCodeBeenSent || !!pendingContact?.validateCodeSent) && ( + {(hasMagicCodeBeenSent ?? !!pendingContact?.validateCodeSent) && ( { - if(!loginData || !!loginData.pendingFields?.addedLogin) { + if (!loginData || !!loginData.pendingFields?.addedLogin) { return; } // Navigate to methods page on successful magic code verification Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS.route); - }, [loginData?.pendingFields, loginList]); + }, [loginData, loginData?.pendingFields, loginList]); return ( Date: Fri, 30 Aug 2024 17:23:30 +0300 Subject: [PATCH 05/11] fix: lint --- src/libs/API/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index b41376d54156..d728ce313ab2 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -428,7 +428,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.ADD_PERSONAL_BANK_ACCOUNT]: Parameters.AddPersonalBankAccountParams; [WRITE_COMMANDS.RESTART_BANK_ACCOUNT_SETUP]: Parameters.RestartBankAccountSetupParams; [WRITE_COMMANDS.OPT_IN_TO_PUSH_NOTIFICATIONS]: Parameters.OptInOutToPushNotificationsParams; - [WRITE_COMMANDS.RESEND_VALIDATE_CODE]: null, + [WRITE_COMMANDS.RESEND_VALIDATE_CODE]: null; [WRITE_COMMANDS.OPT_OUT_OF_PUSH_NOTIFICATIONS]: Parameters.OptInOutToPushNotificationsParams; [WRITE_COMMANDS.READ_NEWEST_ACTION]: Parameters.ReadNewestActionParams; [WRITE_COMMANDS.MARK_AS_UNREAD]: Parameters.MarkAsUnreadParams; From e9b440699f80078131f4210cdc4dee56816149ca Mon Sep 17 00:00:00 2001 From: Getabalew Date: Fri, 30 Aug 2024 18:40:55 +0300 Subject: [PATCH 06/11] fix: clear pending contact method action --- src/libs/actions/User.ts | 26 ++++++++++++++----- .../Profile/Contacts/NewContactMethodPage.tsx | 11 ++++++++ .../Contacts/ValidateContactActionPage.tsx | 3 +++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index a0d2654a8ea5..a719f32a4cc5 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -288,6 +288,19 @@ function resetContactMethodValidateCodeSentState(contactMethod: string) { }, }); } + +/** + * Clears unvalidated new contact method action + */ +function clearUnvalidatedNewContactMethodAction() { + Onyx.merge(ONYXKEYS.PENDING_CONTACT_ACTION, { + validateCodeSent: null, + contactMethod: null, + pendingFields: null, + errorFields: null, + }); +} + /** * Validates the action to add secondary contact method */ @@ -351,12 +364,7 @@ function saveNewContactMethodAndRequestValidationCode(contactMethod: string) { { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM, - value: { - isLoading: false, - errorFields: { - ctionVerified: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('contacts.genericFailureMessages.requestContactMethodValidateCode'), - }, - }, + value: {isLoading: false}, }, ]; @@ -441,6 +449,11 @@ function addNewContactMethod(contactMethod: string, validateCode = '') { key: ONYXKEYS.ACCOUNT, value: {isLoading: false}, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: ONYXKEYS.PENDING_CONTACT_ACTION, + value: {validateCodeSent: null}, + }, ]; const parameters: AddNewContactMethodParams = {partnerUserID: contactMethod, validateCode}; @@ -1246,4 +1259,5 @@ export { clearDraftCustomStatus, requestRefund, saveNewContactMethodAndRequestValidationCode, + clearUnvalidatedNewContactMethodAction, }; diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx index a1eb3e3747ce..10c1bd1fd3e0 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx @@ -4,6 +4,7 @@ import React, {useCallback, useEffect, useRef} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import {useOnyx, withOnyx} from 'react-native-onyx'; +import DotIndicatorMessage from '@components/DotIndicatorMessage'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; import type {FormOnyxValues} from '@components/Form/types'; @@ -42,6 +43,8 @@ function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { const navigateBackTo = route?.params?.backTo ?? ROUTES.SETTINGS_PROFILE; + const hasFailedToSendVerificationCode = !!pendingContactAction?.errorFields?.actionVerified; + const addNewContactMethod = useCallback((values: FormOnyxValues) => { const phoneLogin = LoginUtils.getPhoneLogin(values.phoneOrEmail); const validateIfnumber = LoginUtils.validateNumber(phoneLogin); @@ -58,6 +61,8 @@ function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { Navigation.navigate(ROUTES.SETINGS_CONTACT_METHOD_VALIDATE_ACTION); }, [pendingContactAction]); + useEffect(() => () => User.clearUnvalidatedNewContactMethodAction(), []); + const validate = React.useCallback( (values: FormOnyxValues): Errors => { const phoneLogin = LoginUtils.getPhoneLogin(values.phoneOrEmail); @@ -127,6 +132,12 @@ function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { maxLength={CONST.LOGIN_CHARACTER_LIMIT} /> + {hasFailedToSendVerificationCode && ( + + )} ); diff --git a/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx b/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx index 06b2da01c9be..9e526d65f2d7 100644 --- a/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx +++ b/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx @@ -6,6 +6,7 @@ import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as User from '@libs/actions/User'; import Navigation from '@libs/Navigation/Navigation'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -31,6 +32,8 @@ function ValidateContactActionPage() { Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS.route); }, [loginData, loginData?.pendingFields, loginList]); + useEffect(() => () => User.clearUnvalidatedNewContactMethodAction(), []); + return ( Date: Fri, 30 Aug 2024 19:19:59 +0300 Subject: [PATCH 07/11] fix: clear pending contact method action on back press --- .../settings/Profile/Contacts/NewContactMethodPage.tsx | 2 -- .../Profile/Contacts/ValidateContactActionPage.tsx | 7 +++++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx index 10c1bd1fd3e0..351e45711976 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx @@ -61,8 +61,6 @@ function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { Navigation.navigate(ROUTES.SETINGS_CONTACT_METHOD_VALIDATE_ACTION); }, [pendingContactAction]); - useEffect(() => () => User.clearUnvalidatedNewContactMethodAction(), []); - const validate = React.useCallback( (values: FormOnyxValues): Errors => { const phoneLogin = LoginUtils.getPhoneLogin(values.phoneOrEmail); diff --git a/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx b/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx index 9e526d65f2d7..ca239aea73ee 100644 --- a/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx +++ b/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx @@ -32,7 +32,10 @@ function ValidateContactActionPage() { Navigation.navigate(ROUTES.SETTINGS_CONTACT_METHODS.route); }, [loginData, loginData?.pendingFields, loginList]); - useEffect(() => () => User.clearUnvalidatedNewContactMethodAction(), []); + const onBackButtonPress = () => { + User.clearUnvalidatedNewContactMethodAction(); + Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.route) + } return ( Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.route)} + onBackButtonPress={onBackButtonPress} /> Date: Fri, 30 Aug 2024 19:28:37 +0300 Subject: [PATCH 08/11] fix: clear pending contact method action --- src/libs/actions/User.ts | 1 - src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index a719f32a4cc5..f7dbf7090a8b 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -295,7 +295,6 @@ function resetContactMethodValidateCodeSentState(contactMethod: string) { function clearUnvalidatedNewContactMethodAction() { Onyx.merge(ONYXKEYS.PENDING_CONTACT_ACTION, { validateCodeSent: null, - contactMethod: null, pendingFields: null, errorFields: null, }); diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx index 351e45711976..10c1bd1fd3e0 100644 --- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx +++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.tsx @@ -61,6 +61,8 @@ function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { Navigation.navigate(ROUTES.SETINGS_CONTACT_METHOD_VALIDATE_ACTION); }, [pendingContactAction]); + useEffect(() => () => User.clearUnvalidatedNewContactMethodAction(), []); + const validate = React.useCallback( (values: FormOnyxValues): Errors => { const phoneLogin = LoginUtils.getPhoneLogin(values.phoneOrEmail); From 0a40dd5a91f1eb1f47d8638055bbea99ddb76f1c Mon Sep 17 00:00:00 2001 From: Getabalew Date: Fri, 30 Aug 2024 20:00:01 +0300 Subject: [PATCH 09/11] fix: lint --- .../settings/Profile/Contacts/ValidateContactActionPage.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx b/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx index ca239aea73ee..469fb0908fcd 100644 --- a/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx +++ b/src/pages/settings/Profile/Contacts/ValidateContactActionPage.tsx @@ -34,8 +34,8 @@ function ValidateContactActionPage() { const onBackButtonPress = () => { User.clearUnvalidatedNewContactMethodAction(); - Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.route) - } + Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.route); + }; return ( Date: Sat, 31 Aug 2024 09:04:19 +0300 Subject: [PATCH 10/11] fix: use the correct function to request validation code for primary login --- .../Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx index dabc9d1e8865..c77c6e2a0743 100644 --- a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx +++ b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.tsx @@ -147,7 +147,12 @@ function BaseValidateCodeForm({ * Request a validate code / magic code be sent to verify this contact method */ const resendValidateCode = () => { - User.requestContactMethodValidateCode(contactMethod); + if (!!pendingContact?.contactMethod && isValidatingAction) { + User.saveNewContactMethodAndRequestValidationCode(pendingContact?.contactMethod); + } else { + User.requestContactMethodValidateCode(contactMethod); + } + inputValidateCodeRef.current?.clear(); }; From 0a2c0b23a5efaabce0c40de996700284232395a1 Mon Sep 17 00:00:00 2001 From: Getabalew Date: Mon, 2 Sep 2024 21:47:20 +0300 Subject: [PATCH 11/11] fix: clear failed contact method from error --- src/libs/actions/User.ts | 11 +++++++++++ .../Profile/Contacts/ContactMethodDetailsPage.tsx | 10 ++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index f7dbf7090a8b..1ac44512b8c5 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -260,6 +260,16 @@ function deleteContactMethod(contactMethod: string, loginList: Record {isFailedAddContactMethod && ( - User.clearContactMethod(contactMethod)} + canDismissError /> )}