Skip to content

Commit

Permalink
Merge pull request #5560 from Expensify/marcaaron-inviteInlineError
Browse files Browse the repository at this point in the history
  • Loading branch information
thienlnam authored Oct 6, 2021
2 parents c30f4e7 + 774a229 commit 19a6bc1
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 161 deletions.
101 changes: 101 additions & 0 deletions src/components/FormAlertWithSubmitButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import _ from 'underscore';
import React from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import styles from '../styles/styles';
import Icon from './Icon';
import {Exclamation} from './Icon/Expensicons';
import colors from '../styles/colors';
import Button from './Button';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import TextLink from './TextLink';
import Text from './Text';

const propTypes = {
/** Whether to show the alert text */
isAlertVisible: PropTypes.bool.isRequired,

/** Submit function */
onSubmit: PropTypes.func.isRequired,

/** Text for the button */
buttonText: PropTypes.string.isRequired,

/** Callback fired when the "fix the errors" link is pressed */
onFixTheErrorsLinkPressed: PropTypes.func.isRequired,

/** Error message to display above button */
message: PropTypes.string,

...withLocalizePropTypes,
};

const defaultProps = {
message: '',
};

const FormAlertWithSubmitButton = ({
isAlertVisible,
onSubmit,
buttonText,
translate,
onFixTheErrorsLinkPressed,
message,
}) => {
/**
* @returns {React.Component}
*/
function getAlertPrompt() {
let error = '';

if (!_.isEmpty(message)) {
error = (
<Text style={styles.mutedTextLabel}>{message}</Text>
);
} else {
error = (
<>
<Text style={styles.mutedTextLabel}>
{`${translate('common.please')} `}
</Text>
<TextLink
style={styles.label}
onPress={onFixTheErrorsLinkPressed}
>
{translate('common.fixTheErrors')}
</TextLink>
<Text style={styles.mutedTextLabel}>
{` ${translate('common.inTheFormBeforeContinuing')}.`}
</Text>
</>
);
}

return (
<View style={[styles.flexRow, styles.ml2, styles.flexWrap, styles.flex1]}>
{error}
</View>
);
}

return (
<View style={[styles.mh5, styles.mb5, styles.flex1, styles.justifyContentEnd]}>
{isAlertVisible && (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mb3]}>
<Icon src={Exclamation} fill={colors.red} />
{getAlertPrompt()}
</View>
)}
<Button
success
text={buttonText}
onPress={onSubmit}
pressOnEnter
/>
</View>
);
};

FormAlertWithSubmitButton.propTypes = propTypes;
FormAlertWithSubmitButton.defaultProps = defaultProps;
export default withLocalize(FormAlertWithSubmitButton);
6 changes: 3 additions & 3 deletions src/languages/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ export default {
},
please: 'Please',
contactUs: 'contact us',
pleaseEnterEmailOrPhoneNumber: 'Please enter an email or phone number',
fixTheErrors: 'fix the errors',
inTheFormBeforeContinuing: 'in the form before continuing',
confirm: 'Confirm',
reset: 'Reset',
done: 'Done',
Expand Down Expand Up @@ -369,7 +372,6 @@ export default {
},
},
loginForm: {
pleaseEnterEmailOrPhoneNumber: 'Please enter an email or phone number',
phoneOrEmail: 'Phone or email',
error: {
invalidFormatLogin: 'The email or phone number entered is invalid. Please fix the format and try again.',
Expand Down Expand Up @@ -444,8 +446,6 @@ export default {
firstName: 'Please enter valid first name',
lastName: 'Please enter valid last name',
noDefaultDepositAccountOrDebitCardAvailable: 'Please add a default deposit bank account or debit card',
fixTheErrors: 'fix the errors',
inTheFormBeforeContinuing: 'in the form before continuing',
validationAmounts: 'The validation amounts you entered are incorrect. Please double-check your bank statement and try again.',
},
},
Expand Down
6 changes: 3 additions & 3 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ export default {
},
please: 'Por favor',
contactUs: 'contáctenos',
pleaseEnterEmailOrPhoneNumber: 'Por favor escribe un email o número de teléfono',
fixTheErrors: 'corrige los errores',
inTheFormBeforeContinuing: 'en el formulario antes de continuar',
confirm: 'Confirmar',
reset: 'Restablecer',
done: 'Listo',
Expand Down Expand Up @@ -369,7 +372,6 @@ export default {
},
},
loginForm: {
pleaseEnterEmailOrPhoneNumber: 'Por favor escribe un email o número de teléfono',
phoneOrEmail: 'Número de teléfono o email',
error: {
invalidFormatLogin: 'El email o número de teléfono que has introducido no es válido. Corrígelo e inténtalo de nuevo.',
Expand Down Expand Up @@ -444,8 +446,6 @@ export default {
firstName: 'Ingresa un nombre válido',
lastName: 'Ingresa un apellido válido',
noDefaultDepositAccountOrDebitCardAvailable: 'Por favor agrega una cuenta bancaria para depósitos o una tarjeta de débito',
fixTheErrors: 'corrige los errores',
inTheFormBeforeContinuing: 'en el formulario antes de continuar',
validationAmounts: 'Los montos de validación que ingresaste son incorrectos. Verifica tu cuenta de banco e intenta de nuevo.',
},
},
Expand Down
10 changes: 1 addition & 9 deletions src/libs/actions/BankAccounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ function setFreePlanVerifiedBankAccountID(bankAccountID) {
* @param {String} errorModalMessage The error message to be displayed in the modal's body.
*/
function showBankAccountErrorModal(errorModalMessage = null) {
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {isErrorModalVisible: true, errorModalMessage});
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {errorModalMessage});
}

