From c46311ebb21ea8aee6f91ffdaaa99da8fcce7fb2 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 5 Aug 2021 12:01:53 -0700 Subject: [PATCH 01/60] Add errorOutline style to TextInput --- src/components/TextInputWithLabel.js | 7 ++++++- src/styles/styles.js | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/TextInputWithLabel.js b/src/components/TextInputWithLabel.js index 63cdd87dbb89..6e9abe401177 100644 --- a/src/components/TextInputWithLabel.js +++ b/src/components/TextInputWithLabel.js @@ -54,7 +54,12 @@ const TextInputWithLabel = props => ( )} diff --git a/src/styles/styles.js b/src/styles/styles.js index b1ade504e459..53ce3d4a1cf7 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -511,6 +511,10 @@ const styles = { noOutline: addOutlineWidth({}, 0), + errorOutline: { + borderColor: colors.red, + }, + formLabel: { fontFamily: fontFamily.GTA_BOLD, fontWeight: fontWeightBold, From 18dcbeb81195e2271276b236c3090663bbe2a169 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 5 Aug 2021 12:02:52 -0700 Subject: [PATCH 02/60] Keep track of bank Account errors in Onyx --- src/libs/actions/BankAccounts.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 23ea4e36a16a..7bc3a3e769b6 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -563,6 +563,10 @@ function validateBankAccount(bankAccountID, validateCode) { }); } +function showBankAccountError(error) { + Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {error}).then(() => Growl.error(error)); +} + /** * Create or update the bank account in db with the updated data. * @@ -725,12 +729,12 @@ function setupWithdrawalAccount(data) { goToWithdrawalAccountSetupStep(nextStep, achData); if (error) { - Growl.error(error, 5000); + showBankAccountError(error); } }); } -function hideExistingOwnersError() { +function hideBankAccountErrors() { Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {error: '', existingOwnersList: ''}); } @@ -746,5 +750,6 @@ export { goToWithdrawalAccountSetupStep, setupWithdrawalAccount, validateBankAccount, - hideExistingOwnersError, + hideBankAccountErrors, + showBankAccountError, }; From ed5af851ff6556154625487b5af430933b97972d Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 5 Aug 2021 12:03:24 -0700 Subject: [PATCH 03/60] Update BankAccountStep --- src/pages/ReimbursementAccount/BankAccountStep.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index b38563acdef0..637a5410a222 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -23,7 +23,7 @@ import exampleCheckImage from '../../../assets/images/example-check-image.png'; import Text from '../../components/Text'; import { goToWithdrawalAccountSetupStep, - hideExistingOwnersError, + hideBankAccountErrors, setupWithdrawalAccount, } from '../../libs/actions/BankAccounts'; import ConfirmModal from '../../components/ConfirmModal'; @@ -211,8 +211,16 @@ class BankAccountStep extends React.Component { placeholder={this.props.translate('bankAccount.routingNumber')} keyboardType="number-pad" value={this.state.routingNumber} - onChangeText={routingNumber => this.setState({routingNumber})} + onChangeText={(routingNumber) => { + if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.routingNumber')) { + hideBankAccountErrors(); + } + this.setState({routingNumber}); + }} disabled={shouldDisableInputs} + errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.routingNumber') + ? this.props.reimbursementAccount.error + : ''} /> From 59ac4c4be96355eeef41c6ef87598a095a93530f Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 5 Aug 2021 12:03:38 -0700 Subject: [PATCH 04/60] Update CompanyStep error handling --- src/pages/ReimbursementAccount/CompanyStep.js | 94 +++++++++++++++---- 1 file changed, 77 insertions(+), 17 deletions(-) diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index c0fc39effba9..b791a8281cdc 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -6,7 +6,11 @@ import Str from 'expensify-common/lib/str'; import moment from 'moment'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import CONST from '../../CONST'; -import {goToWithdrawalAccountSetupStep, setupWithdrawalAccount} from '../../libs/actions/BankAccounts'; +import { + goToWithdrawalAccountSetupStep, hideBankAccountErrors, + setupWithdrawalAccount, + showBankAccountError, +} from '../../libs/actions/BankAccounts'; import Navigation from '../../libs/Navigation/Navigation'; import Text from '../../components/Text'; import TextInputWithLabel from '../../components/TextInputWithLabel'; @@ -66,47 +70,47 @@ class CompanyStep extends React.Component { */ validate() { if (!this.state.password.trim()) { - Growl.error(this.props.translate('common.passwordCannotBeBlank')); + showBankAccountError(this.props.translate('common.passwordCannotBeBlank')); return false; } if (!isValidAddress(this.state.addressStreet)) { - Growl.error(this.props.translate('bankAccount.error.addressStreet')); + showBankAccountError(this.props.translate('bankAccount.error.addressStreet')); return false; } if (this.state.addressState === '') { - Growl.error(this.props.translate('bankAccount.error.addressState')); + showBankAccountError(this.props.translate('bankAccount.error.addressState')); return false; } if (!isValidZipCode(this.state.addressZipCode)) { - Growl.error(this.props.translate('bankAccount.error.zipCode')); + showBankAccountError(this.props.translate('bankAccount.error.zipCode')); return false; } if (!Str.isValidURL(this.state.website)) { - Growl.error(this.props.translate('bankAccount.error.website')); + showBankAccountError(this.props.translate('bankAccount.error.website')); return false; } if (!/[0-9]{9}/.test(this.state.companyTaxID)) { - Growl.error(this.props.translate('bankAccount.error.taxID')); + showBankAccountError(this.props.translate('bankAccount.error.taxID')); return false; } if (!isValidDate(this.state.incorporationDate)) { - Growl.error(this.props.translate('bankAccount.error.incorporationDate')); + showBankAccountError(this.props.translate('bankAccount.error.incorporationDate')); return false; } if (!isValidIndustryCode(this.state.industryCode)) { - Growl.error(this.props.translate('bankAccount.error.industryCode')); + showBankAccountError(this.props.translate('bankAccount.error.industryCode')); return false; } if (!this.state.hasNoConnectionToCannabis) { - Growl.error(this.props.translate('bankAccount.error.restrictedBusiness')); + showBankAccountError(this.props.translate('bankAccount.error.restrictedBusiness')); return false; } @@ -150,8 +154,16 @@ class CompanyStep extends React.Component { this.setState({addressStreet})} + onChangeText={(addressStreet) => { + if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.addressStreet')) { + hideBankAccountErrors(); + } + this.setState({addressStreet}); + }} value={this.state.addressStreet} + errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.addressStreet') + ? this.props.translate('bankAccount.error.addressStreet') + : ''} /> @@ -172,8 +184,16 @@ class CompanyStep extends React.Component { this.setState({addressZipCode})} + onChangeText={(addressZipCode) => { + if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.zipCode')) { + hideBankAccountErrors(); + } + this.setState({addressZipCode}); + }} value={this.state.addressZipCode} + errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.zipCode') + ? this.props.translate('bankAccount.error.zipCode') + : ''} /> this.setState({website})} + onChangeText={(website) => { + if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.website')) { + hideBankAccountErrors(); + } + this.setState({website}); + }} value={this.state.website} + errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.website') + ? this.props.translate('bankAccount.error.website') + : ''} /> this.setState({companyTaxID})} + onChangeText={(companyTaxID) => { + if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.taxID')) { + hideBankAccountErrors(); + } + this.setState({companyTaxID}); + }} value={this.state.companyTaxID} disabled={shouldDisableCompanyTaxID} + errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.taxID') + ? this.props.translate('bankAccount.error.taxID') + : ''} /> {this.props.translate('companyStep.companyType')} @@ -211,9 +247,17 @@ class CompanyStep extends React.Component { {/* TODO: Replace with date picker */} this.setState({incorporationDate})} + onChangeText={(incorporationDate) => { + if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.incorporationDate')) { + hideBankAccountErrors(); + } + this.setState({incorporationDate}); + }} value={this.state.incorporationDate} placeholder={this.props.translate('companyStep.incorporationDatePlaceholder')} + errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.incorporationDate') + ? this.props.translate('bankAccount.error.incorporationDate') + : ''} /> @@ -230,8 +274,16 @@ class CompanyStep extends React.Component { helpLinkText={this.props.translate('common.whatThis')} helpLinkURL="https://www.naics.com/search/" containerStyles={[styles.mt4]} - onChangeText={industryCode => this.setState({industryCode})} + onChangeText={(industryCode) => { + if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.industryCode')) { + hideBankAccountErrors(); + } + this.setState({industryCode}); + }} value={this.state.industryCode} + errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.industryCode') + ? this.props.translate('bankAccount.error.industryCode') + : ''} /> this.setState({password})} + onChangeText={(password) => { + if (this.props.reimbursementAccount.error === this.props.translate('common.passwordCannotBeBlank')) { + hideBankAccountErrors(); + } + this.setState({password}); + }} value={this.state.password} onSubmitEditing={this.submit} + errorText={this.props.reimbursementAccount.error === this.props.translate('common.passwordCannotBeBlank') + ? this.props.translate('common.passwordCannotBeBlank') + : ''} /> Date: Thu, 5 Aug 2021 12:03:52 -0700 Subject: [PATCH 05/60] Update IdentityForm to handle DOB errors --- src/pages/ReimbursementAccount/IdentityForm.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/IdentityForm.js b/src/pages/ReimbursementAccount/IdentityForm.js index 3122d5e6532b..5efdd346631f 100644 --- a/src/pages/ReimbursementAccount/IdentityForm.js +++ b/src/pages/ReimbursementAccount/IdentityForm.js @@ -41,6 +41,9 @@ const propTypes = { ssnLast4: PropTypes.string, }), + /** Any errors that the API can throw from invalid form data */ + error: PropTypes.string, + ...withLocalizePropTypes, }; @@ -56,10 +59,11 @@ const defaultProps = { dob: '', ssnLast4: '', }, + error: '', }; const IdentityForm = ({ - translate, values, onFieldChange, style, + translate, values, onFieldChange, style, error, }) => { const { firstName, lastName, street, city, state, zipCode, dob, ssnLast4, @@ -88,6 +92,7 @@ const IdentityForm = ({ placeholder={translate('common.dateFormat')} value={dob} onChangeText={val => onFieldChange('dob', val)} + errorText={error} /> Date: Thu, 5 Aug 2021 12:08:32 -0700 Subject: [PATCH 06/60] Update propTypes --- .../BeneficialOwnersStep.js | 28 ++++++++++++-- src/pages/ReimbursementAccount/CompanyStep.js | 27 ++++++++++++-- .../ReimbursementAccount/RequestorStep.js | 37 +++++++++++++++++-- 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/src/pages/ReimbursementAccount/BeneficialOwnersStep.js b/src/pages/ReimbursementAccount/BeneficialOwnersStep.js index 8562fbef130a..fec43d64b986 100644 --- a/src/pages/ReimbursementAccount/BeneficialOwnersStep.js +++ b/src/pages/ReimbursementAccount/BeneficialOwnersStep.js @@ -2,6 +2,7 @@ import _ from 'underscore'; import React from 'react'; import PropTypes from 'prop-types'; import {ScrollView, View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; import Text from '../../components/Text'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import styles from '../../styles/styles'; @@ -11,17 +12,29 @@ import Button from '../../components/Button'; import IdentityForm from './IdentityForm'; import FixedFooter from '../../components/FixedFooter'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; -import {goToWithdrawalAccountSetupStep, setupWithdrawalAccount} from '../../libs/actions/BankAccounts'; +import { + goToWithdrawalAccountSetupStep, + hideBankAccountErrors, + setupWithdrawalAccount, +} from '../../libs/actions/BankAccounts'; import Navigation from '../../libs/Navigation/Navigation'; import CONST from '../../CONST'; import {isValidIdentity} from '../../libs/ValidationUtils'; import Growl from '../../libs/Growl'; +import ONYXKEYS from '../../ONYXKEYS'; +import compose from '../../libs/compose'; const propTypes = { /** Name of the company */ companyName: PropTypes.string.isRequired, ...withLocalizePropTypes, + + /** Bank account currently in setup */ + reimbursementAccount: PropTypes.shape({ + /** Error set when handling the API response */ + error: PropTypes.string, + }).isRequired, }; class BeneficialOwnersStep extends React.Component { @@ -160,6 +173,9 @@ class BeneficialOwnersStep extends React.Component { onFieldChange={(fieldName, value) => this.setState((prevState) => { const beneficialOwners = [...prevState.beneficialOwners]; beneficialOwners[index][fieldName] = value; + if (fieldName === 'dob' && this.props.reimbursementAccount.error) { + hideBankAccountErrors(); + } return {beneficialOwners}; })} values={{ @@ -230,5 +246,11 @@ class BeneficialOwnersStep extends React.Component { } BeneficialOwnersStep.propTypes = propTypes; - -export default withLocalize(BeneficialOwnersStep); +export default compose( + withLocalize, + withOnyx({ + reimbursementAccount: { + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, + }, + }), +)(BeneficialOwnersStep); diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index b791a8281cdc..eeb07d2a36a8 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -4,6 +4,8 @@ import React from 'react'; import {View, ScrollView} from 'react-native'; import Str from 'expensify-common/lib/str'; import moment from 'moment'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import CONST from '../../CONST'; import { @@ -22,10 +24,21 @@ import TextLink from '../../components/TextLink'; import Picker from '../../components/Picker'; import StatePicker from '../../components/StatePicker'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; -import Growl from '../../libs/Growl'; import { isValidAddress, isValidDate, isValidIndustryCode, isValidZipCode, } from '../../libs/ValidationUtils'; +import compose from '../../libs/compose'; +import ONYXKEYS from '../../ONYXKEYS'; + +const propTypes = { + /** Bank account currently in setup */ + reimbursementAccount: PropTypes.shape({ + /** Error set when handling the API response */ + error: PropTypes.string, + }).isRequired, + + ...withLocalizePropTypes, +}; class CompanyStep extends React.Component { constructor(props) { @@ -337,6 +350,12 @@ class CompanyStep extends React.Component { } } -CompanyStep.propTypes = withLocalizePropTypes; - -export default withLocalize(CompanyStep); +CompanyStep.propTypes = propTypes; +export default compose( + withLocalize, + withOnyx({ + reimbursementAccount: { + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, + }, + }), +)(CompanyStep); diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index 2287724daa9b..9dc5a22337cf 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -1,6 +1,8 @@ import React from 'react'; import lodashGet from 'lodash/get'; import {View, ScrollView} from 'react-native'; +import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; import styles from '../../styles/styles'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; @@ -9,13 +11,29 @@ import TextLink from '../../components/TextLink'; import Navigation from '../../libs/Navigation/Navigation'; import CheckboxWithLabel from '../../components/CheckboxWithLabel'; import Text from '../../components/Text'; -import {goToWithdrawalAccountSetupStep, setupWithdrawalAccount} from '../../libs/actions/BankAccounts'; +import { + goToWithdrawalAccountSetupStep, + hideBankAccountErrors, + setupWithdrawalAccount, +} from '../../libs/actions/BankAccounts'; import Button from '../../components/Button'; import FixedFooter from '../../components/FixedFooter'; import IdentityForm from './IdentityForm'; import {isValidIdentity} from '../../libs/ValidationUtils'; import Growl from '../../libs/Growl'; import Onfido from '../../components/Onfido'; +import compose from '../../libs/compose'; +import ONYXKEYS from '../../ONYXKEYS'; + +const propTypes = { + /** Bank account currently in setup */ + reimbursementAccount: PropTypes.shape({ + /** Error set when handling the API response */ + error: PropTypes.string, + }).isRequired, + + ...withLocalizePropTypes, +}; class RequestorStep extends React.Component { constructor(props) { @@ -46,6 +64,11 @@ class RequestorStep extends React.Component { zipCode: 'requestorAddressZipCode', }; const fieldName = lodashGet(renamedFields, field, field); + + if (field === 'dob' && this.props.reimbursementAccount.error) { + hideBankAccountErrors(); + } + this.setState({[fieldName]: value}); } @@ -189,7 +212,13 @@ class RequestorStep extends React.Component { } } -RequestorStep.propTypes = withLocalizePropTypes; +RequestorStep.propTypes = propTypes; RequestorStep.displayName = 'RequestorStep'; - -export default withLocalize(RequestorStep); +export default compose( + withLocalize, + withOnyx({ + reimbursementAccount: { + key: ONYXKEYS.REIMBURSEMENT_ACCOUNT, + }, + }), +)(RequestorStep); From 9bf41ec01b706cb78d2bf2d5e97f582c112cfc9c Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 5 Aug 2021 16:41:57 -0700 Subject: [PATCH 07/60] use variable for error --- .../ReimbursementAccount/BankAccountStep.js | 10 +++---- src/pages/ReimbursementAccount/CompanyStep.js | 29 ++++++++++--------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 637a5410a222..5c0ef8ebbbf1 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -130,8 +130,8 @@ class BankAccountStep extends React.Component { const isFromPlaid = this.props.achData.setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID; const shouldDisableInputs = Boolean(this.props.achData.bankAccountID) || isFromPlaid; const existingOwners = this.props.reimbursementAccount.existingOwners; - const isExistingOwnersErrorVisible = Boolean(this.props.reimbursementAccount.error - && existingOwners); + const error = this.props.reimbursementAccount.error; + const isExistingOwnersErrorVisible = Boolean(error && existingOwners); return ( { - if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.routingNumber')) { + if (error === this.props.translate('bankAccount.error.routingNumber')) { hideBankAccountErrors(); } this.setState({routingNumber}); }} disabled={shouldDisableInputs} - errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.routingNumber') - ? this.props.reimbursementAccount.error - : ''} + errorText={error === this.props.translate('bankAccount.error.routingNumber') ? error : ''} /> acc || !this.state[curr].trim(), false); + const error = this.props.reimbursementAccount.error; return ( <> { - if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.addressStreet')) { + if (error === this.props.translate('bankAccount.error.addressStreet')) { hideBankAccountErrors(); } this.setState({addressStreet}); }} value={this.state.addressStreet} - errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.addressStreet') + errorText={error === this.props.translate('bankAccount.error.addressStreet') ? this.props.translate('bankAccount.error.addressStreet') : ''} /> @@ -198,13 +199,13 @@ class CompanyStep extends React.Component { label={this.props.translate('common.zip')} containerStyles={[styles.mt4]} onChangeText={(addressZipCode) => { - if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.zipCode')) { + if (error === this.props.translate('bankAccount.error.zipCode')) { hideBankAccountErrors(); } this.setState({addressZipCode}); }} value={this.state.addressZipCode} - errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.zipCode') + errorText={error === this.props.translate('bankAccount.error.zipCode') ? this.props.translate('bankAccount.error.zipCode') : ''} /> @@ -220,13 +221,13 @@ class CompanyStep extends React.Component { label={this.props.translate('companyStep.companyWebsite')} containerStyles={[styles.mt4]} onChangeText={(website) => { - if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.website')) { + if (error === this.props.translate('bankAccount.error.website')) { hideBankAccountErrors(); } this.setState({website}); }} value={this.state.website} - errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.website') + errorText={error === this.props.translate('bankAccount.error.website') ? this.props.translate('bankAccount.error.website') : ''} /> @@ -235,14 +236,14 @@ class CompanyStep extends React.Component { containerStyles={[styles.mt4]} keyboardType={CONST.KEYBOARD_TYPE.PHONE_PAD} onChangeText={(companyTaxID) => { - if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.taxID')) { + if (error === this.props.translate('bankAccount.error.taxID')) { hideBankAccountErrors(); } this.setState({companyTaxID}); }} value={this.state.companyTaxID} disabled={shouldDisableCompanyTaxID} - errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.taxID') + errorText={error === this.props.translate('bankAccount.error.taxID') ? this.props.translate('bankAccount.error.taxID') : ''} /> @@ -261,14 +262,14 @@ class CompanyStep extends React.Component { { - if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.incorporationDate')) { + if (error === this.props.translate('bankAccount.error.incorporationDate')) { hideBankAccountErrors(); } this.setState({incorporationDate}); }} value={this.state.incorporationDate} placeholder={this.props.translate('companyStep.incorporationDatePlaceholder')} - errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.incorporationDate') + errorText={error === this.props.translate('bankAccount.error.incorporationDate') ? this.props.translate('bankAccount.error.incorporationDate') : ''} /> @@ -288,13 +289,13 @@ class CompanyStep extends React.Component { helpLinkURL="https://www.naics.com/search/" containerStyles={[styles.mt4]} onChangeText={(industryCode) => { - if (this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.industryCode')) { + if (error === this.props.translate('bankAccount.error.industryCode')) { hideBankAccountErrors(); } this.setState({industryCode}); }} value={this.state.industryCode} - errorText={this.props.reimbursementAccount.error === this.props.translate('bankAccount.error.industryCode') + errorText={error === this.props.translate('bankAccount.error.industryCode') ? this.props.translate('bankAccount.error.industryCode') : ''} /> @@ -305,14 +306,14 @@ class CompanyStep extends React.Component { autoCompleteType="password" textContentType="password" onChangeText={(password) => { - if (this.props.reimbursementAccount.error === this.props.translate('common.passwordCannotBeBlank')) { + if (error === this.props.translate('common.passwordCannotBeBlank')) { hideBankAccountErrors(); } this.setState({password}); }} value={this.state.password} onSubmitEditing={this.submit} - errorText={this.props.reimbursementAccount.error === this.props.translate('common.passwordCannotBeBlank') + errorText={error === this.props.translate('common.passwordCannotBeBlank') ? this.props.translate('common.passwordCannotBeBlank') : ''} /> From 39aa09d8adca5eb76702c660cf0c6bdb6bc13d72 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 5 Aug 2021 16:51:29 -0700 Subject: [PATCH 08/60] style --- src/pages/ReimbursementAccount/BankAccountStep.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 5c0ef8ebbbf1..9cbce7a6c3f4 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -218,7 +218,8 @@ class BankAccountStep extends React.Component { this.setState({routingNumber}); }} disabled={shouldDisableInputs} - errorText={error === this.props.translate('bankAccount.error.routingNumber') ? error : ''} + errorText={error === this.props.translate('bankAccount.error.routingNumber') + ? error : ''} /> Date: Thu, 5 Aug 2021 16:58:06 -0700 Subject: [PATCH 09/60] Rename functikon --- src/libs/actions/BankAccounts.js | 6 +++--- src/pages/ReimbursementAccount/CompanyStep.js | 20 +++++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 7bc3a3e769b6..5af1cfa68377 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -563,7 +563,7 @@ function validateBankAccount(bankAccountID, validateCode) { }); } -function showBankAccountError(error) { +function showBankAccountFormValidationError(error) { Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {error}).then(() => Growl.error(error)); } @@ -729,7 +729,7 @@ function setupWithdrawalAccount(data) { goToWithdrawalAccountSetupStep(nextStep, achData); if (error) { - showBankAccountError(error); + showBankAccountFormValidationError(error); } }); } @@ -751,5 +751,5 @@ export { setupWithdrawalAccount, validateBankAccount, hideBankAccountErrors, - showBankAccountError, + showBankAccountFormValidationError, }; diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index 50421f648b69..e172832078f1 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -11,7 +11,7 @@ import CONST from '../../CONST'; import { goToWithdrawalAccountSetupStep, hideBankAccountErrors, setupWithdrawalAccount, - showBankAccountError, + showBankAccountFormValidationError, } from '../../libs/actions/BankAccounts'; import Navigation from '../../libs/Navigation/Navigation'; import Text from '../../components/Text'; @@ -83,47 +83,47 @@ class CompanyStep extends React.Component { */ validate() { if (!this.state.password.trim()) { - showBankAccountError(this.props.translate('common.passwordCannotBeBlank')); + showBankAccountFormValidationError(this.props.translate('common.passwordCannotBeBlank')); return false; } if (!isValidAddress(this.state.addressStreet)) { - showBankAccountError(this.props.translate('bankAccount.error.addressStreet')); + showBankAccountFormValidationError(this.props.translate('bankAccount.error.addressStreet')); return false; } if (this.state.addressState === '') { - showBankAccountError(this.props.translate('bankAccount.error.addressState')); + showBankAccountFormValidationError(this.props.translate('bankAccount.error.addressState')); return false; } if (!isValidZipCode(this.state.addressZipCode)) { - showBankAccountError(this.props.translate('bankAccount.error.zipCode')); + showBankAccountFormValidationError(this.props.translate('bankAccount.error.zipCode')); return false; } if (!Str.isValidURL(this.state.website)) { - showBankAccountError(this.props.translate('bankAccount.error.website')); + showBankAccountFormValidationError(this.props.translate('bankAccount.error.website')); return false; } if (!/[0-9]{9}/.test(this.state.companyTaxID)) { - showBankAccountError(this.props.translate('bankAccount.error.taxID')); + showBankAccountFormValidationError(this.props.translate('bankAccount.error.taxID')); return false; } if (!isValidDate(this.state.incorporationDate)) { - showBankAccountError(this.props.translate('bankAccount.error.incorporationDate')); + showBankAccountFormValidationError(this.props.translate('bankAccount.error.incorporationDate')); return false; } if (!isValidIndustryCode(this.state.industryCode)) { - showBankAccountError(this.props.translate('bankAccount.error.industryCode')); + showBankAccountFormValidationError(this.props.translate('bankAccount.error.industryCode')); return false; } if (!this.state.hasNoConnectionToCannabis) { - showBankAccountError(this.props.translate('bankAccount.error.restrictedBusiness')); + showBankAccountFormValidationError(this.props.translate('bankAccount.error.restrictedBusiness')); return false; } From 5d9ceafe70d5d5cbf4ec42193b1ff5c379c5f1cb Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Thu, 5 Aug 2021 16:59:13 -0700 Subject: [PATCH 10/60] update comment --- src/pages/ReimbursementAccount/IdentityForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/IdentityForm.js b/src/pages/ReimbursementAccount/IdentityForm.js index 5efdd346631f..59902be1a9de 100644 --- a/src/pages/ReimbursementAccount/IdentityForm.js +++ b/src/pages/ReimbursementAccount/IdentityForm.js @@ -41,7 +41,7 @@ const propTypes = { ssnLast4: PropTypes.string, }), - /** Any errors that the API can throw from invalid form data */ + /** Any errors that can arise from form validation */ error: PropTypes.string, ...withLocalizePropTypes, From 9612775b502d94ac360704b24b96366b41fd8d14 Mon Sep 17 00:00:00 2001 From: Santhoshkumar Sellavel Date: Fri, 6 Aug 2021 22:08:23 +0530 Subject: [PATCH 11/60] Wallet balance translation fix in Payments Page --- src/components/CurrentWalletBalance.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/CurrentWalletBalance.js b/src/components/CurrentWalletBalance.js index b58fe6108dd1..f24b4cff8942 100644 --- a/src/components/CurrentWalletBalance.js +++ b/src/components/CurrentWalletBalance.js @@ -34,13 +34,15 @@ const CurrentWalletBalance = (props) => { ); } - const formattedBalance = Number(props.userWallet.availableBalance).toFixed(2); - + const formattedBalance = props.numberFormat( + props.userWallet.availableBalance, + {style: 'currency', currency: 'USD'}, + ); return ( - {`$${formattedBalance}`} + {`${formattedBalance}`} ); }; From 8871e43ecbd5a03ca89d42c4b6dc7d111f277a0c Mon Sep 17 00:00:00 2001 From: Aman Ansar Date: Sat, 7 Aug 2021 03:56:53 +0530 Subject: [PATCH 12/60] don't allow invalid characters --- src/pages/settings/AddSecondaryLoginPage.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/pages/settings/AddSecondaryLoginPage.js b/src/pages/settings/AddSecondaryLoginPage.js index 3731aa043e3c..414959c19787 100755 --- a/src/pages/settings/AddSecondaryLoginPage.js +++ b/src/pages/settings/AddSecondaryLoginPage.js @@ -71,6 +71,7 @@ class AddSecondaryLoginPage extends Component { }; this.formType = props.route.params.type; this.submitForm = this.submitForm.bind(this); + this.onSecondaryLoginChange = this.onSecondaryLoginChange.bind(this); this.validateForm = this.validateForm.bind(this); this.phoneNumberInputRef = null; @@ -80,6 +81,15 @@ class AddSecondaryLoginPage extends Component { Onyx.merge(ONYXKEYS.USER, {error: ''}); } + onSecondaryLoginChange(login) { + if (this.formType === CONST.LOGIN_TYPE.EMAIL) { + this.setState({login}); + } else if ( + this.formType === CONST.LOGIN_TYPE.PHONE && (/^(\+)(\d)*$/.test(login) || login === '')) { + this.setState({login}); + } + } + /** * Add a secondary login to a user's account */ @@ -135,7 +145,7 @@ class AddSecondaryLoginPage extends Component { ref={el => this.phoneNumberInputRef = el} style={styles.textInput} value={this.state.login} - onChangeText={login => this.setState({login})} + onChangeText={this.onSecondaryLoginChange} keyboardType={this.formType === CONST.LOGIN_TYPE.PHONE ? CONST.KEYBOARD_TYPE.PHONE_PAD : undefined} returnKeyType="done" From 079fe6a740831b57b213d65b656bd7ce28e39a4e Mon Sep 17 00:00:00 2001 From: Aman Ansar Date: Sun, 8 Aug 2021 16:55:29 +0530 Subject: [PATCH 13/60] improvement --- src/pages/settings/AddSecondaryLoginPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/AddSecondaryLoginPage.js b/src/pages/settings/AddSecondaryLoginPage.js index 414959c19787..cec0c83f2f24 100755 --- a/src/pages/settings/AddSecondaryLoginPage.js +++ b/src/pages/settings/AddSecondaryLoginPage.js @@ -85,7 +85,7 @@ class AddSecondaryLoginPage extends Component { if (this.formType === CONST.LOGIN_TYPE.EMAIL) { this.setState({login}); } else if ( - this.formType === CONST.LOGIN_TYPE.PHONE && (/^(\+)(\d)*$/.test(login) || login === '')) { + this.formType === CONST.LOGIN_TYPE.PHONE && (CONST.REGEX.DIGITS_AND_PLUS.test(login) || login === '')) { this.setState({login}); } } From c9adb5f0ee482b915134ce62c5ec85bad7f4f4ed Mon Sep 17 00:00:00 2001 From: Santhoshkumar Sellavel Date: Mon, 9 Aug 2021 22:10:41 +0530 Subject: [PATCH 14/60] es locale formatting for mobile added. --- src/libs/numberFormat/index.native.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/numberFormat/index.native.js b/src/libs/numberFormat/index.native.js index de5366f4faba..f18ac62148f7 100644 --- a/src/libs/numberFormat/index.native.js +++ b/src/libs/numberFormat/index.native.js @@ -4,8 +4,9 @@ import '@formatjs/intl-locale/polyfill'; import '@formatjs/intl-pluralrules/polyfill'; import '@formatjs/intl-numberformat/polyfill'; -// Load en Locale data +// Load en & es Locale data import '@formatjs/intl-numberformat/locale-data/en'; +import '@formatjs/intl-numberformat/locale-data/es'; function numberFormat(locale, number, options) { return new Intl.NumberFormat(locale, options).format(number); From d37f9d41aed9f57138ec157f692a8ee3bb11952e Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 9 Aug 2021 06:47:57 -1000 Subject: [PATCH 15/60] Add red field outlines for the inputs in the IdentityForm --- src/libs/ValidationUtils.js | 11 ++++--- .../ReimbursementAccount/IdentityForm.js | 33 ++++++++++++++++--- .../ReimbursementAccount/RequestorStep.js | 5 --- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/libs/ValidationUtils.js b/src/libs/ValidationUtils.js index 28b3075e45ab..7694952a34bb 100644 --- a/src/libs/ValidationUtils.js +++ b/src/libs/ValidationUtils.js @@ -2,6 +2,7 @@ import moment from 'moment'; import CONST from '../CONST'; import Growl from './Growl'; import {translateLocal} from './translate'; +import {showBankAccountFormValidationError} from './actions/BankAccounts'; /** * Validating that this is a valid address (PO boxes are not allowed) @@ -74,27 +75,27 @@ function isValidSSNLastFour(ssnLast4) { */ function isValidIdentity(identity) { if (!isValidAddress(identity.street)) { - Growl.error(translateLocal('bankAccount.error.address')); + showBankAccountFormValidationError(translateLocal('bankAccount.error.address')); return false; } if (identity.state === '') { - Growl.error(translateLocal('bankAccount.error.addressState')); + showBankAccountFormValidationError(translateLocal('bankAccount.error.addressState')); return false; } if (!isValidZipCode(identity.zipCode)) { - Growl.error(translateLocal('bankAccount.error.zipCode')); + showBankAccountFormValidationError(translateLocal('bankAccount.error.zipCode')); return false; } if (!isValidDate(identity.dob)) { - Growl.error(translateLocal('bankAccount.error.dob')); + showBankAccountFormValidationError(translateLocal('bankAccount.error.dob')); return false; } if (!isValidSSNLastFour(identity.ssnLast4)) { - Growl.error(translateLocal('bankAccount.error.ssnLast4')); + showBankAccountFormValidationError(translateLocal('bankAccount.error.ssnLast4')); return false; } diff --git a/src/pages/ReimbursementAccount/IdentityForm.js b/src/pages/ReimbursementAccount/IdentityForm.js index 59902be1a9de..c36c96b9c578 100644 --- a/src/pages/ReimbursementAccount/IdentityForm.js +++ b/src/pages/ReimbursementAccount/IdentityForm.js @@ -6,6 +6,8 @@ import StatePicker from '../../components/StatePicker'; import TextInputWithLabel from '../../components/TextInputWithLabel'; import styles from '../../styles/styles'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; +import {translateLocal} from '../../libs/translate'; +import {hideBankAccountErrors} from '../../libs/actions/BankAccounts'; const propTypes = { /** Style for wrapping View */ @@ -91,20 +93,37 @@ const IdentityForm = ({ containerStyles={[styles.mt4]} placeholder={translate('common.dateFormat')} value={dob} - onChangeText={val => onFieldChange('dob', val)} + onChangeText={(val) => { + if (error === translateLocal('bankAccount.error.dob')) { + hideBankAccountErrors(); + } + onFieldChange('dob', val); + }} errorText={error} /> onFieldChange('ssnLast4', val)} + onChangeText={(val) => { + if (error === translateLocal('bankAccount.error.ssnLast4')) { + hideBankAccountErrors(); + } + onFieldChange('ssnLast4', val); + }} + errorText={error} /> onFieldChange('street', val)} + onChangeText={(val) => { + if (error === translateLocal('bankAccount.error.address')) { + hideBankAccountErrors(); + } + onFieldChange('street', val); + }} + errorText={error} /> @@ -126,7 +145,13 @@ const IdentityForm = ({ label={translate('common.zip')} containerStyles={[styles.mt4]} value={zipCode} - onChangeText={val => onFieldChange('zipCode', val)} + onChangeText={(val) => { + if (error === translateLocal('bankAccount.error.zipCode')) { + hideBankAccountErrors(); + } + onFieldChange('zipCode', val); + }} + errorText={error} /> ); diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index 9dc5a22337cf..56ef5d56d28a 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -64,11 +64,6 @@ class RequestorStep extends React.Component { zipCode: 'requestorAddressZipCode', }; const fieldName = lodashGet(renamedFields, field, field); - - if (field === 'dob' && this.props.reimbursementAccount.error) { - hideBankAccountErrors(); - } - this.setState({[fieldName]: value}); } From 29c11944b1d5a35ea6d2bb35fbf98a9ee5cabf24 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 9 Aug 2021 06:51:49 -1000 Subject: [PATCH 16/60] Remove unused imports --- src/libs/ValidationUtils.js | 1 - src/pages/ReimbursementAccount/RequestorStep.js | 1 - 2 files changed, 2 deletions(-) diff --git a/src/libs/ValidationUtils.js b/src/libs/ValidationUtils.js index 7694952a34bb..8c6522a040c2 100644 --- a/src/libs/ValidationUtils.js +++ b/src/libs/ValidationUtils.js @@ -1,6 +1,5 @@ import moment from 'moment'; import CONST from '../CONST'; -import Growl from './Growl'; import {translateLocal} from './translate'; import {showBankAccountFormValidationError} from './actions/BankAccounts'; diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index 56ef5d56d28a..7ad9cd796235 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -13,7 +13,6 @@ import CheckboxWithLabel from '../../components/CheckboxWithLabel'; import Text from '../../components/Text'; import { goToWithdrawalAccountSetupStep, - hideBankAccountErrors, setupWithdrawalAccount, } from '../../libs/actions/BankAccounts'; import Button from '../../components/Button'; From 46cc705c846478a2a0f85a05951e2efaba7812d3 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 9 Aug 2021 07:15:36 -1000 Subject: [PATCH 17/60] Fix form validation --- src/pages/ReimbursementAccount/BeneficialOwnersStep.js | 4 +--- src/pages/ReimbursementAccount/IdentityForm.js | 9 +++++---- src/pages/ReimbursementAccount/RequestorStep.js | 1 + 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pages/ReimbursementAccount/BeneficialOwnersStep.js b/src/pages/ReimbursementAccount/BeneficialOwnersStep.js index fec43d64b986..8a92ed2eb0cf 100644 --- a/src/pages/ReimbursementAccount/BeneficialOwnersStep.js +++ b/src/pages/ReimbursementAccount/BeneficialOwnersStep.js @@ -173,9 +173,6 @@ class BeneficialOwnersStep extends React.Component { onFieldChange={(fieldName, value) => this.setState((prevState) => { const beneficialOwners = [...prevState.beneficialOwners]; beneficialOwners[index][fieldName] = value; - if (fieldName === 'dob' && this.props.reimbursementAccount.error) { - hideBankAccountErrors(); - } return {beneficialOwners}; })} values={{ @@ -188,6 +185,7 @@ class BeneficialOwnersStep extends React.Component { dob: owner.dob || '', ssnLast4: owner.ssnLast4 || '', }} + error={this.props.reimbursementAccount.error} /> {this.state.beneficialOwners.length > 1 && ( this.removeBeneficialOwner(owner)}> diff --git a/src/pages/ReimbursementAccount/IdentityForm.js b/src/pages/ReimbursementAccount/IdentityForm.js index c36c96b9c578..0ce065559b28 100644 --- a/src/pages/ReimbursementAccount/IdentityForm.js +++ b/src/pages/ReimbursementAccount/IdentityForm.js @@ -70,6 +70,7 @@ const IdentityForm = ({ const { firstName, lastName, street, city, state, zipCode, dob, ssnLast4, } = values; + console.log(">>>>", error); return ( @@ -99,7 +100,7 @@ const IdentityForm = ({ } onFieldChange('dob', val); }} - errorText={error} + errorText={error === translateLocal('bankAccount.error.dob') ? error : ''} /> @@ -151,7 +152,7 @@ const IdentityForm = ({ } onFieldChange('zipCode', val); }} - errorText={error} + errorText={error === translateLocal('bankAccount.error.zipCode') ? error : ''} /> ); diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index 7ad9cd796235..122b5825acbf 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -133,6 +133,7 @@ class RequestorStep extends React.Component { dob: this.state.dob, ssnLast4: this.state.ssnLast4, }} + error={this.props.reimbursementAccount.error} /> Date: Mon, 9 Aug 2021 07:18:23 -1000 Subject: [PATCH 18/60] Remove unused imports --- src/pages/ReimbursementAccount/BeneficialOwnersStep.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/BeneficialOwnersStep.js b/src/pages/ReimbursementAccount/BeneficialOwnersStep.js index 8a92ed2eb0cf..e86f22f44bf4 100644 --- a/src/pages/ReimbursementAccount/BeneficialOwnersStep.js +++ b/src/pages/ReimbursementAccount/BeneficialOwnersStep.js @@ -14,7 +14,6 @@ import FixedFooter from '../../components/FixedFooter'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import { goToWithdrawalAccountSetupStep, - hideBankAccountErrors, setupWithdrawalAccount, } from '../../libs/actions/BankAccounts'; import Navigation from '../../libs/Navigation/Navigation'; From 79856ee586ba629b3dc212fa99c8b81ba7cde330 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 9 Aug 2021 07:21:52 -1000 Subject: [PATCH 19/60] remove debug --- src/pages/ReimbursementAccount/IdentityForm.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/IdentityForm.js b/src/pages/ReimbursementAccount/IdentityForm.js index 0ce065559b28..cb60f03b8c28 100644 --- a/src/pages/ReimbursementAccount/IdentityForm.js +++ b/src/pages/ReimbursementAccount/IdentityForm.js @@ -70,7 +70,6 @@ const IdentityForm = ({ const { firstName, lastName, street, city, state, zipCode, dob, ssnLast4, } = values; - console.log(">>>>", error); return ( From 02cc7465949c792d634880875ef6f0d51a0aa703 Mon Sep 17 00:00:00 2001 From: Clem Dal Palu Date: Tue, 10 Aug 2021 11:30:13 +0200 Subject: [PATCH 20/60] Fix the text style for Payment Methods --- src/pages/settings/Payments/PaymentsPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Payments/PaymentsPage.js b/src/pages/settings/Payments/PaymentsPage.js index 70296695c111..0958973677e8 100644 --- a/src/pages/settings/Payments/PaymentsPage.js +++ b/src/pages/settings/Payments/PaymentsPage.js @@ -105,7 +105,7 @@ class PaymentsPage extends React.Component { {this.props.translate('paymentsPage.paymentMethodsTitle')} From bad9ca7a94ce30e55f77caee5c26090e48e199cd Mon Sep 17 00:00:00 2001 From: Santhoshkumar Sellavel Date: Wed, 11 Aug 2021 00:34:31 +0530 Subject: [PATCH 21/60] Updated Add Phone/Email Style in Profile Page --- src/pages/settings/Profile/LoginField.js | 26 +++++++++--------------- src/styles/utilities/spacing.js | 8 ++++++++ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/pages/settings/Profile/LoginField.js b/src/pages/settings/Profile/LoginField.js index bd2d336cf529..12539a1ae416 100755 --- a/src/pages/settings/Profile/LoginField.js +++ b/src/pages/settings/Profile/LoginField.js @@ -1,5 +1,5 @@ import React, {Component} from 'react'; -import {View, Pressable} from 'react-native'; +import {View} from 'react-native'; import PropTypes from 'prop-types'; import Text from '../../../components/Text'; import styles from '../../../styles/styles'; @@ -12,6 +12,7 @@ import Navigation from '../../../libs/Navigation/Navigation'; import {resendValidateCode} from '../../../libs/actions/User'; import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; import Button from '../../../components/Button'; +import MenuItem from '../../../components/MenuItem'; const propTypes = { /** Label to display on login form */ @@ -85,21 +86,14 @@ class LoginField extends Component { {this.props.label} {!this.props.login.partnerUserID ? ( - Navigation.navigate(ROUTES.getSettingsAddLoginRoute(this.props.type))} - > - - - - - - - {`${this.props.translate('common.add')} ${this.props.label}`} - - - - + + Navigation.navigate(ROUTES.getSettingsAddLoginRoute(this.props.type))} + /> + ) : ( diff --git a/src/styles/utilities/spacing.js b/src/styles/utilities/spacing.js index 32a0abb4e8ad..a376ad817217 100644 --- a/src/styles/utilities/spacing.js +++ b/src/styles/utilities/spacing.js @@ -73,6 +73,10 @@ export default { marginRight: 20, }, + mrn5: { + marginRight: -20, + }, + ml1: { marginLeft: 4, }, @@ -93,6 +97,10 @@ export default { marginLeft: 20, }, + mln5: { + marginLeft: -20, + }, + mt1: { marginTop: 4, }, From 85ba3658388fc482371d291a41bacc692ac321d8 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Wed, 11 Aug 2021 03:53:49 +0530 Subject: [PATCH 22/60] handle Undefined IOU Id on IOUdetails page --- src/languages/en.js | 3 ++- src/languages/es.js | 3 ++- src/libs/actions/Report.js | 8 +++++++- src/pages/iou/IOUDetailsModal.js | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 39fafd4d7da9..3405e443693b 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -336,8 +336,9 @@ export default { createGroup: 'Create Group', }, notFound: { - chatYouLookingForCannotBeFound: 'The chat you are looking for cannot be found.', + chatYouLookingForCannotBeFound: 'The chat you are looking for can not be found.', getMeOutOfHere: 'Get me out of here', + iouReportNotFound: 'Payment details you are looking for can not be found.', }, setPasswordPage: { enterPassword: 'Enter a password', diff --git a/src/languages/es.js b/src/languages/es.js index c04745f36511..8e982e0fa87a 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -336,8 +336,9 @@ export default { createGroup: 'Crear Grupo', }, notFound: { - chatYouLookingForCannotBeFound: 'No se pudo encontrar el chat que estabas buscando.', + chatYouLookingForCannotBeFound: 'No se puede encontrar el chat que estás buscando.', getMeOutOfHere: 'Sácame de aquí', + iouReportNotFound: 'No se pueden encontrar los detalles de pago que está buscando.', }, setPasswordPage: { enterPassword: 'Escribe una contraseña', diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 9976e32ca4ab..da0a72dae33d 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -461,11 +461,17 @@ function removeOptimisticActions(reportID) { * * @param {Number} iouReportID - ID of the report we are fetching * @param {Number} chatReportID - associated chatReportID, set as an iouReport field + * @param {Boolean} [shouldRedirectIfEmpty=false] - Whether to redirect to Active Report Screen if IOUReport is empty * @returns {Promise} */ -function fetchIOUReportByID(iouReportID, chatReportID) { +function fetchIOUReportByID(iouReportID, chatReportID, shouldRedirectIfEmpty = false) { return fetchIOUReport(iouReportID, chatReportID) .then((iouReportObject) => { + if (!iouReportObject && shouldRedirectIfEmpty) { + Growl.error(translateLocal('notFound.iouReportNotFound')); + Navigation.navigate(ROUTES.REPORT); + return; + } setLocalIOUReportData(iouReportObject); return iouReportObject; }); diff --git a/src/pages/iou/IOUDetailsModal.js b/src/pages/iou/IOUDetailsModal.js index 17be9bc16467..822149b4a5d3 100644 --- a/src/pages/iou/IOUDetailsModal.js +++ b/src/pages/iou/IOUDetailsModal.js @@ -107,7 +107,7 @@ class IOUDetailsModal extends Component { componentDidMount() { this.isComponentMounted = true; - fetchIOUReportByID(this.props.route.params.iouReportID, this.props.route.params.chatReportID); + fetchIOUReportByID(this.props.route.params.iouReportID, this.props.route.params.chatReportID, true); this.addVenmoPaymentOptionIfAvailable(); this.addExpensifyPaymentOptionIfAvailable(); } From 47d99be7e05c1ab5058359e92364eb9ade212b36 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 10 Aug 2021 16:53:32 -1000 Subject: [PATCH 23/60] Reorganize ReportScreen --- src/pages/home/ReportScreen.js | 56 +++++++++++++++++++++++------ src/pages/home/report/ReportView.js | 56 ----------------------------- 2 files changed, 46 insertions(+), 66 deletions(-) delete mode 100644 src/pages/home/report/ReportView.js diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 13568cdbc257..c782cb47bf72 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -1,17 +1,23 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; import PropTypes from 'prop-types'; +import {Keyboard, View} from 'react-native'; import _ from 'underscore'; import styles from '../../styles/styles'; -import ReportView from './report/ReportView'; import ScreenWrapper from '../../components/ScreenWrapper'; import HeaderView from './HeaderView'; import Navigation from '../../libs/Navigation/Navigation'; import ROUTES from '../../ROUTES'; -import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; -import {handleInaccessibleReport, updateCurrentlyViewedReportID} from '../../libs/actions/Report'; +import {handleInaccessibleReport, updateCurrentlyViewedReportID, addAction} from '../../libs/actions/Report'; import ONYXKEYS from '../../ONYXKEYS'; +import ReportActionsView from './report/ReportActionsView'; +import ReportActionCompose from './report/ReportActionCompose'; +import KeyboardSpacer from '../../components/KeyboardSpacer'; +import SwipeableView from '../../components/SwipeableView'; +import CONST from '../../CONST'; +import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; + const propTypes = { /** Navigation route context info provided by react navigation */ route: PropTypes.shape({ @@ -24,16 +30,26 @@ const propTypes = { /** Tells us if the sidebar has rendered */ isSidebarLoaded: PropTypes.bool, + + /** Whether or not to show the Compose Input */ + session: PropTypes.shape({ + shouldShowComposeInput: PropTypes.bool, + }), }; const defaultProps = { isSidebarLoaded: false, + session: { + shouldShowComposeInput: true, + }, }; class ReportScreen extends React.Component { constructor(props) { super(props); + this.onSubmitComment = this.onSubmitComment.bind(this); + this.state = { isLoading: true, }; @@ -56,6 +72,13 @@ class ReportScreen extends React.Component { clearTimeout(this.loadingTimerId); } + /** + * @param {String} text + */ + onSubmitComment(text) { + addAction(this.getReportID(), text); + } + /** * Get the currently viewed report ID as number * @@ -76,13 +99,12 @@ class ReportScreen extends React.Component { } /** - * Configures a small loading transition of fixed time and proceeds with rendering available data + * Configures a small loading transition and proceeds with rendering available data */ prepareTransition() { this.setState({isLoading: true}); - clearTimeout(this.loadingTimerId); - this.loadingTimerId = setTimeout(() => this.setState({isLoading: false}), 150); + this.loadingTimerId = setTimeout(() => this.setState({isLoading: false}), 0); } /** @@ -102,16 +124,27 @@ class ReportScreen extends React.Component { return null; } + const reportID = this.getReportID(); return ( Navigation.navigate(ROUTES.HOME)} /> - - - {!this.shouldShowLoader() && } + + + {!this.shouldShowLoader() && } + {this.props.session.shouldShowComposeInput && ( + Keyboard.dismiss()}> + + + )} + + ); } @@ -124,4 +157,7 @@ export default withOnyx({ isSidebarLoaded: { key: ONYXKEYS.IS_SIDEBAR_LOADED, }, + session: { + key: ONYXKEYS.SESSION, + }, })(ReportScreen); diff --git a/src/pages/home/report/ReportView.js b/src/pages/home/report/ReportView.js deleted file mode 100644 index 1eb4ea57589a..000000000000 --- a/src/pages/home/report/ReportView.js +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react'; -import {Keyboard, View} from 'react-native'; -import PropTypes from 'prop-types'; -import {withOnyx} from 'react-native-onyx'; -import ReportActionsView from './ReportActionsView'; -import ReportActionCompose from './ReportActionCompose'; -import {addAction} from '../../../libs/actions/Report'; -import KeyboardSpacer from '../../../components/KeyboardSpacer'; -import styles from '../../../styles/styles'; -import SwipeableView from '../../../components/SwipeableView'; -import ONYXKEYS from '../../../ONYXKEYS'; -import CONST from '../../../CONST'; - -const propTypes = { - /** The ID of the report the selected report */ - reportID: PropTypes.number.isRequired, - - /* Onyx Keys */ - - /** Whether or not to show the Compose Input */ - session: PropTypes.shape({ - shouldShowComposeInput: PropTypes.bool, - }), -}; - -const defaultProps = { - session: { - shouldShowComposeInput: true, - }, -}; - -const ReportView = ({reportID, session}) => ( - - - - {session.shouldShowComposeInput && ( - Keyboard.dismiss()}> - addAction(reportID, text)} - reportID={reportID} - /> - - )} - - -); - -ReportView.propTypes = propTypes; -ReportView.defaultProps = defaultProps; -ReportView.displayName = 'ReportView'; - -export default withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, -})(ReportView); From 9bfc91daadf552970885017ada6d9e3d9bded489 Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 11 Aug 2021 10:29:48 +0200 Subject: [PATCH 24/60] Add sentence about requesting increased compensation --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 30535f60b0f5..18d11f260446 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ If you are hired for an Upwork job and have any job-specific questions, please a If you've found a vulnerability, please email security@expensify.com with the subject `Vulnerability Report` instead of creating an issue. ## Payment for Contributions -We hire and pay external contributors via Upwork.com. If you'd like to be paid for contributing, please create an Upwork account and apply for a job in the [Upwork issue list](https://www.upwork.com/ab/jobs/search/?q=Expensify%20React%20Native&sort=recency&user_location_match=2). Payment for your contributions will be made no less than 7 days after the pull request is merged to allow for regression testing. We hire one contributor for each Upwork job. New contributors are limited to working on one job at a time, however experienced contributors may work on numerous jobs simultaneously. If you have not received payment after 8 days of the PR being deployed to production, please email contributors@expensify.com referencing the GH issue and your GH handle. +We hire and pay external contributors via Upwork.com. If you'd like to be paid for contributing, please create an Upwork account and apply for a job in the [Upwork issue list](https://www.upwork.com/ab/jobs/search/?q=Expensify%20React%20Native&sort=recency&user_location_match=2). If you think your compensation should be increased for a specific job, you can request a reevaluation by commenting in the Github issue where the Upwork job was posted. Payment for your contributions will be made no less than 7 days after the pull request is merged to allow for regression testing. We hire one contributor for each Upwork job. New contributors are limited to working on one job at a time, however experienced contributors may work on numerous jobs simultaneously. If you have not received payment after 8 days of the PR being deployed to production, please email contributors@expensify.com referencing the GH issue and your GH handle. ## Finding Jobs There are two ways you can find a job that you can contribute to: From ddc4dd80056b617395952ce741fd7ef46624b3bf Mon Sep 17 00:00:00 2001 From: Alex Beaman Date: Wed, 11 Aug 2021 10:30:13 +0200 Subject: [PATCH 25/60] Fix section title --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 18d11f260446..a6e9d69d6912 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -87,7 +87,7 @@ In this scenario, it’s possible that you found a bug or enhancement that we ha 10. An Expensify engineer will be assigned to your pull request automatically to review. 11. Provide daily updates until reaching completion of your PR. -#### Submit your pull request for final request +#### Submit your pull request for final review 12. When you are ready to submit your pull request for final review, make sure the following checks pass: 1. CLA - You must sign our [Contributor License Agreement](https://github.com/Expensify/Expensify.cash/blob/main/CLA.md) by following the CLA bot instructions that will be posted on your PR 2. Tests - All tests must pass before a merge of a pull request From e2a72bfbf488739df6007047a71dd07244a199ec Mon Sep 17 00:00:00 2001 From: Manan Jadhav Date: Wed, 11 Aug 2021 22:33:41 +0530 Subject: [PATCH 26/60] fix(invalid-props-avatar): Updated proptypes for Avatar containerStyles --- src/components/Avatar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Avatar.js b/src/components/Avatar.js index c3e64dbac2b2..aa56b6262d28 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -12,7 +12,7 @@ const propTypes = { imageStyles: PropTypes.arrayOf(PropTypes.object), /** Extra styles to pass to View wrapper */ - containerStyles: PropTypes.arrayOf(PropTypes.object), + containerStyles: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]), /** Set the size of Avatar */ size: PropTypes.oneOf(['default', 'small']), From d4e264a37bad63e656bd54b6c6996d15341d6540 Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 11 Aug 2021 11:28:30 -0600 Subject: [PATCH 27/60] Deploy iOS to production when deploying other platforms --- .github/workflows/platformDeploy.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml index 3c85ac4a1d01..1e504cf72794 100644 --- a/.github/workflows/platformDeploy.yml +++ b/.github/workflows/platformDeploy.yml @@ -208,10 +208,9 @@ jobs: APPLE_DEMO_EMAIL: ${{ secrets.APPLE_DEMO_EMAIL }} APPLE_DEMO_PASSWORD: ${{ secrets.APPLE_DEMO_PASSWORD }} - # TODO: uncomment when we want to release iOS to production + - name: Run Fastlane for App Store release - # if: ${{ env.SHOULD_DEPLOY_PRODUCTION == 'true' }} - if: ${{ env.SHOULD_DEPLOY_PRODUCTION == 'true' && 'false' == 'true' }} + if: ${{ env.SHOULD_DEPLOY_PRODUCTION == 'true' }} run: bundle exec fastlane ios production env: VERSION: ${{ env.NEW_IOS_VERSION }} From 4e0b97ea35a2b6108d1ab8fbe50ba40a1828111b Mon Sep 17 00:00:00 2001 From: andrew Date: Wed, 11 Aug 2021 11:33:57 -0600 Subject: [PATCH 28/60] Remove newline --- .github/workflows/platformDeploy.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml index 1e504cf72794..b70cf7b1667d 100644 --- a/.github/workflows/platformDeploy.yml +++ b/.github/workflows/platformDeploy.yml @@ -208,7 +208,6 @@ jobs: APPLE_DEMO_EMAIL: ${{ secrets.APPLE_DEMO_EMAIL }} APPLE_DEMO_PASSWORD: ${{ secrets.APPLE_DEMO_PASSWORD }} - - name: Run Fastlane for App Store release if: ${{ env.SHOULD_DEPLOY_PRODUCTION == 'true' }} run: bundle exec fastlane ios production From 1b68a5f0d320665226547400f2b5e96d56825e03 Mon Sep 17 00:00:00 2001 From: "Jules Sam. Randolph" Date: Sat, 7 Aug 2021 12:10:57 -0300 Subject: [PATCH 29/60] perf: use explicit composite architecture for RenderHTML component This allows to avoid the cost of instantiating a new engine for each HTML snippet, see https://git.io/JRcZb fix #4123 --- src/App.js | 2 + .../BaseHTMLEngineProvider.js} | 59 +++++++++++-------- .../htmlEnginePropTypes.js} | 6 +- src/components/HTMLEngineProvider/index.js | 20 +++++++ .../HTMLEngineProvider/index.native.js | 15 +++++ src/components/RenderHTML.js | 27 +++++++++ src/components/RenderHTML/index.js | 22 ------- src/components/RenderHTML/index.native.js | 19 ------ .../home/report/ReportActionItemFragment.js | 1 - 9 files changed, 100 insertions(+), 71 deletions(-) rename src/components/{RenderHTML/BaseRenderHTML.js => HTMLEngineProvider/BaseHTMLEngineProvider.js} (83%) rename src/components/{RenderHTML/renderHTMLPropTypes.js => HTMLEngineProvider/htmlEnginePropTypes.js} (57%) create mode 100755 src/components/HTMLEngineProvider/index.js create mode 100755 src/components/HTMLEngineProvider/index.native.js create mode 100644 src/components/RenderHTML.js delete mode 100755 src/components/RenderHTML/index.js delete mode 100755 src/components/RenderHTML/index.native.js diff --git a/src/App.js b/src/App.js index 269af1f82456..c24c06fc082e 100644 --- a/src/App.js +++ b/src/App.js @@ -7,6 +7,7 @@ import ErrorBoundary from './components/ErrorBoundary'; import Expensify from './Expensify'; import {LocaleContextProvider} from './components/withLocalize'; import OnyxProvider from './components/OnyxProvider'; +import HTMLEngineProvider from './components/HTMLEngineProvider'; import ComposeProviders from './components/ComposeProviders'; LogBox.ignoreLogs([ @@ -25,6 +26,7 @@ const App = () => ( OnyxProvider, SafeAreaProvider, LocaleContextProvider, + HTMLEngineProvider, ]} > diff --git a/src/components/RenderHTML/BaseRenderHTML.js b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js similarity index 83% rename from src/components/RenderHTML/BaseRenderHTML.js rename to src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js index 42058198ced7..4259d3e4de02 100755 --- a/src/components/RenderHTML/BaseRenderHTML.js +++ b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js @@ -1,8 +1,10 @@ /* eslint-disable react/prop-types */ import _ from 'underscore'; -import React from 'react'; -import {useWindowDimensions, TouchableOpacity} from 'react-native'; -import HTML, { +import React, {useMemo} from 'react'; +import {TouchableOpacity} from 'react-native'; +import { + TRenderEngineProvider, + RenderHTMLConfigProvider, defaultHTMLElementModels, TNodeChildrenRenderer, splitBoxModelStyle, @@ -18,20 +20,16 @@ import ThumbnailImage from '../ThumbnailImage'; import variables from '../../styles/variables'; import themeColors from '../../styles/themes/default'; import Text from '../Text'; -import { - propTypes as renderHTMLPropTypes, - defaultProps as renderHTMLDefaultProps, -} from './renderHTMLPropTypes'; const propTypes = { /** Whether text elements should be selectable */ textSelectable: PropTypes.bool, - ...renderHTMLPropTypes, + children: PropTypes.node, }; const defaultProps = { textSelectable: false, - ...renderHTMLDefaultProps, + children: null, }; const MAX_IMG_DIMENSIONS = 512; @@ -221,31 +219,40 @@ const renderersProps = { }, }; -const BaseRenderHTML = ({html, debug, textSelectable}) => { - const {width} = useWindowDimensions(); - const containerWidth = width * 0.8; +const defaultViewProps = {style: {alignItems: 'flex-start'}}; + +// We are using the explicit composite architecture for performance gains. +// Configuration for RenderHTML is handled in a top-level component providing +// context to RenderHTMLSource components. See https://git.io/JRcZb +// Beware that each prop should be referentialy stable between renders to avoid +// costly invalidations and commits. +const BaseHTMLEngineProvider = ({children, textSelectable}) => { + // We need to memoize this prop to make it referentially stable. + const defaultTextProps = useMemo(() => ({selectable: textSelectable}), [textSelectable]); return ( - + > + + {children} + + ); }; -BaseRenderHTML.displayName = 'BaseRenderHTML'; -BaseRenderHTML.propTypes = propTypes; -BaseRenderHTML.defaultProps = defaultProps; +BaseHTMLEngineProvider.displayName = 'BaseHTMLEngineProvider'; +BaseHTMLEngineProvider.propTypes = propTypes; +BaseHTMLEngineProvider.defaultProps = defaultProps; -export default BaseRenderHTML; +export default BaseHTMLEngineProvider; diff --git a/src/components/RenderHTML/renderHTMLPropTypes.js b/src/components/HTMLEngineProvider/htmlEnginePropTypes.js similarity index 57% rename from src/components/RenderHTML/renderHTMLPropTypes.js rename to src/components/HTMLEngineProvider/htmlEnginePropTypes.js index 58032059e4b9..6c8537c8d228 100644 --- a/src/components/RenderHTML/renderHTMLPropTypes.js +++ b/src/components/HTMLEngineProvider/htmlEnginePropTypes.js @@ -1,14 +1,14 @@ import PropTypes from 'prop-types'; const propTypes = { - /** HTML string to render */ - html: PropTypes.string.isRequired, + children: PropTypes.node, - /** Optional debug flag */ + /** Optional debug flag. Prints the TRT in the console when true. */ debug: PropTypes.bool, }; const defaultProps = { + children: null, debug: false, }; diff --git a/src/components/HTMLEngineProvider/index.js b/src/components/HTMLEngineProvider/index.js new file mode 100755 index 000000000000..a96bccad3c2e --- /dev/null +++ b/src/components/HTMLEngineProvider/index.js @@ -0,0 +1,20 @@ +import React from 'react'; +import BaseHTMLEngineProvider from './BaseHTMLEngineProvider'; +import {defaultProps, propTypes} from './htmlEnginePropTypes'; +import withWindowDimensions from '../withWindowDimensions'; +import canUseTouchScreen from '../../libs/canUseTouchscreen'; + +const HTMLEngineProvider = ({isSmallScreenWidth, debug, children}) => ( + + {children} + +); + +HTMLEngineProvider.displayName = 'HTMLEngineProvider'; +HTMLEngineProvider.propTypes = propTypes; +HTMLEngineProvider.defaultProps = defaultProps; + +export default withWindowDimensions(HTMLEngineProvider); diff --git a/src/components/HTMLEngineProvider/index.native.js b/src/components/HTMLEngineProvider/index.native.js new file mode 100755 index 000000000000..b524495e7084 --- /dev/null +++ b/src/components/HTMLEngineProvider/index.native.js @@ -0,0 +1,15 @@ +import React from 'react'; +import BaseHTMLEngineProvider from './BaseHTMLEngineProvider'; +import {propTypes, defaultProps} from './htmlEnginePropTypes'; + +const HTMLEngineProvider = ({debug, children}) => ( + + {children} + +); + +HTMLEngineProvider.displayName = 'HTMLEngineProvider'; +HTMLEngineProvider.propTypes = propTypes; +HTMLEngineProvider.defaultProps = defaultProps; + +export default HTMLEngineProvider; diff --git a/src/components/RenderHTML.js b/src/components/RenderHTML.js new file mode 100644 index 000000000000..74f8a888b2e0 --- /dev/null +++ b/src/components/RenderHTML.js @@ -0,0 +1,27 @@ +import React from 'react'; +import {useWindowDimensions} from 'react-native'; +import PropTypes from 'prop-types'; +import {RenderHTMLSource} from 'react-native-render-html'; + +// We are using the explicit composite architecture for performance gains. +// Configuration for RenderHTML is handled in a top-level component providing +// context to RenderHTMLSource components. See https://git.io/JRcZb +// The provider is available at src/components/HTMLEngineProvider/ +const RenderHTML = ({html}) => { + const {width} = useWindowDimensions(); + return ( + + ); +}; + +RenderHTML.displayName = 'RenderHTML'; +RenderHTML.propTypes = { + /** HTML string to render */ + html: PropTypes.string.isRequired, +}; +RenderHTML.defaultProps = {}; + +export default RenderHTML; diff --git a/src/components/RenderHTML/index.js b/src/components/RenderHTML/index.js deleted file mode 100755 index 405d2621154b..000000000000 --- a/src/components/RenderHTML/index.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import BaseRenderHTML from './BaseRenderHTML'; -import withWindowDimensions from '../withWindowDimensions'; -import { - propTypes, - defaultProps, -} from './renderHTMLPropTypes'; -import canUseTouchScreen from '../../libs/canUseTouchscreen'; - -const RenderHTML = ({html, debug, isSmallScreenWidth}) => ( - -); - -RenderHTML.displayName = 'RenderHTML'; -RenderHTML.propTypes = propTypes; -RenderHTML.defaultProps = defaultProps; - -export default withWindowDimensions(RenderHTML); diff --git a/src/components/RenderHTML/index.native.js b/src/components/RenderHTML/index.native.js deleted file mode 100755 index 99048ea86c37..000000000000 --- a/src/components/RenderHTML/index.native.js +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import BaseRenderHTML from './BaseRenderHTML'; -import { - propTypes, - defaultProps, -} from './renderHTMLPropTypes'; - -const RenderHTML = ({html, debug}) => ( - -); - -RenderHTML.displayName = 'RenderHTML'; -RenderHTML.propTypes = propTypes; -RenderHTML.defaultProps = defaultProps; - -export default RenderHTML; diff --git a/src/pages/home/report/ReportActionItemFragment.js b/src/pages/home/report/ReportActionItemFragment.js index 15241841116b..218b4f4c10b8 100644 --- a/src/pages/home/report/ReportActionItemFragment.js +++ b/src/pages/home/report/ReportActionItemFragment.js @@ -62,7 +62,6 @@ class ReportActionItemFragment extends React.PureComponent { ? ( ' : '')} - debug={false} /> ) : ( Date: Sat, 7 Aug 2021 12:13:38 -0300 Subject: [PATCH 30/60] fix: custom tags () should never be self-closing Self-closing tags are only allowed for void elements in HTML5. Otherwise, the required behavior for parsers is to ignore the slash and consider the expression as a tag opening. This will lead to bugs with htmlparser2 if `` was followed by other tags, where those tags would be parsed as children of `` instead of siblings. --- src/pages/home/report/ReportActionItemFragment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionItemFragment.js b/src/pages/home/report/ReportActionItemFragment.js index 218b4f4c10b8..5a69a14c263c 100644 --- a/src/pages/home/report/ReportActionItemFragment.js +++ b/src/pages/home/report/ReportActionItemFragment.js @@ -61,7 +61,7 @@ class ReportActionItemFragment extends React.PureComponent { return fragment.html !== fragment.text ? ( ' : '')} + html={fragment.html + (fragment.isEdited ? '' : '')} /> ) : ( Date: Wed, 11 Aug 2021 12:27:08 -0700 Subject: [PATCH 31/60] copy update --- src/pages/ReimbursementAccount/CompanyStep.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index 5260a4ff1306..911541f35f87 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -257,7 +257,7 @@ class CompanyStep extends React.Component { this.setState({isConfirmModalOpen: false})} prompt="Please double check any highlighted fields and try again." isVisible={this.state.isConfirmModalOpen} From e6d33ee10d5023a57c992c196d8fa52c7e804bc2 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Thu, 12 Aug 2021 02:38:58 +0530 Subject: [PATCH 32/60] added new marker --- src/libs/UnreadIndicatorUpdater/index.js | 2 + .../updateUnread/index.desktop.js | 1 + .../updateUnread/index.website.js | 2 + src/pages/home/report/MarkerBadge.js | 128 ++++++++++++++++++ src/pages/home/report/ReportActionsView.js | 40 ++++++ src/pages/home/report/ReportView.js | 2 +- 6 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 src/pages/home/report/MarkerBadge.js diff --git a/src/libs/UnreadIndicatorUpdater/index.js b/src/libs/UnreadIndicatorUpdater/index.js index 00547ec957d5..09aa8bf90d27 100644 --- a/src/libs/UnreadIndicatorUpdater/index.js +++ b/src/libs/UnreadIndicatorUpdater/index.js @@ -30,6 +30,7 @@ let connectionID; * the title and unread count indicators */ function listenForReportChanges() { + console.debug('count listner'); connectionID = Onyx.connect({ key: ONYXKEYS.COLLECTION.REPORT, callback: (report) => { @@ -48,6 +49,7 @@ function listenForReportChanges() { } else { unreadActionCounts[report.reportID] = report.unreadActionCount || 0; } + console.debug('count caller', report.reportID, report.unreadActionCount); throttledUpdatePageTitleAndUnreadCount(); }, }); diff --git a/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js b/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js index 34176ff9b7bd..eb4d14e29462 100644 --- a/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js +++ b/src/libs/UnreadIndicatorUpdater/updateUnread/index.desktop.js @@ -8,6 +8,7 @@ const ipcRenderer = window.require('electron').ipcRenderer; * @param {Number} totalCount */ function updateUnread(totalCount) { + console.debug('message count'); // Ask the main Electron process to update our // badge count in the Mac OS dock icon ipcRenderer.send(ELECTRON_EVENTS.REQUEST_UPDATE_BADGE_COUNT, totalCount); diff --git a/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js b/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js index 75f6d3f31d08..b5d2a1d1aff2 100644 --- a/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js +++ b/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js @@ -9,6 +9,8 @@ import CONFIG from '../../../CONFIG'; * @param {Number} totalCount */ function updateUnread(totalCount) { + console.debug('message count'); + const hasUnread = totalCount !== 0; document.title = hasUnread ? `(${totalCount}) ${CONFIG.SITE_TITLE}` : CONFIG.SITE_TITLE; document.getElementById('favicon').href = hasUnread ? CONFIG.FAVICON.UNREAD : CONFIG.FAVICON.DEFAULT; diff --git a/src/pages/home/report/MarkerBadge.js b/src/pages/home/report/MarkerBadge.js new file mode 100644 index 000000000000..56294cc5e466 --- /dev/null +++ b/src/pages/home/report/MarkerBadge.js @@ -0,0 +1,128 @@ +import React, {PureComponent} from 'react'; +import {Animated, Text, View} from 'react-native'; +import PropTypes from 'prop-types'; +import styles from '../../../styles/styles'; +import Button from '../../../components/Button'; +import Icon from '../../../components/Icon'; +import {Close, DownArrow} from '../../../components/Icon/Expensicons'; +import themeColors from '../../../styles/themes/default'; + +const MARKER_NOT_ACTIVE_TRANSLATE_Y = -30; +const MARKER_ACTIVE_TRANSLATE_Y = 10; +const propTypes = { + count: PropTypes.number, + active: PropTypes.bool, + onClose: PropTypes.func, + onClick: PropTypes.func, +}; +const defaultProps = { + count: 0, + active: false, + onClose: () => {}, + onClick: () => {}, +}; +class Markerbadge extends PureComponent { + constructor(props) { + super(props); + this.translateY = new Animated.Value(MARKER_NOT_ACTIVE_TRANSLATE_Y); + this.show = this.show.bind(this); + this.hide = this.hide.bind(this); + } + + componentDidUpdate() { + if (this.props.active && this.props.count > 0) { + this.show(); + } else { + this.hide(); + } + } + + show() { + Animated.spring(this.translateY, { + toValue: MARKER_ACTIVE_TRANSLATE_Y, + duration: 80, + useNativeDriver: true, + }).start(); + } + + hide() { + Animated.spring(this.translateY, { + toValue: MARKER_NOT_ACTIVE_TRANSLATE_Y, + duration: 80, + useNativeDriver: true, + }).start(); + } + + render() { + return ( + + +