-
Notifications
You must be signed in to change notification settings - Fork 3.7k
feat: validate new contact method action #48320
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
087f2fd
74ec327
650f47f
c11acac
8d8f6a4
e9b4406
0714b23
db17bf3
0a40dd5
41ef7e8
c2f3b6f
0a2c0b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| type AddNewContactMethodParams = {partnerUserID: string}; | ||
| type AddNewContactMethodParams = {partnerUserID: string; validateCode: string}; | ||
|
|
||
| export default AddNewContactMethodParams; |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -260,6 +260,16 @@ function deleteContactMethod(contactMethod: string, loginList: Record<string, Lo | |||
| Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS.getRoute(backTo)); | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Clears a contact method optimistically. this is used when the contact method fails to be added to the backend | ||||
| */ | ||||
|
|
||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||
| function clearContactMethod(contactMethod: string) { | ||||
| Onyx.merge(ONYXKEYS.LOGIN_LIST, { | ||||
| [contactMethod]: null, | ||||
| }); | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Clears any possible stored errors for a specific field on a contact method | ||||
| */ | ||||
|
|
@@ -289,10 +299,91 @@ function resetContactMethodValidateCodeSentState(contactMethod: string) { | |||
| }); | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Clears unvalidated new contact method action | ||||
| */ | ||||
| function clearUnvalidatedNewContactMethodAction() { | ||||
| Onyx.merge(ONYXKEYS.PENDING_CONTACT_ACTION, { | ||||
| validateCodeSent: null, | ||||
| pendingFields: null, | ||||
| errorFields: null, | ||||
| }); | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Validates the action to add secondary contact method | ||||
| */ | ||||
| function saveNewContactMethodAndRequestValidationCode(contactMethod: string) { | ||||
| const optimisticData: OnyxUpdate[] = [ | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.PENDING_CONTACT_ACTION, | ||||
| value: { | ||||
| contactMethod, | ||||
| errorFields: { | ||||
| actionVerified: null, | ||||
| }, | ||||
| pendingFields: { | ||||
| actionVerified: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, | ||||
| }, | ||||
| }, | ||||
| }, | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM, | ||||
| value: {isLoading: true}, | ||||
| }, | ||||
| ]; | ||||
|
|
||||
| const successData: OnyxUpdate[] = [ | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.PENDING_CONTACT_ACTION, | ||||
| value: { | ||||
| validateCodeSent: true, | ||||
| errorFields: { | ||||
| actionVerified: null, | ||||
| }, | ||||
| pendingFields: { | ||||
| actionVerified: null, | ||||
| }, | ||||
| }, | ||||
| }, | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM, | ||||
| value: {isLoading: false}, | ||||
| }, | ||||
| ]; | ||||
|
|
||||
| const failureData: OnyxUpdate[] = [ | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.PENDING_CONTACT_ACTION, | ||||
| value: { | ||||
| validateCodeSent: null, | ||||
| errorFields: { | ||||
| actionVerified: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('contacts.genericFailureMessages.requestContactMethodValidateCode'), | ||||
| }, | ||||
| pendingFields: { | ||||
| actionVerified: null, | ||||
| }, | ||||
| }, | ||||
| }, | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM, | ||||
| value: {isLoading: false}, | ||||
| }, | ||||
| ]; | ||||
|
|
||||
| API.write(WRITE_COMMANDS.RESEND_VALIDATE_CODE, null, {optimisticData, successData, failureData}); | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Adds a secondary login to a user's account | ||||
| */ | ||||
| function addNewContactMethodAndNavigate(contactMethod: string, backTo?: string) { | ||||
| function addNewContactMethod(contactMethod: string, validateCode = '') { | ||||
| const optimisticData: OnyxUpdate[] = [ | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
|
|
@@ -310,6 +401,11 @@ function addNewContactMethodAndNavigate(contactMethod: string, backTo?: string) | |||
| }, | ||||
| }, | ||||
| }, | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.ACCOUNT, | ||||
| value: {isLoading: true}, | ||||
| }, | ||||
| ]; | ||||
| const successData: OnyxUpdate[] = [ | ||||
| { | ||||
|
|
@@ -323,6 +419,24 @@ function addNewContactMethodAndNavigate(contactMethod: string, backTo?: string) | |||
| }, | ||||
| }, | ||||
| }, | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.PENDING_CONTACT_ACTION, | ||||
| value: { | ||||
| validateCodeSent: null, | ||||
| errorFields: { | ||||
| actionVerified: null, | ||||
| }, | ||||
| pendingFields: { | ||||
| actionVerified: null, | ||||
| }, | ||||
| }, | ||||
| }, | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.ACCOUNT, | ||||
| value: {isLoading: false}, | ||||
| }, | ||||
| ]; | ||||
| const failureData: OnyxUpdate[] = [ | ||||
| { | ||||
|
|
@@ -339,12 +453,21 @@ function addNewContactMethodAndNavigate(contactMethod: string, backTo?: string) | |||
| }, | ||||
| }, | ||||
| }, | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.ACCOUNT, | ||||
| value: {isLoading: false}, | ||||
| }, | ||||
| { | ||||
| onyxMethod: Onyx.METHOD.MERGE, | ||||
| key: ONYXKEYS.PENDING_CONTACT_ACTION, | ||||
| value: {validateCodeSent: null}, | ||||
| }, | ||||
| ]; | ||||
|
|
||||
| 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)); | ||||
getusha marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
| } | ||||
|
|
||||
| /** | ||||
|
|
@@ -1123,7 +1246,8 @@ export { | |||
| updateNewsletterSubscription, | ||||
| deleteContactMethod, | ||||
| clearContactMethodErrors, | ||||
| addNewContactMethodAndNavigate, | ||||
| clearContactMethod, | ||||
| addNewContactMethod, | ||||
| validateLogin, | ||||
| validateSecondaryLogin, | ||||
| isBlockedFromConcierge, | ||||
|
|
@@ -1144,4 +1268,6 @@ export { | |||
| updateDraftCustomStatus, | ||||
| clearDraftCustomStatus, | ||||
| requestRefund, | ||||
| saveNewContactMethodAndRequestValidationCode, | ||||
| clearUnvalidatedNewContactMethodAction, | ||||
| }; | ||||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -1,9 +1,10 @@ | ||||
| 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 DotIndicatorMessage from '@components/DotIndicatorMessage'; | ||||
| import FormProvider from '@components/Form/FormProvider'; | ||||
| import InputWrapper from '@components/Form/InputWrapper'; | ||||
| import type {FormOnyxValues} from '@components/Form/types'; | ||||
|
|
@@ -38,19 +39,29 @@ function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { | |||
| const styles = useThemeStyles(); | ||||
| const {translate} = useLocalize(); | ||||
| const loginInputRef = useRef<AnimatedTextInputRef>(null); | ||||
| const [pendingContactAction] = useOnyx(ONYXKEYS.PENDING_CONTACT_ACTION); | ||||
|
|
||||
| const navigateBackTo = route?.params?.backTo ?? ROUTES.SETTINGS_PROFILE; | ||||
|
|
||||
| const addNewContactMethod = useCallback( | ||||
| (values: FormOnyxValues<typeof ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM>) => { | ||||
| const phoneLogin = LoginUtils.getPhoneLogin(values.phoneOrEmail); | ||||
| const validateIfnumber = LoginUtils.validateNumber(phoneLogin); | ||||
| const submitDetail = (validateIfnumber || values.phoneOrEmail).trim().toLowerCase(); | ||||
| const hasFailedToSendVerificationCode = !!pendingContactAction?.errorFields?.actionVerified; | ||||
|
|
||||
| User.addNewContactMethodAndNavigate(submitDetail, route.params?.backTo); | ||||
| }, | ||||
| [route.params?.backTo], | ||||
| ); | ||||
| const addNewContactMethod = useCallback((values: FormOnyxValues<typeof ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM>) => { | ||||
| const phoneLogin = LoginUtils.getPhoneLogin(values.phoneOrEmail); | ||||
| const validateIfnumber = LoginUtils.validateNumber(phoneLogin); | ||||
| const submitDetail = (validateIfnumber || values.phoneOrEmail).trim().toLowerCase(); | ||||
|
|
||||
| User.saveNewContactMethodAndRequestValidationCode(submitDetail); | ||||
| }, []); | ||||
|
|
||||
| useEffect(() => { | ||||
| if (!pendingContactAction?.validateCodeSent) { | ||||
| return; | ||||
| } | ||||
|
|
||||
| Navigation.navigate(ROUTES.SETINGS_CONTACT_METHOD_VALIDATE_ACTION); | ||||
| }, [pendingContactAction]); | ||||
|
Comment on lines
+56
to
+62
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @getusha What is the purpose for this logic?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @parasharrajat We started requiring verification before adding a contact method. the new flow is
Line 342 in e1d726e
|
||||
|
|
||||
| useEffect(() => () => User.clearUnvalidatedNewContactMethodAction(), []); | ||||
|
|
||||
| const validate = React.useCallback( | ||||
| (values: FormOnyxValues<typeof ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM>): Errors => { | ||||
|
|
@@ -105,7 +116,6 @@ function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { | |||
| onSubmit={addNewContactMethod} | ||||
| submitButtonText={translate('common.add')} | ||||
| style={[styles.flexGrow1, styles.mh5]} | ||||
| enabledWhenOffline | ||||
| > | ||||
| <Text style={styles.mb5}>{translate('common.pleaseEnterEmailOrPhoneNumber')}</Text> | ||||
| <View style={styles.mb6}> | ||||
|
|
@@ -122,6 +132,12 @@ function NewContactMethodPage({loginList, route}: NewContactMethodPageProps) { | |||
| maxLength={CONST.LOGIN_CHARACTER_LIMIT} | ||||
| /> | ||||
| </View> | ||||
| {hasFailedToSendVerificationCode && ( | ||||
| <DotIndicatorMessage | ||||
| messages={ErrorUtils.getLatestErrorField(pendingContactAction, 'actionVerified')} | ||||
| type="error" | ||||
| /> | ||||
| )} | ||||
| </FormProvider> | ||||
| </ScreenWrapper> | ||||
| ); | ||||
|
|
||||
Uh oh!
There was an error while loading. Please reload this page.