/**
Expand Down Expand Up @@ -582,13 +582,6 @@ function validateBankAccount(bankAccountID, validateCode) {
});
}

/**
* Hide error modal
*/
function hideBankAccountErrorModal() {
Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {isErrorModalVisible: false});
}

/**
* Set the current fields with errors.
*
Expand Down Expand Up @@ -806,7 +799,6 @@ export {
setupWithdrawalAccount,
validateBankAccount,
hideBankAccountErrors,
hideBankAccountErrorModal,
showBankAccountErrorModal,
showBankAccountFormValidationError,
setBankAccountFormValidationErrors,
Expand Down
29 changes: 24 additions & 5 deletions src/libs/actions/Policy.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ function updateAllPolicies(policyCollection) {

// Set all the policies
_.each(policyCollection, (policyData, key) => {
Onyx.merge(key, policyData);
Onyx.merge(key, {...policyData, alertMessage: '', errors: null});
});
}

Expand Down Expand Up @@ -179,6 +179,7 @@ function invite(logins, welcomeNote, policyID) {
// Make a shallow copy to preserve original data, and concat the login
const policy = _.clone(allPolicies[key]);
policy.employeeList = [...policy.employeeList, ...newEmployeeList];
policy.alertMessage = '';

// Optimistically add the user to the policy
Onyx.set(key, policy);
Expand All @@ -193,21 +194,21 @@ function invite(logins, welcomeNote, policyID) {
// Save the personalDetails for the invited user in Onyx
if (data.jsonCode === 200) {
Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, formatPersonalDetails(data.personalDetails));
Navigation.goBack();
return;
}

// If the operation failed, undo the optimistic addition
const policyDataWithoutLogin = _.clone(allPolicies[key]);
policyDataWithoutLogin.employeeList = _.without(allPolicies[key].employeeList, ...newEmployeeList);
Onyx.set(key, policyDataWithoutLogin);

// Show the user feedback that the addition failed
let errorMessage = translateLocal('workspace.invite.genericFailureMessage');
policyDataWithoutLogin.alertMessage = translateLocal('workspace.invite.genericFailureMessage');
if (data.jsonCode === 402) {
errorMessage += ` ${translateLocal('workspace.invite.pleaseEnterValidLogin')}`;
policyDataWithoutLogin.alertMessage += ` ${translateLocal('workspace.invite.pleaseEnterValidLogin')}`;
}

Growl.error(errorMessage, 5000);
Onyx.set(key, policyDataWithoutLogin);
});
}

Expand Down Expand Up @@ -294,6 +295,22 @@ function updateLocalPolicyValues(policyID, values) {
Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, values);
}

/**
* @param {String} policyID
* @param {Object} errors
*/
function setWorkspaceErrors(policyID, errors) {
Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {errors: null});
Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {errors});
}

