Skip to content
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

Update "Additional details" form in KYC wallet upgrade flow #6752

Merged
merged 8 commits into from
Dec 14, 2021
3 changes: 3 additions & 0 deletions src/ONYXKEYS.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ export default {
// Stores information about additional details form entry
WALLET_ADDITIONAL_DETAILS: 'walletAdditionalDetails',

// Stores values put into the additional details step of the wallet KYC flow
WALLET_ADDITIONAL_DETAILS_DRAFT: 'walletAdditionalDetailsDraft',
Copy link
Contributor

Choose a reason for hiding this comment

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

A little bit confused by this key name, why DRAFT over something like WALLET_ADDITIONAL_DETAILS_KYC

Copy link
Contributor

Choose a reason for hiding this comment

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

Is it a DRAFT because the user might not finish but will need to come back to it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm following the pattern we initially set up here:

App/src/ONYXKEYS.js

Lines 133 to 134 in 1c80150

// Stores draft information about the active reimbursement account being set up
REIMBURSEMENT_ACCOUNT_DRAFT: 'reimbursementAccountDraft',

And yeah they are drafts since if the user bails on the flow and returns later they can pick up where they left off.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This hopefully will be a detail of all forms eventually but for now we have to store it somewhere.


// Object containing Wallet terms step state
WALLET_TERMS: 'walletTerms',

Expand Down
3 changes: 2 additions & 1 deletion src/components/AddressSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ const propTypes = {

...withLocalizePropTypes,
};

const defaultProps = {
value: '',
containerStyles: null,
containerStyles: [],
};

// Do not convert to class component! It's been tried before and presents more challenges than it's worth.
Expand Down
25 changes: 25 additions & 0 deletions src/components/FormScrollView.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import {ScrollView} from 'react-native';
import styles from '../styles/styles';

const propTypes = {
/** Form elements */
children: PropTypes.node.isRequired,
};

const FormScrollView = React.forwardRef((props, ref) => (
<ScrollView
style={[styles.w100, styles.flex1]}
ref={ref}
contentContainerStyle={styles.flexGrow1}
keyboardShouldPersistTaps="handled"
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
>
{props.children}
</ScrollView>
));

FormScrollView.propTypes = propTypes;
export default FormScrollView;
1 change: 1 addition & 0 deletions src/libs/ValidationUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,4 +316,5 @@ export {
isValidLengthForFirstOrLastName,
isValidPaypalUsername,
isValidRoutingNumber,
isValidSSNLastFour,
};
72 changes: 48 additions & 24 deletions src/libs/actions/Wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,26 @@ function fetchOnfidoToken() {
}

/**
* Privately used to update the additionalDetails object in Onyx (which will have various effects on the UI)
*
* @param {Boolean} loading whether we are making the API call to validate the user's provided personal details
* @param {String[]} [errorFields] an array of field names that should display errors in the UI
* @param {String} [additionalErrorMessage] an additional error message to display in the UI
* @private
*/
function setAdditionalDetailsStep(loading, errorFields = null, additionalErrorMessage = '') {
Onyx.merge(ONYXKEYS.WALLET_ADDITIONAL_DETAILS, {loading, errorFields, additionalErrorMessage});
function setAdditionalDetailsLoading(loading) {
Onyx.merge(ONYXKEYS.WALLET_ADDITIONAL_DETAILS, {loading});
}

/**
* @param {Object} errorFields
*/
function setAdditionalDetailsErrors(errorFields) {
Onyx.merge(ONYXKEYS.WALLET_ADDITIONAL_DETAILS, {errorFields: null});
Onyx.merge(ONYXKEYS.WALLET_ADDITIONAL_DETAILS, {errorFields});
}

/**
* @param {String} additionalErrorMessage
*/
function setAdditionalDetailsErrorMessage(additionalErrorMessage) {
Onyx.merge(ONYXKEYS.WALLET_ADDITIONAL_DETAILS, {additionalErrorMessage});
}

/**
Expand Down Expand Up @@ -70,19 +81,9 @@ function activateWallet(currentStep, parameters) {
onfidoData = parameters.onfidoData;
Onyx.merge(ONYXKEYS.WALLET_ONFIDO, {error: '', loading: true});
} else if (currentStep === CONST.WALLET.STEP.ADDITIONAL_DETAILS) {
setAdditionalDetailsStep(true);

// Personal details are heavily validated on the API side. We will only do a quick check to ensure the values
// exist in some capacity and then stringify them.
const errorFields = _.reduce(CONST.WALLET.REQUIRED_ADDITIONAL_DETAILS_FIELDS, (missingFields, fieldName) => (
!personalDetails[fieldName] ? [...missingFields, fieldName] : missingFields
), []);

if (!_.isEmpty(errorFields)) {
setAdditionalDetailsStep(false, errorFields);
return;
}

setAdditionalDetailsLoading(true);
setAdditionalDetailsErrors(null);
setAdditionalDetailsErrorMessage('');
personalDetails = JSON.stringify(parameters.personalDetails);
} else if (currentStep === CONST.WALLET.STEP.TERMS) {
hasAcceptedTerms = parameters.hasAcceptedTerms;
Expand All @@ -104,7 +105,15 @@ function activateWallet(currentStep, parameters) {

if (currentStep === CONST.WALLET.STEP.ADDITIONAL_DETAILS) {
if (response.title === CONST.WALLET.ERROR.MISSING_FIELD) {
setAdditionalDetailsStep(false, response.data.fieldNames);
// Errors for missing fields are returned from the API as an array of strings so we are converting this to an
// object with field names as keys and boolean for values
const errorFields = _.reduce(response.data.fieldNames, (errors, fieldName) => ({
...errors,
[fieldName]: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

+1 like the change to booleans for values, will keep this refactor in mind

}), {});
setAdditionalDetailsLoading(false);
setAdditionalDetailsErrors(errorFields);
setAdditionalDetailsErrorMessage('');
return;
}

Expand All @@ -116,11 +125,15 @@ function activateWallet(currentStep, parameters) {
];

if (_.contains(errorTitles, response.title)) {
setAdditionalDetailsStep(false, null, response.message);
setAdditionalDetailsLoading(false);
setAdditionalDetailsErrorMessage(response.message);
setAdditionalDetailsErrors(null);
return;
}

setAdditionalDetailsStep(false);
setAdditionalDetailsLoading(false);
setAdditionalDetailsErrors(null);
setAdditionalDetailsErrorMessage('');
return;
}

Expand All @@ -132,7 +145,9 @@ function activateWallet(currentStep, parameters) {
if (currentStep === CONST.WALLET.STEP.ONFIDO) {
Onyx.merge(ONYXKEYS.WALLET_ONFIDO, {error: '', loading: true});
} else if (currentStep === CONST.WALLET.STEP.ADDITIONAL_DETAILS) {
setAdditionalDetailsStep(false);
setAdditionalDetailsLoading(false);
setAdditionalDetailsErrors(null);
setAdditionalDetailsErrorMessage('');
} else if (currentStep === CONST.WALLET.STEP.TERMS) {
Onyx.merge(ONYXKEYS.WALLET_TERMS, {loading: false});
}
Expand All @@ -159,9 +174,18 @@ function fetchUserWallet() {
});
}

/**
* @param {Object} keyValuePair
*/
function updateAdditionalDetailsDraft(keyValuePair) {
Onyx.merge(ONYXKEYS.WALLET_ADDITIONAL_DETAILS_DRAFT, keyValuePair);
}

export {
fetchOnfidoToken,
setAdditionalDetailsStep,
activateWallet,
fetchUserWallet,
setAdditionalDetailsErrors,
updateAdditionalDetailsDraft,
setAdditionalDetailsErrorMessage,
};
Loading