From 7f05ffbb848d13b04e8a0bdaef1e116a32d2b99c Mon Sep 17 00:00:00 2001 From: pROFESOR11 Date: Fri, 3 Sep 2021 11:23:49 +0300 Subject: [PATCH 001/289] override default anchor style with parent style --- src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js index 5dca7c8b00fe..e754febe7a05 100755 --- a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js +++ b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js @@ -70,6 +70,7 @@ function AnchorRenderer({tnode, key, style}) { // An auth token is needed to download Expensify chat attachments const isAttachment = Boolean(htmlAttribs['data-expensify-source']); const fileName = lodashGet(tnode, 'domNode.children[0].data', ''); + const parentStyle = lodashGet(tnode, 'parent.styles.nativeTextRet', {}); return ( From 80735c2a1d0f6670fbf6b5761252c2fa30fc5dd3 Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Fri, 3 Sep 2021 15:26:26 -0700 Subject: [PATCH 002/289] Highlight all errors company step --- src/languages/en.js | 3 + src/languages/es.js | 3 + src/pages/ReimbursementAccount/CompanyStep.js | 179 +++++++++--------- 3 files changed, 95 insertions(+), 90 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index efcb20b5b9cc..6f1f8e290519 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -385,6 +385,9 @@ export default { taxID: 'Please enter a valid Tax ID Number', website: 'Please enter a valid website', zipCode: 'Please enter a valid zip code', + phoneNumber: 'Please enter a valid phone number', + companyName: 'Please enter a valid legal business name', + addressCity: 'Please enter a valid city', addressStreet: 'Please enter a valid address street that is not a PO Box', addressState: 'Please select a valid state', incorporationDate: 'Please enter a valid incorporation date', diff --git a/src/languages/es.js b/src/languages/es.js index 6fbd8ab352cc..d0cc7a7da0fc 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -385,6 +385,9 @@ export default { taxID: 'Ingrese un número de identificación fiscal válido', website: 'Ingrese un sitio web válido', zipCode: 'Ingrese un código postal válido', + phoneNumber: 'Ingrese un teléfono válido', + companyName: 'Ingrese un nombre comercial legal válido', + addressCity: 'Ingrese una ciudad válida', addressStreet: 'Ingrese una calle de dirección válida que no sea un apartado postal', addressState: 'Por favor, selecciona un estado', incorporationDate: 'Ingrese una fecha de incorporación válida', diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index 965dbc78d2d8..9bf4116427f6 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -11,8 +11,8 @@ import CONST from '../../CONST'; import { goToWithdrawalAccountSetupStep, hideBankAccountErrors, setupWithdrawalAccount, - showBankAccountFormValidationError, showBankAccountErrorModal, + setBankAccountFormValidationErrors, } from '../../libs/actions/BankAccounts'; import Navigation from '../../libs/Navigation/Navigation'; import Text from '../../components/Text'; @@ -80,58 +80,106 @@ class CompanyStep extends React.Component { 'password', 'companyPhone', ]; + + // Keys in this.errorTranslationKeys are associated to inputs, they are a subset of the keys found in this.state + this.errorTranslationKeys = { + addressStreet: 'bankAccount.error.addressStreet', + addressCity: 'bankAccount.error.addressCity', + addressZipCode: 'bankAccount.error.zipCode', + companyName: 'bankAccount.error.companyName', + companyPhone: 'bankAccount.error.phoneNumber', + website: 'bankAccount.error.website', + companyTaxID: 'bankAccount.error.taxID', + incorporationDate: 'bankAccount.error.incorporationDate', + industryCode: 'bankAccount.error.industryCode', + password: 'common.passwordCannotBeBlank', + }; + } + + /** + * @returns {Object} + */ + getErrors() { + return lodashGet(this.props, ['reimbursementAccount', 'errors'], {}); + } + + /** + * @param {String} inputKey + * @returns {string} + */ + getErrorText(inputKey) { + const errors = this.getErrors(); + return errors[inputKey] ? this.props.translate(this.errorTranslationKeys[inputKey]) : ''; + } + + /** + * Clear the error associated to inputKey if found and store the inputKey new value in the state. + * + * @param {String} inputKey + * @param {String} value + */ + clearErrorAndSetValue(inputKey, value) { + this.setState({[inputKey]: value}); + const errors = this.getErrors(); + if (!errors[inputKey]) { + // No error found for this inputKey + return; + } + + // Clear the existing error for this inputKey + const newErrors = {...errors}; + delete newErrors[inputKey]; + setBankAccountFormValidationErrors(newErrors); } /** * @returns {Boolean} */ validate() { + const errors = {}; if (!this.state.password.trim()) { - showBankAccountFormValidationError(this.props.translate('common.passwordCannotBeBlank')); - return false; + errors.password = true; } if (!isValidAddress(this.state.addressStreet)) { - showBankAccountFormValidationError(this.props.translate('bankAccount.error.addressStreet')); - return false; + errors.addressStreet = true; } if (this.state.addressState === '') { - showBankAccountFormValidationError(this.props.translate('bankAccount.error.addressState')); - return false; + errors.addressState = true; } if (!isValidZipCode(this.state.addressZipCode)) { - showBankAccountFormValidationError(this.props.translate('bankAccount.error.zipCode')); - return false; + errors.addressZipCode = true; } if (!Str.isValidURL(this.state.website)) { - showBankAccountFormValidationError(this.props.translate('bankAccount.error.website')); - return false; + errors.website = true; } if (!/[0-9]{9}/.test(this.state.companyTaxID)) { - showBankAccountFormValidationError(this.props.translate('bankAccount.error.taxID')); - return false; + errors.companyTaxID = true; } if (!isValidDate(this.state.incorporationDate)) { - showBankAccountFormValidationError(this.props.translate('bankAccount.error.incorporationDate')); - return false; + errors.incorporationDate = true; } if (!isValidIndustryCode(this.state.industryCode)) { - showBankAccountFormValidationError(this.props.translate('bankAccount.error.industryCode')); - return false; + errors.industryCode = true; } if (!this.state.hasNoConnectionToCannabis) { - showBankAccountFormValidationError(this.props.translate('bankAccount.error.restrictedBusiness')); - return false; + errors.hasNoConnectionToCannabis = true; } + this.requiredFields.forEach((inputKey) => { + if (!this.state[inputKey].trim()) { + errors[inputKey] = true; + } + }); - return true; + setBankAccountFormValidationErrors(errors); + return _.size(errors) === 0; } submit() { @@ -147,10 +195,7 @@ class CompanyStep extends React.Component { render() { const shouldDisableCompanyName = Boolean(this.props.achData.bankAccountID && this.props.achData.companyName); const shouldDisableCompanyTaxID = Boolean(this.props.achData.bankAccountID && this.props.achData.companyTaxID); - const missingRequiredFields = this.requiredFields.reduce((acc, curr) => acc || !this.state[curr].trim(), false); - const shouldDisableSubmitButton = !this.state.hasNoConnectionToCannabis || missingRequiredFields; - const error = this.props.reimbursementAccount.error; - + const shouldDisableSubmitButton = !this.state.hasNoConnectionToCannabis; return ( <> this.setState({companyName})} + onChangeText={value => this.clearErrorAndSetValue('companyName', value)} value={this.state.companyName} disabled={shouldDisableCompanyName} + errorText={this.getErrorText('companyName')} /> { - if (error === this.props.translate('bankAccount.error.addressStreet')) { - hideBankAccountErrors(); - } - this.setState({addressStreet}); - }} + onChangeText={value => this.clearErrorAndSetValue('addressStreet', value)} value={this.state.addressStreet} - errorText={error === this.props.translate('bankAccount.error.addressStreet') - ? this.props.translate('bankAccount.error.addressStreet') - : ''} + errorText={this.getErrorText('addressStreet')} /> {this.props.translate('common.noPO')} this.setState({addressCity})} + onChangeText={value => this.clearErrorAndSetValue('addressCity', value)} value={this.state.addressCity} + errorText={this.getErrorText('addressCity')} /> @@ -202,54 +242,34 @@ class CompanyStep extends React.Component { { - if (error === this.props.translate('bankAccount.error.zipCode')) { - hideBankAccountErrors(); - } - this.setState({addressZipCode}); - }} + onChangeText={value => this.clearErrorAndSetValue('addressZipCode', value)} value={this.state.addressZipCode} - errorText={error === this.props.translate('bankAccount.error.zipCode') - ? this.props.translate('bankAccount.error.zipCode') - : ''} + errorText={this.getErrorText('addressZipCode')} /> this.setState({companyPhone})} + onChangeText={value => this.clearErrorAndSetValue('companyPhone', value)} value={this.state.companyPhone} placeholder={this.props.translate('companyStep.companyPhonePlaceholder')} + errorText={this.getErrorText('companyPhone')} /> { - if (error === this.props.translate('bankAccount.error.website')) { - hideBankAccountErrors(); - } - this.setState({website}); - }} + onChangeText={value => this.clearErrorAndSetValue('website', value)} value={this.state.website} - errorText={error === this.props.translate('bankAccount.error.website') - ? this.props.translate('bankAccount.error.website') - : ''} + errorText={this.getErrorText('website')} /> { - if (error === this.props.translate('bankAccount.error.taxID')) { - hideBankAccountErrors(); - } - this.setState({companyTaxID}); - }} + onChangeText={value => this.clearErrorAndSetValue('companyTaxID', value)} value={this.state.companyTaxID} disabled={shouldDisableCompanyTaxID} - errorText={error === this.props.translate('bankAccount.error.taxID') - ? this.props.translate('bankAccount.error.taxID') - : ''} + errorText={this.getErrorText('companyTaxID')} /> { - if (error === this.props.translate('bankAccount.error.incorporationDate')) { - hideBankAccountErrors(); - } - this.setState({incorporationDate}); - }} + onChangeText={value => this.clearErrorAndSetValue('incorporationDate', value)} value={this.state.incorporationDate} placeholder={this.props.translate('companyStep.incorporationDatePlaceholder')} - errorText={error === this.props.translate('bankAccount.error.incorporationDate') - ? this.props.translate('bankAccount.error.incorporationDate') - : ''} + errorText={this.getErrorText('incorporationDate')} /> @@ -291,33 +304,19 @@ class CompanyStep extends React.Component { helpLinkText={this.props.translate('common.whatThis')} helpLinkURL="https://www.naics.com/search/" containerStyles={[styles.mt4]} - onChangeText={(industryCode) => { - if (error === this.props.translate('bankAccount.error.industryCode')) { - hideBankAccountErrors(); - } - this.setState({industryCode}); - }} + onChangeText={value => this.clearErrorAndSetValue('industryCode', value)} value={this.state.industryCode} - errorText={error === this.props.translate('bankAccount.error.industryCode') - ? this.props.translate('bankAccount.error.industryCode') - : ''} + errorText={this.getErrorText('industryCode')} /> { - if (error === this.props.translate('common.passwordCannotBeBlank')) { - hideBankAccountErrors(); - } - this.setState({password}); - }} + onChangeText={value => this.clearErrorAndSetValue('password', value)} value={this.state.password} onSubmitEditing={shouldDisableSubmitButton ? undefined : this.submit} - errorText={error === this.props.translate('common.passwordCannotBeBlank') - ? this.props.translate('common.passwordCannotBeBlank') - : ''} + errorText={this.getErrorText('password')} // Use new-password to prevent an autoComplete bug https://github.com/Expensify/Expensify/issues/173177 // eslint-disable-next-line react/jsx-props-no-multi-spaces From 79d07ed4ae64773aa4c877490e2fcbfec93e4689 Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Fri, 3 Sep 2021 16:33:20 -0700 Subject: [PATCH 003/289] Display error for Company Type in Company Step Add props to receive error in ExpensiPicker Set red outline based on the error received Display optional error text in ExpensiPicker --- src/components/ExpensiPicker.js | 52 +++++++++++++------ src/components/ExpensiTextInput/propTypes.js | 2 +- src/pages/ReimbursementAccount/CompanyStep.js | 4 +- 3 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/components/ExpensiPicker.js b/src/components/ExpensiPicker.js index c80744146298..370007ffa518 100644 --- a/src/components/ExpensiPicker.js +++ b/src/components/ExpensiPicker.js @@ -10,11 +10,19 @@ const propTypes = { /** Should the picker appear disabled? */ isDisabled: PropTypes.bool, + + /** Error text to display */ + errorText: PropTypes.string, + + /** Should the input be styled for errors */ + hasError: PropTypes.bool, }; const defaultProps = { label: '', isDisabled: false, + errorText: '', + hasError: false, }; class ExpensiPicker extends PureComponent { @@ -27,27 +35,37 @@ class ExpensiPicker extends PureComponent { render() { const { - label, isDisabled, ...pickerProps + errorText, + label, + isDisabled, + ...pickerProps } = this.props; return ( - - {label && ( + <> + + {label && ( {label} - )} - this.setState({isOpen: true})} - onClose={() => this.setState({isOpen: false})} - disabled={isDisabled} + )} + this.setState({isOpen: true})} + onClose={() => this.setState({isOpen: false})} + disabled={isDisabled} // eslint-disable-next-line react/jsx-props-no-spreading - {...pickerProps} - /> - + {...pickerProps} + /> + + + {Boolean(errorText) && ( + {errorText} + )} + ); } } diff --git a/src/components/ExpensiTextInput/propTypes.js b/src/components/ExpensiTextInput/propTypes.js index e3a42808a3d5..b535a244c559 100644 --- a/src/components/ExpensiTextInput/propTypes.js +++ b/src/components/ExpensiTextInput/propTypes.js @@ -33,7 +33,7 @@ const defaultProps = { label: '', errorText: '', placeholder: '', - error: false, + hasError: false, containerStyles: [], translateX: -22, inputStyle: [], diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index 9bf4116427f6..a4f7e7fdaeab 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -91,6 +91,7 @@ class CompanyStep extends React.Component { website: 'bankAccount.error.website', companyTaxID: 'bankAccount.error.taxID', incorporationDate: 'bankAccount.error.incorporationDate', + incorporationType: 'bankAccount.error.companyType', industryCode: 'bankAccount.error.industryCode', password: 'common.passwordCannotBeBlank', }; @@ -275,9 +276,10 @@ class CompanyStep extends React.Component { ({value, label}))} - onChange={incorporationType => this.setState({incorporationType})} + onChange={value => this.clearErrorAndSetValue('incorporationType', value)} value={this.state.incorporationType} placeholder={{value: '', label: '-'}} + errorText={this.getErrorText('incorporationType')} /> From e1a032d27323513408dd50f8bde7eda8ee7691da Mon Sep 17 00:00:00 2001 From: Santhoshkumar Sellavel Date: Sun, 5 Sep 2021 13:02:01 +0530 Subject: [PATCH 004/289] Removed Call options for automated expensisy accounts except 1:1 with concierge. Remove timezone in details page for all automated accounts --- src/pages/DetailsPage.js | 6 ++++-- src/pages/home/HeaderView.js | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/pages/DetailsPage.js b/src/pages/DetailsPage.js index ad99904118c9..cc9401fdc04f 100755 --- a/src/pages/DetailsPage.js +++ b/src/pages/DetailsPage.js @@ -2,6 +2,7 @@ import React from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; +import _ from 'underscore'; import Str from 'expensify-common/lib/str'; import moment from 'moment'; import styles from '../styles/styles'; @@ -15,7 +16,7 @@ import personalDetailsPropType from './personalDetailsPropType'; import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; import compose from '../libs/compose'; import CommunicationsLink from '../components/CommunicationsLink'; -import CONST from '../CONST'; +import CONST, {EXPENSIFY_EMAILS} from '../CONST'; const matchType = PropTypes.shape({ params: PropTypes.shape({ @@ -69,6 +70,7 @@ const DetailsPage = ({ const timezone = moment().tz(details.timezone.selected); const GMTTime = `${timezone.toString().split(/[+-]/)[0].slice(-3)} ${timezone.zoneAbbr()}`; const currentTime = Number.isNaN(Number(timezone.zoneAbbr())) ? timezone.zoneAbbr() : GMTTime; + const shouldShowLocalTime = !_.contains(EXPENSIFY_EMAILS, details.login); return ( @@ -126,7 +128,7 @@ const DetailsPage = ({ ) : null} - {details.timezone ? ( + { shouldShowLocalTime && details.timezone ? ( {translate('detailsPage.localTime')} diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index e43fd8377535..40811e8e0ac5 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -4,6 +4,7 @@ import {View, Pressable} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; +import lodashIntersection from 'lodash/intersection'; import Str from 'expensify-common/lib/str'; import styles from '../../styles/styles'; import ONYXKEYS from '../../ONYXKEYS'; @@ -22,7 +23,7 @@ import {participantPropTypes} from './sidebar/optionPropTypes'; import VideoChatButtonAndMenu from '../../components/VideoChatButtonAndMenu'; import IOUBadge from '../../components/IOUBadge'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; -import CONST from '../../CONST'; +import CONST, {EXPENSIFY_EMAILS} from '../../CONST'; import {getDefaultRoomSubtitle, isDefaultRoom, isArchivedRoom} from '../../libs/reportUtils'; import Text from '../../components/Text'; import Tooltip from '../../components/Tooltip'; @@ -93,6 +94,9 @@ const HeaderView = (props) => { const subtitle = getDefaultRoomSubtitle(props.report, props.policies); const isConcierge = participants.length === 1 && participants.includes(CONST.EMAIL.CONCIERGE); + // Show call button when there 1:1 chat with concierge. Else participants should not include automated expensify emails + const shouldShowCallButton = isConcierge || lodashIntersection(participants, EXPENSIFY_EMAILS).length === 0; + return ( @@ -162,7 +166,7 @@ const HeaderView = (props) => { )} - + {shouldShowCallButton && } togglePinnedState(props.report)} From c3bee7298b689ca930aa0e99f27ce9d530cb981b Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 6 Sep 2021 12:51:23 -0700 Subject: [PATCH 005/289] Fix how we create the Concierge report --- src/libs/actions/Report.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index edaf0f346a2e..57f20553ea8d 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -313,11 +313,18 @@ function fetchChatReportsByIDs(chatList, shouldRedirectIfInacessible = false) { Log.info('[Report] successfully fetched report data', false, {chatList}); fetchedReports = reportSummaryList; - // If we receive a 404 response while fetching a single report, treat that report as inacessible. + // If we receive a 404 response while fetching a single report, treat that report as inaccessible. if (jsonCode === 404 && shouldRedirectIfInacessible) { throw new Error(CONST.REPORT.ERROR.INACCESSIBLE_REPORT); } + // If the user doesn't have a report with Concierge yet, we need to create it + const hasConciergeChat = _.reduce(reportSummaryList, (exists, report) => exists || isConciergeChatReport(report), false); + if (!hasConciergeChat) { + // eslint-disable-next-line no-use-before-define + fetchOrCreateChatReport([currentUserEmail, CONST.EMAIL.CONCIERGE], false); + } + return Promise.all(_.map(fetchedReports, (chatReport) => { // If there aren't any IOU actions, we don't need to fetch any additional data if (!chatReport.hasIOUAction) { @@ -940,12 +947,8 @@ function fetchAllReports( .split(',') .filter(_.identity); - // Get all the chat reports if they have any, otherwise create one with concierge - if (reportIDs.length > 0) { - return fetchChatReportsByIDs(reportIDs); - } - - return fetchOrCreateChatReport([currentUserEmail, CONST.EMAIL.CONCIERGE], false); + // Get all the chat reports if they have any + return fetchChatReportsByIDs(reportIDs); }) .then((returnedReportIDs) => { Onyx.set(ONYXKEYS.INITIAL_REPORT_DATA_LOADED, true); From 71f63e798ed2249bfb24599ac61532486ac5d865 Mon Sep 17 00:00:00 2001 From: Jasper Huang Date: Mon, 6 Sep 2021 13:04:30 -0700 Subject: [PATCH 006/289] revert unneeded --- src/libs/actions/Report.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 57f20553ea8d..9c7daa28c6c7 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -947,8 +947,12 @@ function fetchAllReports( .split(',') .filter(_.identity); - // Get all the chat reports if they have any - return fetchChatReportsByIDs(reportIDs); + // Get all the chat reports if they have any, otherwise create one with concierge + if (reportIDs.length > 0) { + return fetchChatReportsByIDs(reportIDs); + } + + return fetchOrCreateChatReport([currentUserEmail, CONST.EMAIL.CONCIERGE], false); }) .then((returnedReportIDs) => { Onyx.set(ONYXKEYS.INITIAL_REPORT_DATA_LOADED, true); From c6e0e3a78530f52abdd22986b023554cc4f16806 Mon Sep 17 00:00:00 2001 From: Clem Dal Palu Date: Tue, 7 Sep 2021 17:01:57 +0200 Subject: [PATCH 007/289] Remove industry code from VBA request in favor of random --- src/pages/ReimbursementAccount/CompanyStep.js | 26 +------------------ 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index 965dbc78d2d8..865e258b13d1 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -25,7 +25,7 @@ import TextLink from '../../components/TextLink'; import StatePicker from '../../components/StatePicker'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; import { - isValidAddress, isValidDate, isValidIndustryCode, isValidZipCode, + isValidAddress, isValidDate, isValidZipCode, } from '../../libs/ValidationUtils'; import compose from '../../libs/compose'; import ONYXKEYS from '../../ONYXKEYS'; @@ -59,7 +59,6 @@ class CompanyStep extends React.Component { incorporationType: lodashGet(props, ['achData', 'incorporationType'], ''), incorporationDate: lodashGet(props, ['achData', 'incorporationDate'], ''), incorporationState: lodashGet(props, ['achData', 'incorporationState']) || '', - industryCode: lodashGet(props, ['achData', 'industryCode'], ''), hasNoConnectionToCannabis: lodashGet(props, ['achData', 'hasNoConnectionToCannabis'], false), password: '', }; @@ -76,7 +75,6 @@ class CompanyStep extends React.Component { 'incorporationDate', 'incorporationState', 'incorporationType', - 'industryCode', 'password', 'companyPhone', ]; @@ -121,11 +119,6 @@ class CompanyStep extends React.Component { return false; } - if (!isValidIndustryCode(this.state.industryCode)) { - showBankAccountFormValidationError(this.props.translate('bankAccount.error.industryCode')); - return false; - } - if (!this.state.hasNoConnectionToCannabis) { showBankAccountFormValidationError(this.props.translate('bankAccount.error.restrictedBusiness')); return false; @@ -285,23 +278,6 @@ class CompanyStep extends React.Component { /> - {/* TODO: Replace with NAICS picker */} - { - if (error === this.props.translate('bankAccount.error.industryCode')) { - hideBankAccountErrors(); - } - this.setState({industryCode}); - }} - value={this.state.industryCode} - errorText={error === this.props.translate('bankAccount.error.industryCode') - ? this.props.translate('bankAccount.error.industryCode') - : ''} - /> Date: Tue, 7 Sep 2021 14:42:39 -0700 Subject: [PATCH 008/289] Use _.some instead of _.reduce --- src/libs/actions/Report.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index 9c7daa28c6c7..f2f220947ec8 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -319,7 +319,7 @@ function fetchChatReportsByIDs(chatList, shouldRedirectIfInacessible = false) { } // If the user doesn't have a report with Concierge yet, we need to create it - const hasConciergeChat = _.reduce(reportSummaryList, (exists, report) => exists || isConciergeChatReport(report), false); + const hasConciergeChat = _.some(reportSummaryList, report => isConciergeChatReport(report)); if (!hasConciergeChat) { // eslint-disable-next-line no-use-before-define fetchOrCreateChatReport([currentUserEmail, CONST.EMAIL.CONCIERGE], false); From 6fda3da5d21e733750cad1da0bdcfe866cda6330 Mon Sep 17 00:00:00 2001 From: Rajat Parashar Date: Wed, 8 Sep 2021 22:06:13 +0530 Subject: [PATCH 009/289] added bouncing efffect to Lists of the app --- src/components/IOUConfirmationList.js | 2 +- src/components/OptionsList.js | 2 +- src/pages/EnablePayments/AdditionalDetailsStep.js | 2 +- src/pages/ReimbursementAccount/BeneficialOwnersStep.js | 2 +- src/pages/ReimbursementAccount/CompanyStep.js | 2 +- src/pages/ReimbursementAccount/RequestorStep.js | 2 +- src/pages/RequestCallPage.js | 2 +- src/pages/iou/IOUDetailsModal.js | 2 +- src/pages/settings/AboutPage.js | 2 +- src/pages/settings/AddSecondaryLoginPage.js | 2 +- src/pages/settings/AppDownloadLinks.js | 2 +- src/pages/settings/InitialPage.js | 2 +- src/pages/settings/PasswordPage.js | 2 +- src/pages/settings/Profile/ProfilePage.js | 2 +- src/pages/signin/SignInPageLayout/SignInPageLayoutNarrow.js | 1 + src/pages/workspace/WorkspaceCardPage.js | 2 +- src/pages/workspace/WorkspaceInvitePage.js | 2 +- src/pages/workspace/WorkspaceSidebar.js | 2 +- 18 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/components/IOUConfirmationList.js b/src/components/IOUConfirmationList.js index b3e946a3f347..95f09bb0b51e 100755 --- a/src/components/IOUConfirmationList.js +++ b/src/components/IOUConfirmationList.js @@ -319,7 +319,7 @@ class IOUConfirmationList extends Component { const selectedParticipants = this.getSelectedParticipants(); return ( <> - + - + {_.map(this.fields, field => ( <> goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.REQUESTOR)} shouldShowBackButton /> - + {`${this.props.translate('beneficialOwnersStep.additionalInformation')}: `} diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index 5bc7d8725ca4..0562371f6418 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -159,7 +159,7 @@ class CompanyStep extends React.Component { onBackButtonPress={() => goToWithdrawalAccountSetupStep(CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT)} onCloseButtonPress={Navigation.dismissModal} /> - + {this.props.translate('companyStep.subtitle')} ) : ( <> - + this.onFieldChange(field, value)} diff --git a/src/pages/RequestCallPage.js b/src/pages/RequestCallPage.js index 6b7d971fece8..a70236a220d1 100644 --- a/src/pages/RequestCallPage.js +++ b/src/pages/RequestCallPage.js @@ -163,7 +163,7 @@ class RequestCallPage extends Component { ], true)} onCloseButtonPress={() => Navigation.dismissModal(true)} /> - + {this.props.translate('requestCallPage.description')} diff --git a/src/pages/iou/IOUDetailsModal.js b/src/pages/iou/IOUDetailsModal.js index 822149b4a5d3..a7c224c7a132 100644 --- a/src/pages/iou/IOUDetailsModal.js +++ b/src/pages/iou/IOUDetailsModal.js @@ -228,7 +228,7 @@ class IOUDetailsModal extends Component { /> {reportIsLoading ? : ( - + { onCloseButtonPress={() => Navigation.dismissModal(true)} /> Navigation.navigate(ROUTES.SETTINGS_PROFILE)} onCloseButtonPress={() => Navigation.dismissModal()} /> - + {this.props.translate(this.formType === CONST.LOGIN_TYPE.PHONE ? 'addSecondaryLoginPage.enterPreferredPhoneNumberToSendValidationLink' diff --git a/src/pages/settings/AppDownloadLinks.js b/src/pages/settings/AppDownloadLinks.js index faa7b0d0b3ea..dab8c3d8d4cf 100644 --- a/src/pages/settings/AppDownloadLinks.js +++ b/src/pages/settings/AppDownloadLinks.js @@ -46,7 +46,7 @@ const AppDownloadLinksPage = ({translate}) => { onBackButtonPress={() => Navigation.goBack()} onCloseButtonPress={() => Navigation.dismissModal(true)} /> - + {menuItems.map(item => ( Navigation.dismissModal(true)} /> - + diff --git a/src/pages/settings/PasswordPage.js b/src/pages/settings/PasswordPage.js index b1febd78bfa5..7175329aea92 100755 --- a/src/pages/settings/PasswordPage.js +++ b/src/pages/settings/PasswordPage.js @@ -119,7 +119,7 @@ class PasswordPage extends Component { onBackButtonPress={() => Navigation.navigate(ROUTES.SETTINGS)} onCloseButtonPress={() => Navigation.dismissModal(true)} /> - + {this.props.translate('passwordPage.changingYourPasswordPrompt')} diff --git a/src/pages/settings/Profile/ProfilePage.js b/src/pages/settings/Profile/ProfilePage.js index c636d999a01d..724d77620c33 100755 --- a/src/pages/settings/Profile/ProfilePage.js +++ b/src/pages/settings/Profile/ProfilePage.js @@ -204,7 +204,7 @@ class ProfilePage extends Component { onBackButtonPress={() => Navigation.navigate(ROUTES.SETTINGS)} onCloseButtonPress={() => Navigation.dismissModal(true)} /> - + ( - + - + {this.props.translate('workspace.invite.invitePeoplePrompt')} diff --git a/src/pages/workspace/WorkspaceSidebar.js b/src/pages/workspace/WorkspaceSidebar.js index eeec0f789da4..efabef27019c 100644 --- a/src/pages/workspace/WorkspaceSidebar.js +++ b/src/pages/workspace/WorkspaceSidebar.js @@ -89,7 +89,7 @@ const WorkspaceSidebar = ({ return ( Date: Wed, 8 Sep 2021 13:15:54 -0700 Subject: [PATCH 010/289] Keep Concierge report creation in fetchAllReports --- src/libs/actions/Report.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index f2f220947ec8..cf637cea40d9 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -318,13 +318,6 @@ function fetchChatReportsByIDs(chatList, shouldRedirectIfInacessible = false) { throw new Error(CONST.REPORT.ERROR.INACCESSIBLE_REPORT); } - // If the user doesn't have a report with Concierge yet, we need to create it - const hasConciergeChat = _.some(reportSummaryList, report => isConciergeChatReport(report)); - if (!hasConciergeChat) { - // eslint-disable-next-line no-use-before-define - fetchOrCreateChatReport([currentUserEmail, CONST.EMAIL.CONCIERGE], false); - } - return Promise.all(_.map(fetchedReports, (chatReport) => { // If there aren't any IOU actions, we don't need to fetch any additional data if (!chatReport.hasIOUAction) { @@ -957,6 +950,14 @@ function fetchAllReports( .then((returnedReportIDs) => { Onyx.set(ONYXKEYS.INITIAL_REPORT_DATA_LOADED, true); + // If at this point the user still doesn't have a Concierge report, create it for them. + // This means they were a participant in reports before their account was created (e.g. default rooms) + const hasConciergeChat = _.some(allReports, report => isConciergeChatReport(report)); + if (!hasConciergeChat) { + // eslint-disable-next-line no-use-before-define + fetchOrCreateChatReport([currentUserEmail, CONST.EMAIL.CONCIERGE], false); + } + if (shouldRecordHomePageTiming) { Timing.end(CONST.TIMING.HOMEPAGE_REPORTS_LOADED); } From e635fd890290fe8b1fa470200d14c4c17d7338dd Mon Sep 17 00:00:00 2001 From: Meet Mangukiya Date: Thu, 9 Sep 2021 12:28:10 +0530 Subject: [PATCH 011/289] fix unread marking logic for mobile on visibility change --- src/libs/Visibility/index.native.js | 4 +++- src/pages/home/report/ReportActionsView.js | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/libs/Visibility/index.native.js b/src/libs/Visibility/index.native.js index ba878d4ef7d0..5a2f1d74909f 100644 --- a/src/libs/Visibility/index.native.js +++ b/src/libs/Visibility/index.native.js @@ -1,10 +1,12 @@ // Mobile apps do not require this check for visibility as // they do not use the Notification lib. +import {AppState} from 'react-native'; + /** * @return {Boolean} */ -const isVisible = () => true; +const isVisible = () => AppState.currentState === 'active'; export default { isVisible, diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index cf944d4b196d..bc91c5def802 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -129,7 +129,12 @@ class ReportActionsView extends React.Component { this.scrollToListBottom(); } }); - updateLastReadActionID(this.props.reportID); + + // Only mark as read if the report is open + if (!this.props.isDrawerOpen) { + updateLastReadActionID(this.props.reportID); + } + this.updateUnreadIndicatorPosition(this.props.report.unreadActionCount); fetchActions(this.props.reportID); } @@ -229,7 +234,8 @@ class ReportActionsView extends React.Component { * Records the max action on app visibility change event. */ onVisibilityChange() { - if (Visibility.isVisible()) { + // only mark as read if visible AND report is open. + if (Visibility.isVisible() && !this.props.isDrawerOpen) { updateLastReadActionID(this.props.reportID); } } From 046abd26c5811c0cba08704b6f5e18cf339aa6eb Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Thu, 9 Sep 2021 13:28:21 -0700 Subject: [PATCH 012/289] Add error outline for StatePicker --- src/components/ExpensiPicker.js | 3 ++- src/components/StatePicker.js | 5 +++++ src/pages/ReimbursementAccount/CompanyStep.js | 8 +++++--- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/components/ExpensiPicker.js b/src/components/ExpensiPicker.js index 370007ffa518..d038741bc49e 100644 --- a/src/components/ExpensiPicker.js +++ b/src/components/ExpensiPicker.js @@ -36,6 +36,7 @@ class ExpensiPicker extends PureComponent { render() { const { errorText, + hasError, label, isDisabled, ...pickerProps @@ -47,7 +48,7 @@ class ExpensiPicker extends PureComponent { styles.expensiPickerContainer, this.state.isOpen && styles.borderColorFocus, isDisabled && styles.inputDisabled, - errorText && styles.borderColorDanger, + (errorText || hasError) && styles.borderColorDanger, ]} > {label && ( diff --git a/src/components/StatePicker.js b/src/components/StatePicker.js index b754777dd848..f8f8349bd80b 100644 --- a/src/components/StatePicker.js +++ b/src/components/StatePicker.js @@ -17,11 +17,15 @@ const propTypes = { /** The value that needs to be selected */ value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), + /** Should the input be styled for errors */ + hasError: PropTypes.bool, + ...withLocalizePropTypes, }; const defaultProps = { value: '', + hasError: false, }; const StatePicker = props => ( @@ -31,6 +35,7 @@ const StatePicker = props => ( onChange={props.onChange} value={props.value} label={props.translate('common.state')} + hasError={props.hasError} /> ); diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index a4f7e7fdaeab..e6553ce7c757 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -9,7 +9,7 @@ import {withOnyx} from 'react-native-onyx'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import CONST from '../../CONST'; import { - goToWithdrawalAccountSetupStep, hideBankAccountErrors, + goToWithdrawalAccountSetupStep, setupWithdrawalAccount, showBankAccountErrorModal, setBankAccountFormValidationErrors, @@ -235,8 +235,9 @@ class CompanyStep extends React.Component { this.setState({addressState})} + onChange={value => this.clearErrorAndSetValue('addressState', value)} value={this.state.addressState} + hasError={this.getErrors().addressState} /> @@ -295,8 +296,9 @@ class CompanyStep extends React.Component { this.setState({incorporationState})} + onChange={value => this.clearErrorAndSetValue('incorporationState', value)} value={this.state.incorporationState} + hasError={this.getErrors().incorporationState} /> From 8eb34586110c5861cbf4f518234908aa99f10e29 Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Thu, 9 Sep 2021 16:52:16 -0700 Subject: [PATCH 013/289] Handle the subStep directly from Onyx The subState in the VBA flow was being copied from Onyx into a local state in the BankAccountStep component and it was read from this local state. This caused that when we update the subState from BankAccounts.js in Onyx, the component BankAccountStep missed the update because it was reading it from the local state. --- .../ReimbursementAccount/BankAccountStep.js | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index 93458d8a7cae..d816daf2fd16 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -3,7 +3,7 @@ import lodashGet from 'lodash/get'; import React from 'react'; import {View, Image} from 'react-native'; import PropTypes from 'prop-types'; -import {withOnyx} from 'react-native-onyx'; +import Onyx, {withOnyx} from 'react-native-onyx'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; import MenuItem from '../../components/MenuItem'; import { @@ -49,7 +49,6 @@ class BankAccountStep extends React.Component { this.addPlaidAccount = this.addPlaidAccount.bind(this); this.state = { // One of CONST.BANK_ACCOUNT.SETUP_TYPE - bankAccountAddMethod: props.achData.subStep || undefined, hasAcceptedTerms: props.achData.acceptTerms || true, routingNumber: props.achData.routingNumber || '', accountNumber: props.achData.accountNumber || '', @@ -78,6 +77,16 @@ class BankAccountStep extends React.Component { return errors[inputKey] ? this.props.translate(this.errorTranslationKeys[inputKey]) : ''; } + setSubStep(subStep) { + console.debug('setSubStep', subStep); + if (!subStep) { + // undefined seems to be ignored by Onyx + Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: {subStep: null}}); + } else { + Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {achData: {subStep}}); + } + } + toggleTerms() { this.setState(prevState => ({ hasAcceptedTerms: !prevState.hasAcceptedTerms, @@ -185,15 +194,16 @@ class BankAccountStep extends React.Component { // Disable bank account fields once they've been added in db so they can't be changed const isFromPlaid = this.props.achData.setupType === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID; const shouldDisableInputs = Boolean(this.props.achData.bankAccountID) || isFromPlaid; + const {subStep} = this.props.achData; return ( this.setState({bankAccountAddMethod: undefined})} - shouldShowBackButton={!_.isUndefined(this.state.bankAccountAddMethod)} + onBackButtonPress={() => this.setSubStep(undefined)} + shouldShowBackButton={!_.isUndefined(subStep)} /> - {!this.state.bankAccountAddMethod && ( + {!subStep && ( <> @@ -202,9 +212,7 @@ class BankAccountStep extends React.Component { { - this.setState({bankAccountAddMethod: CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID}); - }} + onPress={() => this.setSubStep(CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID)} disabled={this.props.isPlaidDisabled} shouldShowRightIcon /> @@ -216,9 +224,7 @@ class BankAccountStep extends React.Component { { - this.setState({bankAccountAddMethod: CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL}); - }} + onPress={() => this.setSubStep(CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL)} shouldShowRightIcon /> @@ -240,16 +246,15 @@ class BankAccountStep extends React.Component { )} - {this.state.bankAccountAddMethod === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID && ( + {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID && ( { - this.setState({bankAccountAddMethod: undefined}); - }} + onExitPlaid={() => this.setSubStep(undefined)} + /> )} - {this.state.bankAccountAddMethod === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL && ( + {subStep === CONST.BANK_ACCOUNT.SETUP_TYPE.MANUAL && ( <> From 7c5866e6ae4b76215f541e49a9d058cd6a3d1e42 Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Thu, 9 Sep 2021 18:39:29 -0700 Subject: [PATCH 014/289] Avoid double-fetching the withdrawal account data Withdrawal account data was being loaded from AuthScreens component, and then again from ReiumbursementAccountPage on mount. Moved the code handling the step from route to componentDidUpdate in ReimbursementAccountPage and is not fetching anymore. --- src/libs/actions/BankAccounts.js | 7 +++++-- .../ReimbursementAccount/BankAccountStep.js | 2 +- .../ReimbursementAccountPage.js | 16 ++++++++++------ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/libs/actions/BankAccounts.js b/src/libs/actions/BankAccounts.js index 1704d1f19d04..2847f22fb28e 100644 --- a/src/libs/actions/BankAccounts.js +++ b/src/libs/actions/BankAccounts.js @@ -345,9 +345,9 @@ function fetchFreePlanVerifiedBankAccount(stepToOpen) { // We are using set here since we will rely on data from the server (not local data) to populate the VBA flow // and determine which step to navigate to. Onyx.set(ONYXKEYS.REIMBURSEMENT_ACCOUNT, { - loading: true, + loading: true, // shows loading indicator error: '', - + fetching: true, // only used when fetching // We temporarily keep the achData state to prevent UI changes while fetching. achData: {state: lodashGet(reimbursementAccountInSetup, 'state', '')}, }); @@ -505,6 +505,7 @@ function fetchFreePlanVerifiedBankAccount(stepToOpen) { .finally(() => { const dataToMerge = { loading: false, + fetching: false, }; // If we didn't get a routingNumber and accountNumber from the response and we have previously saved @@ -581,6 +582,7 @@ function setFreePlanVerifiedBankAccountID(bankAccountID) { * @param {String} validateCode */ function validateBankAccount(bankAccountID, validateCode) { + console.log('validateBankAccount'); Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {loading: true}); API.BankAccount_Validate({bankAccountID, validateCode}) @@ -653,6 +655,7 @@ function showBankAccountFormValidationError(error) { * @param {Object} [data] */ function setupWithdrawalAccount(data) { + console.log('setupWithdrawalAccount', data); let nextStep; Onyx.merge(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {loading: true}); diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index d816daf2fd16..f420c4f5c880 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -201,7 +201,7 @@ class BankAccountStep extends React.Component { title={this.props.translate('bankAccount.addBankAccount')} onCloseButtonPress={Navigation.dismissModal} onBackButtonPress={() => this.setSubStep(undefined)} - shouldShowBackButton={!_.isUndefined(subStep)} + shouldShowBackButton={Boolean(subStep)} /> {!subStep && ( <> diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js index 7e4f7fa8a779..b174473d2d09 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js @@ -7,7 +7,7 @@ import {View} from 'react-native'; import PropTypes from 'prop-types'; import ScreenWrapper from '../../components/ScreenWrapper'; import { - fetchFreePlanVerifiedBankAccount, + goToWithdrawalAccountSetupStep, hideBankAccountErrorModal, hideBankAccountErrors, } from '../../libs/actions/BankAccounts'; @@ -87,11 +87,6 @@ const defaultProps = { }; class ReimbursementAccountPage extends React.Component { - componentDidMount() { - // We can specify a step to navigate to by using route params when the component mounts. - fetchFreePlanVerifiedBankAccount(this.getStepToOpenFromRouteParams()); - } - componentDidUpdate(prevProps) { const currentStep = lodashGet( this.props, @@ -104,6 +99,15 @@ class ReimbursementAccountPage extends React.Component { CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT, ); + if (prevProps.reimbursementAccount.fetching && !this.props.reimbursementAccount.fetching) { + // We can specify a step to navigate to by using route params when finish fetching the bank account data. + const routeStep = this.getStepToOpenFromRouteParams(); + if (this.props.reimbursementAccount.achData.currentStep !== routeStep) { + goToWithdrawalAccountSetupStep(routeStep); + return; + } + } + if (currentStep === previousStep) { return; } From 21bfaa0ebb1d8a9e04266f718ebad7f9a19f715d Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Fri, 10 Sep 2021 09:56:02 -0700 Subject: [PATCH 015/289] Fix indentation and remove empty line --- src/components/ExpensiPicker.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ExpensiPicker.js b/src/components/ExpensiPicker.js index d038741bc49e..f04eb62e5cb5 100644 --- a/src/components/ExpensiPicker.js +++ b/src/components/ExpensiPicker.js @@ -52,16 +52,15 @@ class ExpensiPicker extends PureComponent { ]} > {label && ( - {label} + {label} )} this.setState({isOpen: true})} onClose={() => this.setState({isOpen: false})} disabled={isDisabled} - // eslint-disable-next-line react/jsx-props-no-spreading + // eslint-disable-next-line react/jsx-props-no-spreading {...pickerProps} /> - {Boolean(errorText) && ( {errorText} From 81afa9aec329a1bf53abbb3811163af9a4e4577d Mon Sep 17 00:00:00 2001 From: Santhoshkumar Sellavel Date: Sat, 11 Sep 2021 01:23:53 +0530 Subject: [PATCH 016/289] Restricted call option in 1:1 chat alone & PR requested changes --- src/libs/reportUtils.js | 12 +++++++++++- src/pages/DetailsPage.js | 6 +++--- src/pages/home/HeaderView.js | 11 ++++++----- src/pages/home/report/ReportActionCompose.js | 7 +++---- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/libs/reportUtils.js b/src/libs/reportUtils.js index 66f9c4dbae8f..a0adfa4892bd 100644 --- a/src/libs/reportUtils.js +++ b/src/libs/reportUtils.js @@ -3,7 +3,7 @@ import Str from 'expensify-common/lib/str'; import lodashGet from 'lodash/get'; import Onyx from 'react-native-onyx'; import ONYXKEYS from '../ONYXKEYS'; -import CONST from '../CONST'; +import CONST, {EXPENSIFY_EMAILS} from '../CONST'; let sessionEmail; Onyx.connect({ @@ -152,6 +152,15 @@ function isConciergeChatReport(report) { && report.participants[0] === CONST.EMAIL.CONCIERGE; } +/** + * Returns true if there is any automated expensify account in emails + * @param {Array.} emails + * @returns {Boolean} + */ +function hasExpensifyEmails(emails) { + return _.intersection(emails, EXPENSIFY_EMAILS).length > 0; +} + export { getReportParticipantsTitle, isReportMessageAttachment, @@ -163,4 +172,5 @@ export { getDefaultRoomSubtitle, isArchivedRoom, isConciergeChatReport, + hasExpensifyEmails, }; diff --git a/src/pages/DetailsPage.js b/src/pages/DetailsPage.js index cc9401fdc04f..f3146646cde3 100755 --- a/src/pages/DetailsPage.js +++ b/src/pages/DetailsPage.js @@ -2,7 +2,6 @@ import React from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import Str from 'expensify-common/lib/str'; import moment from 'moment'; import styles from '../styles/styles'; @@ -16,7 +15,8 @@ import personalDetailsPropType from './personalDetailsPropType'; import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; import compose from '../libs/compose'; import CommunicationsLink from '../components/CommunicationsLink'; -import CONST, {EXPENSIFY_EMAILS} from '../CONST'; +import CONST from '../CONST'; +import {hasExpensifyEmails} from '../libs/reportUtils'; const matchType = PropTypes.shape({ params: PropTypes.shape({ @@ -70,7 +70,7 @@ const DetailsPage = ({ const timezone = moment().tz(details.timezone.selected); const GMTTime = `${timezone.toString().split(/[+-]/)[0].slice(-3)} ${timezone.zoneAbbr()}`; const currentTime = Number.isNaN(Number(timezone.zoneAbbr())) ? timezone.zoneAbbr() : GMTTime; - const shouldShowLocalTime = !_.contains(EXPENSIFY_EMAILS, details.login); + const shouldShowLocalTime = !hasExpensifyEmails([details.login]); return ( diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index 40811e8e0ac5..2f5ad85216ae 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -4,7 +4,6 @@ import {View, Pressable} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; -import lodashIntersection from 'lodash/intersection'; import Str from 'expensify-common/lib/str'; import styles from '../../styles/styles'; import ONYXKEYS from '../../ONYXKEYS'; @@ -23,8 +22,10 @@ import {participantPropTypes} from './sidebar/optionPropTypes'; import VideoChatButtonAndMenu from '../../components/VideoChatButtonAndMenu'; import IOUBadge from '../../components/IOUBadge'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; -import CONST, {EXPENSIFY_EMAILS} from '../../CONST'; -import {getDefaultRoomSubtitle, isDefaultRoom, isArchivedRoom} from '../../libs/reportUtils'; +import CONST from '../../CONST'; +import { + getDefaultRoomSubtitle, isDefaultRoom, isArchivedRoom, hasExpensifyEmails, +} from '../../libs/reportUtils'; import Text from '../../components/Text'; import Tooltip from '../../components/Tooltip'; @@ -94,8 +95,8 @@ const HeaderView = (props) => { const subtitle = getDefaultRoomSubtitle(props.report, props.policies); const isConcierge = participants.length === 1 && participants.includes(CONST.EMAIL.CONCIERGE); - // Show call button when there 1:1 chat with concierge. Else participants should not include automated expensify emails - const shouldShowCallButton = isConcierge || lodashIntersection(participants, EXPENSIFY_EMAILS).length === 0; + // Except Concierge, call options for automated expensify accounts in 1:1 chat is not useful, so hide the button + const shouldShowCallButton = isConcierge || !(participants.length === 1 && hasExpensifyEmails(participants)); return ( diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index eee2dc62faf5..b101629f5a17 100755 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -42,7 +42,7 @@ import EmojiPickerMenu from './EmojiPickerMenu'; import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions'; import withDrawerState from '../../../components/withDrawerState'; import getButtonState from '../../../libs/getButtonState'; -import CONST, {EXCLUDED_IOU_EMAILS, EXPENSIFY_EMAILS} from '../../../CONST'; +import CONST, {EXCLUDED_IOU_EMAILS} from '../../../CONST'; import canFocusInputOnScreenFocus from '../../../libs/canFocusInputOnScreenFocus'; import variables from '../../../styles/variables'; import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize'; @@ -51,7 +51,7 @@ import Navigation from '../../../libs/Navigation/Navigation'; import ROUTES from '../../../ROUTES'; import * as User from '../../../libs/actions/User'; import ReportActionPropTypes from './ReportActionPropTypes'; -import {canEditReportAction, isArchivedRoom} from '../../../libs/reportUtils'; +import {canEditReportAction, hasExpensifyEmails, isArchivedRoom} from '../../../libs/reportUtils'; import ReportActionComposeFocusManager from '../../../libs/ReportActionComposeFocusManager'; import Text from '../../../components/Text'; import {participantPropTypes} from '../sidebar/optionPropTypes'; @@ -458,12 +458,11 @@ class ReportActionCompose extends React.Component { // eslint-disable-next-line no-unused-vars const reportParticipants = lodashGet(this.props.report, 'participants', []); const hasMultipleParticipants = reportParticipants.length > 1; - const hasExpensifyEmails = lodashIntersection(reportParticipants, EXPENSIFY_EMAILS).length > 0; const hasExcludedIOUEmails = lodashIntersection(reportParticipants, EXCLUDED_IOU_EMAILS).length > 0; const reportRecipient = this.props.personalDetails[reportParticipants[0]]; const currentUserTimezone = lodashGet(this.props.myPersonalDetails, 'timezone', CONST.DEFAULT_TIME_ZONE); const reportRecipientTimezone = lodashGet(reportRecipient, 'timezone', CONST.DEFAULT_TIME_ZONE); - const shouldShowReportRecipientLocalTime = !hasExpensifyEmails + const shouldShowReportRecipientLocalTime = !hasExpensifyEmails(reportParticipants) && !hasMultipleParticipants && reportRecipient && reportRecipientTimezone From 6cf1682cbdfc5b0ad508a9824680f666d548d31e Mon Sep 17 00:00:00 2001 From: Prashant Mangukiya Date: Sat, 11 Sep 2021 02:11:03 +0530 Subject: [PATCH 017/289] Corrected floating button in VBA flow. Now button shows at bottom of each step. --- .../ReimbursementAccount/BankAccountStep.js | 14 +++++++------- .../BeneficialOwnersStep.js | 6 ++---- src/pages/ReimbursementAccount/CompanyStep.js | 17 +++++++---------- src/pages/ReimbursementAccount/RequestorStep.js | 17 +++++++---------- .../ReimbursementAccount/ValidationStep.js | 2 +- 5 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js index d1069ea2fecb..7384a2f40184 100644 --- a/src/pages/ReimbursementAccount/BankAccountStep.js +++ b/src/pages/ReimbursementAccount/BankAccountStep.js @@ -298,14 +298,14 @@ class BankAccountStep extends React.Component { )} /> +