/**
* @param {String} policyID
*/
function hideWorkspaceAlertMessage(policyID) {
Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {alertMessage: ''});
}

export {
getPolicySummaries,
getPolicyList,
Expand All @@ -304,4 +321,6 @@ export {
uploadAvatar,
update,
updateLocalPolicyValues,
setWorkspaceErrors,
hideWorkspaceAlertMessage,
};
67 changes: 10 additions & 57 deletions src/pages/ReimbursementAccount/ReimbursementAccountForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,12 @@ import PropTypes from 'prop-types';
import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';

import TextLink from '../../components/TextLink';
import Text from '../../components/Text';
import Button from '../../components/Button';
import styles from '../../styles/styles';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
import Icon from '../../components/Icon';
import {Exclamation} from '../../components/Icon/Expensicons';
import colors from '../../styles/colors';
import reimbursementAccountPropTypes from './reimbursementAccountPropTypes';
import compose from '../../libs/compose';
import ONYXKEYS from '../../ONYXKEYS';
import FormAlertWithSubmitButton from '../../components/FormAlertWithSubmitButton';

const propTypes = {
/** ACH data for the withdrawal account actively being set up */
Expand All @@ -32,44 +27,6 @@ const defaultProps = {
};

class ReimbursementAccountForm extends React.Component {
/**
* @returns {React.Component|String}
*/
getAlertPrompt() {
let error = '';

if (!_.isEmpty(this.props.reimbursementAccount.errorModalMessage)) {
error = (
<Text style={styles.mutedTextLabel}>{this.props.reimbursementAccount.errorModalMessage}</Text>
);
} else {
error = (
<>
<Text style={styles.mutedTextLabel}>
{`${this.props.translate('common.please')} `}
</Text>
<TextLink
style={styles.label}
onPress={() => {
this.form.scrollTo({y: 0, animated: true});
}}
>
{this.props.translate('bankAccount.error.fixTheErrors')}
</TextLink>
<Text style={styles.mutedTextLabel}>
{` ${this.props.translate('bankAccount.error.inTheFormBeforeContinuing')}.`}
</Text>
</>
);
}

return (
<View style={[styles.flexRow, styles.ml2, styles.flexWrap, styles.flex1]}>
{error}
</View>
);
}

render() {
const isErrorVisible = _.size(lodashGet(this.props, 'reimbursementAccount.errors', {})) > 0
|| lodashGet(this.props, 'reimbursementAccount.errorModalMessage', '').length > 0
Expand All @@ -88,19 +45,15 @@ class ReimbursementAccountForm extends React.Component {
<View style={[styles.mh5, styles.mb5]}>
{this.props.children}
</View>
<View style={[styles.mh5, styles.mb5, styles.flex1, styles.justifyContentEnd]}>
{isErrorVisible && (
<View style={[styles.flexRow, styles.alignItemsCenter, styles.mb3]}>
<Icon src={Exclamation} fill={colors.red} />
{this.getAlertPrompt()}
</View>
)}
<Button
success
text={this.props.translate('common.saveAndContinue')}
onPress={this.props.onSubmit}
/>
</View>
<FormAlertWithSubmitButton
isAlertVisible={isErrorVisible}
buttonText={this.props.translate('common.saveAndContinue')}
onSubmit={this.props.onSubmit}
onFixTheErrorsLinkPressed={() => {
this.form.scrollTo({y: 0, animated: true});
}}
message={this.props.reimbursementAccount.errorModalMessage}
/>
</ScrollView>
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/signin/LoginForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class LoginForm extends React.Component {
*/
validateAndSubmitForm() {
if (!this.state.login.trim()) {
this.setState({formError: 'loginForm.pleaseEnterEmailOrPhoneNumber'});
this.setState({formError: 'common.pleaseEnterEmailOrPhoneNumber'});
return;
}

Expand Down
Loading

0 comments on commit 19a6bc1

Please sign in to comment.