From bd08c054b103c2707393deca8fe3e3b88c59791f Mon Sep 17 00:00:00 2001 From: miroslav Date: Mon, 7 Nov 2022 11:13:21 +0100 Subject: [PATCH 001/133] fix composer hidden while loading messages --- src/pages/home/ReportScreen.js | 34 +++++++++++++-------------- src/pages/home/report/ReportFooter.js | 1 + 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index d85dabdf9dcd..6ed8c4efa082 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -287,25 +287,23 @@ class ReportScreen extends React.Component { /> ) : ( - <> - - - + )} + diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index 7c3a4191b390..de0d47ed8186 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -94,6 +94,7 @@ class ReportFooter extends React.Component { contentContainerStyle={this.props.isComposerFullSize ? styles.flex1 : {}} > Date: Wed, 9 Nov 2022 20:26:27 +0100 Subject: [PATCH 002/133] refactor report skeleton view --- .../ReportActionsSkeletonView/index.js | 25 ++++++++++++++++++- src/pages/home/ReportScreen.js | 25 +++++++++++-------- src/pages/home/report/ReportFooter.js | 1 - 3 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/components/ReportActionsSkeletonView/index.js b/src/components/ReportActionsSkeletonView/index.js index 1062fd665450..cd4b541e7b8f 100644 --- a/src/components/ReportActionsSkeletonView/index.js +++ b/src/components/ReportActionsSkeletonView/index.js @@ -2,10 +2,18 @@ import React from 'react'; import PropTypes from 'prop-types'; import SkeletonViewLines from './SkeletonViewLines'; import CONST from '../../CONST'; +import ReportFooter from '../../pages/home/report/ReportFooter'; const propTypes = { /** Height of the container component */ containerHeight: PropTypes.number.isRequired, + + /** Should we show composer at the bottom */ + shouldShowComposer: PropTypes.bool, +}; + +const defaultProps = { + shouldShowComposer: false, }; const ReportActionsSkeletonView = (props) => { @@ -25,9 +33,24 @@ const ReportActionsSkeletonView = (props) => { skeletonViewLines.push(); } } - return <>{skeletonViewLines}; + return ( + <> + {skeletonViewLines} + {props.shouldShowComposer && skeletonViewLines.length > 0 && ( + {}} + report={{reportID: '0'}} + reportActions={{}} + /> + )} + + ); }; ReportActionsSkeletonView.displayName = 'ReportActionsSkeletonView'; ReportActionsSkeletonView.propTypes = propTypes; +ReportActionsSkeletonView.defaultProps = defaultProps; + export default ReportActionsSkeletonView; diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 053927f7a1f9..fa56190b2d13 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -228,7 +228,9 @@ class ReportScreen extends React.Component { style={screenWrapperStyle} > - + + + )} > @@ -299,17 +301,20 @@ class ReportScreen extends React.Component { {(!this.isReportReadyForDisplay() || isLoadingInitialReportActions) && ( + )} + {this.isReportReadyForDisplay() && !isLoadingInitialReportActions && ( + )} - diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index de0d47ed8186..7c3a4191b390 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -94,7 +94,6 @@ class ReportFooter extends React.Component { contentContainerStyle={this.props.isComposerFullSize ? styles.flex1 : {}} > Date: Fri, 11 Nov 2022 22:07:20 +0100 Subject: [PATCH 003/133] fix dummy composer issue --- .../ReportActionsSkeletonView/index.js | 18 ----------- src/pages/home/ReportScreen.js | 30 +++++++++++-------- src/pages/home/report/ReportFooter.js | 1 + 3 files changed, 18 insertions(+), 31 deletions(-) diff --git a/src/components/ReportActionsSkeletonView/index.js b/src/components/ReportActionsSkeletonView/index.js index cd4b541e7b8f..18d291253eee 100644 --- a/src/components/ReportActionsSkeletonView/index.js +++ b/src/components/ReportActionsSkeletonView/index.js @@ -2,18 +2,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import SkeletonViewLines from './SkeletonViewLines'; import CONST from '../../CONST'; -import ReportFooter from '../../pages/home/report/ReportFooter'; const propTypes = { /** Height of the container component */ containerHeight: PropTypes.number.isRequired, - - /** Should we show composer at the bottom */ - shouldShowComposer: PropTypes.bool, -}; - -const defaultProps = { - shouldShowComposer: false, }; const ReportActionsSkeletonView = (props) => { @@ -36,21 +28,11 @@ const ReportActionsSkeletonView = (props) => { return ( <> {skeletonViewLines} - {props.shouldShowComposer && skeletonViewLines.length > 0 && ( - {}} - report={{reportID: '0'}} - reportActions={{}} - /> - )} ); }; ReportActionsSkeletonView.displayName = 'ReportActionsSkeletonView'; ReportActionsSkeletonView.propTypes = propTypes; -ReportActionsSkeletonView.defaultProps = defaultProps; export default ReportActionsSkeletonView; diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index fa56190b2d13..2556cb49e247 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -229,7 +229,14 @@ class ReportScreen extends React.Component { > - + + {}} + report={{reportID: '0'}} + reportActions={{}} + /> )} @@ -301,20 +308,17 @@ class ReportScreen extends React.Component { {(!this.isReportReadyForDisplay() || isLoadingInitialReportActions) && ( - )} - {this.isReportReadyForDisplay() && !isLoadingInitialReportActions && ( - )} + diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index 7c3a4191b390..de0d47ed8186 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -94,6 +94,7 @@ class ReportFooter extends React.Component { contentContainerStyle={this.props.isComposerFullSize ? styles.flex1 : {}} > Date: Tue, 15 Nov 2022 17:36:30 +0100 Subject: [PATCH 004/133] Add SendMoneyElsewhere request --- src/libs/actions/IOU.js | 87 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index d9ac2d1519a1..a0ebcdb317a6 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -720,6 +720,93 @@ function payIOUReport({ return promiseWithHandlers; } +/** + * @param {Object} report + * @param {Number} amount + * @param {String} currency + * @param {String} comment + * @param {String} ownerEmail - Email of the person generating the IOU. + * @param {String} userEmail - Email of the other person participating in the IOU. + */ +function sendMoneyElsewhere(report, amount, currency, comment, ownerEmail, userEmail) { + const participants = [ + {login: ownerEmail}, + {login: userEmail}, + ]; + const chatReport = lodashGet(report, 'reportID', null) + ? report + : ReportUtils.buildOptimisticChatReport(participants); + + const chatReportID = chatReport.reportID; + const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(ownerEmail, userEmail); + + const optimisticAddReportIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( + Report.getMaxSequenceNumber(chatReport.reportID) + 1, + CONST.IOU.REPORT_ACTION_TYPE.CREATE, + amount, + currency, + comment, + participants, + optimisticIOUReport.reportID, + ); + + const optimisticReimbursedReportAction = ReportUtils.buildOptimisticIOUReportAction( + Report.getMaxSequenceNumber(chatReport.reportID) + 2, + CONST.IOU.REPORT_ACTION_TYPE.PAY, + amount, + currency, + comment, + participants, + optimisticIOUReport.reportID, + ); + + const newIOUReportDetails = { + requestorEmail: ownerEmail, + amount, + currency, + comment, + }; + const paymentMethodType = CONST.IOU.PAYMENT_TYPE.ELSEWHERE; + + const optimisticData = [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: ONYXKEYS.IOU, + value: { + errors: {}, + }, + }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, + value: { + [optimisticReimbursedReportAction.reportID]: optimisticReimbursedReportAction, + }, + }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, + value: chatReport, + }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_IOUS}${optimisticIOUReport.reportID}`, + value: optimisticIOUReport, + }, + ]; + + API.write('SendMoney', { + iouReportID: optimisticIOUReport.reportID, + chatReportID, + optimisticReimbursedReportAction, + optimisticAddReportIOUReportAction, + paymentMethodType, + transactionID: optimisticReimbursedReportAction.originalMessage.IOUTransactionID, + clientID: optimisticReimbursedReportAction.sequenceNumber, + newIOUReportDetails, + }, {optimisticData}); +} + export { cancelMoneyRequest, splitBill, From 913ffbc1ff0b829e343e9fc9eb0eab290bd5a3cd Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 16 Nov 2022 01:51:22 +0100 Subject: [PATCH 005/133] Update logic in sendMoneyElsewhere --- src/libs/actions/IOU.js | 111 +++++++++++-------- src/pages/home/report/ReportActionCompose.js | 3 +- src/pages/iou/IOUModal.js | 3 +- 3 files changed, 68 insertions(+), 49 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index a0ebcdb317a6..25ae37cf6bb5 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1,6 +1,7 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; +import Str from 'expensify-common/lib/str'; import CONST from '../../CONST'; import ONYXKEYS from '../../ONYXKEYS'; import ROUTES from '../../ROUTES'; @@ -725,69 +726,66 @@ function payIOUReport({ * @param {Number} amount * @param {String} currency * @param {String} comment - * @param {String} ownerEmail - Email of the person generating the IOU. - * @param {String} userEmail - Email of the other person participating in the IOU. + * @param {String} managerEmail - Email of the person sending the money + * @param {String} recipient - The user receiving the money */ -function sendMoneyElsewhere(report, amount, currency, comment, ownerEmail, userEmail) { - const participants = [ - {login: ownerEmail}, - {login: userEmail}, - ]; - const chatReport = lodashGet(report, 'reportID', null) - ? report - : ReportUtils.buildOptimisticChatReport(participants); - - const chatReportID = chatReport.reportID; - const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(ownerEmail, userEmail); - - const optimisticAddReportIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( - Report.getMaxSequenceNumber(chatReport.reportID) + 1, - CONST.IOU.REPORT_ACTION_TYPE.CREATE, +function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, recipient) { + const newIOUReportDetails = JSON.stringify({ amount, currency, + requestorEmail: recipient.login, comment, - participants, - optimisticIOUReport.reportID, - ); + idempotencyKey: Str.guid(), + }); - const optimisticReimbursedReportAction = ReportUtils.buildOptimisticIOUReportAction( - Report.getMaxSequenceNumber(chatReport.reportID) + 2, + const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login); + let chatReport = lodashGet(report, 'reportID', null) ? report : null; + let isNewChat = false; + if (!chatReport) { + chatReport = ReportUtils.getChatByParticipants([recipientEmail]); + } + if (!chatReport) { + chatReport = ReportUtils.buildOptimisticChatReport([recipientEmail]); + isNewChat = true; + } + const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientEmail, managerEmail, amount, chatReport.reportID, currency, preferredLocale); + const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; + + const optimisticPaidReportAction = ReportUtils.buildOptimisticIOUReportAction( + newSequenceNumber, CONST.IOU.REPORT_ACTION_TYPE.PAY, amount, currency, comment, - participants, + [recipient], + CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + '', optimisticIOUReport.reportID, ); - const newIOUReportDetails = { - requestorEmail: ownerEmail, - amount, - currency, - comment, - }; - const paymentMethodType = CONST.IOU.PAYMENT_TYPE.ELSEWHERE; - + // First, add data that will be used in all cases const optimisticData = [ { onyxMethod: CONST.ONYX.METHOD.MERGE, - key: ONYXKEYS.IOU, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, value: { - errors: {}, + ...chatReport, + lastVisitedTimestamp: Date.now(), + lastReadSequenceNumber: newSequenceNumber, + maxSequenceNumber: newSequenceNumber, + lastMessageText: optimisticPaidReportAction.message[0].text, + lastMessageHtml: optimisticPaidReportAction.message[0].html, + hasOutstandingIOU: optimisticIOUReport.total !== 0, + iouReportID: optimisticIOUReport.reportID, }, }, { onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimisticReimbursedReportAction.reportID]: optimisticReimbursedReportAction, + [optimisticPaidReportAction.sequenceNumber]: optimisticPaidReportAction, }, }, - { - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, - value: chatReport, - }, { onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_IOUS}${optimisticIOUReport.reportID}`, @@ -795,16 +793,36 @@ function sendMoneyElsewhere(report, amount, currency, comment, ownerEmail, userE }, ]; + // Now, let's add the data we need just when we are creating a new chat report + if (isNewChat) { + const optimisticCreateAction = ReportUtils.buildOptimisticCreatedReportAction(recipientEmail); + + // Change the method to set for new reports because it doesn't exist yet, is faster, + // and we need the data to be available when we navigate to the chat page + optimisticData[0].onyxMethod = CONST.ONYX.METHOD.SET; + optimisticData[0].value = { + ...optimisticData[0].value, + pendingFields: {createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD}, + }; + optimisticData[1].onyxMethod = CONST.ONYX.METHOD.SET; + optimisticData[1].value = { + ...optimisticCreateAction, + ...optimisticData[1].value, + }; + optimisticData[2].onyxMethod = CONST.ONYX.METHOD.SET; + } + API.write('SendMoney', { iouReportID: optimisticIOUReport.reportID, - chatReportID, - optimisticReimbursedReportAction, - optimisticAddReportIOUReportAction, - paymentMethodType, - transactionID: optimisticReimbursedReportAction.originalMessage.IOUTransactionID, - clientID: optimisticReimbursedReportAction.sequenceNumber, + chatReportID: chatReport.reportID, + paidReportActionID: optimisticPaidReportAction.reportActionID, + paymentMethodType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + transactionID: Report.openPaymentDetailsPage.originalMessage.IOUTransactionID, + clientID: optimisticPaidReportAction.sequenceNumber, newIOUReportDetails, }, {optimisticData}); + + Navigation.navigate(ROUTES.getReportRoute(chatReport.reportID)); } export { @@ -814,4 +832,5 @@ export { requestMoney, payIOUReport, setIOUSelectedCurrency, + sendMoneyElsewhere, }; diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index ab5aa6fba104..26d52dfec8d0 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -436,7 +436,8 @@ class ReportActionCompose extends React.Component { if (reportActionKey !== -1 && this.props.reportActions[reportActionKey]) { const {reportActionID, message} = this.props.reportActions[reportActionKey]; - Report.saveReportActionDraft(this.props.reportID, reportActionID, _.last(message).html); + + // Report.saveReportActionDraft(this.props.reportID, reportActionID, _.last(message).html); } } } diff --git a/src/pages/iou/IOUModal.js b/src/pages/iou/IOUModal.js index cb6905b3bc1f..2c0cc436722c 100755 --- a/src/pages/iou/IOUModal.js +++ b/src/pages/iou/IOUModal.js @@ -295,13 +295,12 @@ class IOUModal extends Component { idempotencyKey: Str.guid(), }); - IOU.payIOUReport({ + IOU.sendMoneyElsewhere({ chatReportID: lodashGet(this.props, 'route.params.reportID', ''), reportID: '0', paymentMethodType, amount, currency, - requestorPayPalMeAddress: this.state.participants[0].payPalMeAddress, comment, newIOUReportDetails, }) From 2ad8370ce6e1a4c7c8abff19ff65c4f1580753a1 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 16 Nov 2022 16:27:30 +0100 Subject: [PATCH 006/133] Cleanup --- src/pages/home/report/ReportActionCompose.js | 3 +-- src/pages/iou/IOUModal.js | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 26d52dfec8d0..ab5aa6fba104 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -436,8 +436,7 @@ class ReportActionCompose extends React.Component { if (reportActionKey !== -1 && this.props.reportActions[reportActionKey]) { const {reportActionID, message} = this.props.reportActions[reportActionKey]; - - // Report.saveReportActionDraft(this.props.reportID, reportActionID, _.last(message).html); + Report.saveReportActionDraft(this.props.reportID, reportActionID, _.last(message).html); } } } diff --git a/src/pages/iou/IOUModal.js b/src/pages/iou/IOUModal.js index 2c0cc436722c..cb6905b3bc1f 100755 --- a/src/pages/iou/IOUModal.js +++ b/src/pages/iou/IOUModal.js @@ -295,12 +295,13 @@ class IOUModal extends Component { idempotencyKey: Str.guid(), }); - IOU.sendMoneyElsewhere({ + IOU.payIOUReport({ chatReportID: lodashGet(this.props, 'route.params.reportID', ''), reportID: '0', paymentMethodType, amount, currency, + requestorPayPalMeAddress: this.state.participants[0].payPalMeAddress, comment, newIOUReportDetails, }) From d3311f4c03c6eabde9fba2a28871155a02685d7b Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 16 Nov 2022 16:46:09 +0100 Subject: [PATCH 007/133] Use the new SendMoneyElseWhere command from IOUModal --- src/libs/actions/IOU.js | 2 +- src/pages/iou/IOUModal.js | 34 ++++++++++++---------------------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 25ae37cf6bb5..71cf1d946dd9 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -817,7 +817,7 @@ function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, rec chatReportID: chatReport.reportID, paidReportActionID: optimisticPaidReportAction.reportActionID, paymentMethodType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, - transactionID: Report.openPaymentDetailsPage.originalMessage.IOUTransactionID, + transactionID: optimisticPaidReportAction.originalMessage.IOUTransactionID, clientID: optimisticPaidReportAction.sequenceNumber, newIOUReportDetails, }, {optimisticData}); diff --git a/src/pages/iou/IOUModal.js b/src/pages/iou/IOUModal.js index cb6905b3bc1f..471aa2d55c0a 100755 --- a/src/pages/iou/IOUModal.js +++ b/src/pages/iou/IOUModal.js @@ -286,28 +286,18 @@ class IOUModal extends Component { const amount = Math.round(this.state.amount * 100); const currency = this.props.iou.selectedCurrencyCode; const comment = this.state.comment; - - const newIOUReportDetails = JSON.stringify({ - amount, - currency, - requestorEmail: this.state.participants[0].login, - comment, - idempotencyKey: Str.guid(), - }); - - IOU.payIOUReport({ - chatReportID: lodashGet(this.props, 'route.params.reportID', ''), - reportID: '0', - paymentMethodType, - amount, - currency, - requestorPayPalMeAddress: this.state.participants[0].payPalMeAddress, - comment, - newIOUReportDetails, - }) - .finally(() => { - Navigation.navigate(ROUTES.REPORT); - }); + const participant = this.state.participants[0]; + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { + IOU.sendMoneyElsewhere( + this.props.report, + amount, + currency, + comment, + this.props.currentUserPersonalDetails.login, + participant, + ); + } } /** From 2b31e3f915cac30bdf3e7f2b8301fd02660da6b8 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 16 Nov 2022 16:54:46 +0100 Subject: [PATCH 008/133] Fix param type --- src/libs/actions/IOU.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 71cf1d946dd9..419f7cd41fbe 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -727,7 +727,7 @@ function payIOUReport({ * @param {String} currency * @param {String} comment * @param {String} managerEmail - Email of the person sending the money - * @param {String} recipient - The user receiving the money + * @param {Object} recipient - The user receiving the money */ function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, recipient) { const newIOUReportDetails = JSON.stringify({ From e22793ee7a5f88ece75c0e1ddbe4b5423bb9ffbd Mon Sep 17 00:00:00 2001 From: Hans Date: Tue, 15 Nov 2022 19:05:55 +0700 Subject: [PATCH 009/133] make avatar update when online --- src/components/Avatar.js | 48 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/src/components/Avatar.js b/src/components/Avatar.js index aa4f6dbf92fd..2e49c16bbc97 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -1,7 +1,8 @@ -import React, {PureComponent} from 'react'; +import React, {Component, PureComponent} from 'react'; import {Image, View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; +import lodashGet from 'lodash/get'; import stylePropTypes from '../styles/stylePropTypes'; import Icon from './Icon'; import themeColors from '../styles/themes/default'; @@ -9,6 +10,8 @@ import CONST from '../CONST'; import * as StyleUtils from '../styles/StyleUtils'; import * as Expensicons from './Icon/Expensicons'; import getAvatarDefaultSource from '../libs/getAvatarDefaultSource'; +import {withNetwork} from './OnyxProvider'; +import networkPropTypes from './networkPropTypes'; const propTypes = { /** Source for the avatar. Can be a URL or an icon. */ @@ -29,6 +32,9 @@ const propTypes = { /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ fallbackIcon: PropTypes.func, + + /** Props to detect online status */ + network: networkPropTypes.isRequired, }; const defaultProps = { @@ -40,7 +46,7 @@ const defaultProps = { fallbackIcon: Expensicons.FallbackAvatar, }; -class Avatar extends PureComponent { +class Avatar extends Component { constructor(props) { super(props); this.state = { @@ -48,6 +54,42 @@ class Avatar extends PureComponent { }; } + shouldComponentUpdate(nextProps, nextState) { + if ( + lodashGet(this.props.network, 'isOffline') + && !lodashGet(nextProps.network, 'isOffline') + ) { + return true; + } + if (this.props.source !== nextProps.source) { + return true; + } + if (this.state.imageError !== nextState.imageError) { + return true; + } + + if (this.props.fill !== nextProps.fill) { + return true; + } + if (this.props.size !== nextProps.size) { + return true; + } + + return false; + } + + componentDidUpdate(prevProps) { + if (!this.state.imageError) { + return; + } + if ( + lodashGet(prevProps.network, 'isOffline') + && !lodashGet(this.props.network, 'isOffline') + ) { + this.setState({imageError: false}); + } + } + render() { if (!this.props.source) { return null; @@ -86,4 +128,4 @@ class Avatar extends PureComponent { Avatar.defaultProps = defaultProps; Avatar.propTypes = propTypes; -export default Avatar; +export default withNetwork()(Avatar); From 5718a0b7ee84633c1db122998f58e45a51698fc8 Mon Sep 17 00:00:00 2001 From: Hans Date: Thu, 17 Nov 2022 10:27:12 +0700 Subject: [PATCH 010/133] fix linting --- 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 2e49c16bbc97..f2848b8b779e 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -1,4 +1,4 @@ -import React, {Component, PureComponent} from 'react'; +import React, {Component} from 'react'; import {Image, View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; From 5374b911aafbe1ce166e6432c4eaa105cf646810 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Thu, 17 Nov 2022 20:26:29 +0100 Subject: [PATCH 011/133] Allow sending money while offline --- src/components/SettlementButton.js | 2 +- src/libs/ReportUtils.js | 7 +++--- src/libs/actions/IOU.js | 36 ++++++++++++++++++++++++++---- src/pages/iou/IOUModal.js | 1 - 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/components/SettlementButton.js b/src/components/SettlementButton.js index 12e38b6294be..5fdfb437802f 100644 --- a/src/components/SettlementButton.js +++ b/src/components/SettlementButton.js @@ -84,7 +84,7 @@ class SettlementButton extends React.Component { > {triggerKYCFlow => ( { if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 9252911b4535..68adf102d297 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -669,10 +669,11 @@ function buildOptimisticReportAction(sequenceNumber, text, file) { * @param {String} chatReportID - Report ID of the chat where the IOU is. * @param {String} currency - IOU currency. * @param {String} locale - Locale where the IOU is created + * @param {Boolean} isSendingMoney - Whether we're requesting or sending money * * @returns {Object} */ -function buildOptimisticIOUReport(ownerEmail, userEmail, total, chatReportID, currency, locale) { +function buildOptimisticIOUReport(ownerEmail, userEmail, total, chatReportID, currency, locale, isSendingMoney = false) { const formattedTotal = NumberFormatUtils.format(locale, total, { style: 'currency', @@ -682,12 +683,12 @@ function buildOptimisticIOUReport(ownerEmail, userEmail, total, chatReportID, cu cachedTotal: formattedTotal, chatReportID, currency, - hasOutstandingIOU: true, + hasOutstandingIOU: !isSendingMoney, managerEmail: userEmail, ownerEmail, reportID: generateReportID(), state: CONST.REPORT.STATE.SUBMITTED, - stateNum: 1, + stateNum: isSendingMoney ? 2 : 1, total, }; } diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 419f7cd41fbe..cdc8cb75b8e0 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -748,7 +748,7 @@ function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, rec chatReport = ReportUtils.buildOptimisticChatReport([recipientEmail]); isNewChat = true; } - const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientEmail, managerEmail, amount, chatReport.reportID, currency, preferredLocale); + const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientEmail, managerEmail, amount, chatReport.reportID, currency, preferredLocale, true); const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; const optimisticPaidReportAction = ReportUtils.buildOptimisticIOUReportAction( @@ -775,7 +775,7 @@ function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, rec maxSequenceNumber: newSequenceNumber, lastMessageText: optimisticPaidReportAction.message[0].text, lastMessageHtml: optimisticPaidReportAction.message[0].html, - hasOutstandingIOU: optimisticIOUReport.total !== 0, + hasOutstandingIOU: false, iouReportID: optimisticIOUReport.reportID, }, }, @@ -783,7 +783,10 @@ function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, rec onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimisticPaidReportAction.sequenceNumber]: optimisticPaidReportAction, + [optimisticPaidReportAction.sequenceNumber]: { + ...optimisticPaidReportAction, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, }, }, { @@ -793,6 +796,31 @@ function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, rec }, ]; + const successData = [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + value: { + [optimisticPaidReportAction.sequenceNumber]: { + pendingAction: null, + }, + }, + }, + ]; + + const failureData = [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + value: { + [optimisticPaidReportAction.sequenceNumber]: { + ...optimisticPaidReportAction, + pendingAction: null, + }, + }, + }, + ]; + // Now, let's add the data we need just when we are creating a new chat report if (isNewChat) { const optimisticCreateAction = ReportUtils.buildOptimisticCreatedReportAction(recipientEmail); @@ -820,7 +848,7 @@ function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, rec transactionID: optimisticPaidReportAction.originalMessage.IOUTransactionID, clientID: optimisticPaidReportAction.sequenceNumber, newIOUReportDetails, - }, {optimisticData}); + }, {optimisticData, successData, failureData}); Navigation.navigate(ROUTES.getReportRoute(chatReport.reportID)); } diff --git a/src/pages/iou/IOUModal.js b/src/pages/iou/IOUModal.js index 471aa2d55c0a..096597341ac3 100755 --- a/src/pages/iou/IOUModal.js +++ b/src/pages/iou/IOUModal.js @@ -25,7 +25,6 @@ import Tooltip from '../../components/Tooltip'; import CONST from '../../CONST'; import * as PersonalDetails from '../../libs/actions/PersonalDetails'; import withCurrentUserPersonalDetails from '../../components/withCurrentUserPersonalDetails'; -import ROUTES from '../../ROUTES'; import networkPropTypes from '../../components/networkPropTypes'; import {withNetwork} from '../../components/OnyxProvider'; import reportPropTypes from '../reportPropTypes'; From 3f4a97301fc4648b7d588a82461f8f0b61df40c2 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 18 Nov 2022 01:20:56 +0100 Subject: [PATCH 012/133] Wrap IOUAction in OfflineWithFeedback --- src/components/ReportActionItem/IOUAction.js | 13 +++++++++++-- src/libs/actions/ReportActions.js | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/IOUAction.js b/src/components/ReportActionItem/IOUAction.js index 015766612056..671673e52a56 100644 --- a/src/components/ReportActionItem/IOUAction.js +++ b/src/components/ReportActionItem/IOUAction.js @@ -7,6 +7,8 @@ import IOUQuote from './IOUQuote'; import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes'; import IOUPreview from './IOUPreview'; import Navigation from '../../libs/Navigation/Navigation'; +import OfflineWithFeedback from '../OfflineWithFeedback'; +import * as ReportActions from '../../libs/actions/ReportActions'; import ROUTES from '../../ROUTES'; import styles from '../../styles/styles'; @@ -39,7 +41,14 @@ const IOUAction = (props) => { Navigation.navigate(ROUTES.getIouDetailsRoute(props.chatReportID, props.action.originalMessage.IOUReportID)); }; return ( - <> + { + ReportActions.clearSendMoneyErrors(); + }} + errorRowStyles={[styles.mbn1]} + > { containerStyles={[styles.cursorPointer]} /> )} - + ); }; diff --git a/src/libs/actions/ReportActions.js b/src/libs/actions/ReportActions.js index c56bcabaae58..828cdecdda1d 100644 --- a/src/libs/actions/ReportActions.js +++ b/src/libs/actions/ReportActions.js @@ -23,7 +23,21 @@ function clearReportActionErrors(reportID, sequenceNumber) { }); } +/** + * This method clears the errors for a chat where send money action was done + * @param {String} chatReportID + * @param {String} reportActionID + */ +function clearSendMoneyErrors(chatReportID, reportActionID) { + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, { + [reportActionID]: { + errors: null, + }, + }); +} + export { clearReportActionErrors, deleteOptimisticReportAction, + clearSendMoneyErrors, }; From cbc5d7d012068dffb7afcd89ce7bc2f73cc66b37 Mon Sep 17 00:00:00 2001 From: Hans Date: Sat, 19 Nov 2022 16:09:01 +0700 Subject: [PATCH 013/133] fix linting: early return --- src/components/Avatar.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/components/Avatar.js b/src/components/Avatar.js index f2848b8b779e..88362dbc3470 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -79,15 +79,13 @@ class Avatar extends Component { } componentDidUpdate(prevProps) { - if (!this.state.imageError) { - return; - } if ( - lodashGet(prevProps.network, 'isOffline') - && !lodashGet(this.props.network, 'isOffline') + !this.state.imageError || !lodashGet(prevProps.network, 'isOffline') + || lodashGet(this.props.network, 'isOffline') ) { - this.setState({imageError: false}); + return; } + this.setState({imageError: false}); } render() { From 2bac5e70787853610dd1a2e4d78742b3e9b5862d Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 21 Nov 2022 12:44:14 +0100 Subject: [PATCH 014/133] Reverse wrapping IOUAction in OfflineWithFeedback --- src/components/ReportActionItem/IOUAction.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/components/ReportActionItem/IOUAction.js b/src/components/ReportActionItem/IOUAction.js index 671673e52a56..015766612056 100644 --- a/src/components/ReportActionItem/IOUAction.js +++ b/src/components/ReportActionItem/IOUAction.js @@ -7,8 +7,6 @@ import IOUQuote from './IOUQuote'; import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes'; import IOUPreview from './IOUPreview'; import Navigation from '../../libs/Navigation/Navigation'; -import OfflineWithFeedback from '../OfflineWithFeedback'; -import * as ReportActions from '../../libs/actions/ReportActions'; import ROUTES from '../../ROUTES'; import styles from '../../styles/styles'; @@ -41,14 +39,7 @@ const IOUAction = (props) => { Navigation.navigate(ROUTES.getIouDetailsRoute(props.chatReportID, props.action.originalMessage.IOUReportID)); }; return ( - { - ReportActions.clearSendMoneyErrors(); - }} - errorRowStyles={[styles.mbn1]} - > + <> { containerStyles={[styles.cursorPointer]} /> )} - + ); }; From 1928a625301de0a388938e85e4f5d77543dc9340 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 21 Nov 2022 13:54:12 +0100 Subject: [PATCH 015/133] Add PayPalMe flow for sending money --- src/libs/actions/IOU.js | 10 ++++++++-- src/pages/iou/IOUModal.js | 19 +++++++++---------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index cdc8cb75b8e0..3d7453b7055f 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -726,10 +726,11 @@ function payIOUReport({ * @param {Number} amount * @param {String} currency * @param {String} comment + * @param {String} paymentMethodType * @param {String} managerEmail - Email of the person sending the money * @param {Object} recipient - The user receiving the money */ -function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, recipient) { +function sendMoneyElsewhere(report, amount, currency, comment, paymentMethodType, managerEmail, recipient) { const newIOUReportDetails = JSON.stringify({ amount, currency, @@ -844,12 +845,17 @@ function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, rec iouReportID: optimisticIOUReport.reportID, chatReportID: chatReport.reportID, paidReportActionID: optimisticPaidReportAction.reportActionID, - paymentMethodType: CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + paymentMethodType, transactionID: optimisticPaidReportAction.originalMessage.IOUTransactionID, clientID: optimisticPaidReportAction.sequenceNumber, newIOUReportDetails, }, {optimisticData, successData, failureData}); + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { + const url = buildPayPalPaymentUrl(amount, recipient.payPalMeAddress, currency); + asyncOpenURL(Promise.resolve(), url); + } + Navigation.navigate(ROUTES.getReportRoute(chatReport.reportID)); } diff --git a/src/pages/iou/IOUModal.js b/src/pages/iou/IOUModal.js index 096597341ac3..6fd1a9271565 100755 --- a/src/pages/iou/IOUModal.js +++ b/src/pages/iou/IOUModal.js @@ -287,16 +287,15 @@ class IOUModal extends Component { const comment = this.state.comment; const participant = this.state.participants[0]; - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { - IOU.sendMoneyElsewhere( - this.props.report, - amount, - currency, - comment, - this.props.currentUserPersonalDetails.login, - participant, - ); - } + IOU.sendMoneyElsewhere( + this.props.report, + amount, + currency, + comment, + paymentMethodType, + this.props.currentUserPersonalDetails.login, + participant, + ); } /** From a3ffc0dd0635cc2b4d44394d1798ebe8bacabf71 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 21 Nov 2022 14:22:45 +0100 Subject: [PATCH 016/133] Create separate method for PayPal flow --- src/libs/actions/IOU.js | 35 +++++++++++++++++++++++++++++------ src/pages/iou/IOUModal.js | 31 ++++++++++++++++++++++--------- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 3d7453b7055f..12e86390502e 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -730,7 +730,7 @@ function payIOUReport({ * @param {String} managerEmail - Email of the person sending the money * @param {Object} recipient - The user receiving the money */ -function sendMoneyElsewhere(report, amount, currency, comment, paymentMethodType, managerEmail, recipient) { +function sendMoney(report, amount, currency, comment, paymentMethodType, managerEmail, recipient) { const newIOUReportDetails = JSON.stringify({ amount, currency, @@ -851,14 +851,36 @@ function sendMoneyElsewhere(report, amount, currency, comment, paymentMethodType newIOUReportDetails, }, {optimisticData, successData, failureData}); - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { - const url = buildPayPalPaymentUrl(amount, recipient.payPalMeAddress, currency); - asyncOpenURL(Promise.resolve(), url); - } - Navigation.navigate(ROUTES.getReportRoute(chatReport.reportID)); } +/** + * @param {Object} report + * @param {Number} amount + * @param {String} currency + * @param {String} comment + * @param {String} managerEmail - Email of the person sending the money + * @param {Object} recipient - The user receiving the money + */ +function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, recipient) { + const paymentMethodType = CONST.IOU.PAYMENT_TYPE.ELSEWHERE; + sendMoney(report, amount, currency, comment, paymentMethodType, managerEmail, recipient); +} + +/** + * @param {Object} report + * @param {Number} amount + * @param {String} currency + * @param {String} comment + * @param {String} managerEmail - Email of the person sending the money + * @param {Object} recipient - The user receiving the money + */ +function sendMoneyViaPaypal(report, amount, currency, comment, managerEmail, recipient) { + const paymentMethodType = CONST.IOU.PAYMENT_TYPE.PAYPAL_ME; + sendMoney(report, amount, currency, comment, paymentMethodType, managerEmail, recipient); + asyncOpenURL(Promise.resolve(), buildPayPalPaymentUrl(amount, recipient.payPalMeAddress, currency)); +} + export { cancelMoneyRequest, splitBill, @@ -867,4 +889,5 @@ export { payIOUReport, setIOUSelectedCurrency, sendMoneyElsewhere, + sendMoneyViaPaypal, }; diff --git a/src/pages/iou/IOUModal.js b/src/pages/iou/IOUModal.js index 6fd1a9271565..0296a60c839d 100755 --- a/src/pages/iou/IOUModal.js +++ b/src/pages/iou/IOUModal.js @@ -287,15 +287,28 @@ class IOUModal extends Component { const comment = this.state.comment; const participant = this.state.participants[0]; - IOU.sendMoneyElsewhere( - this.props.report, - amount, - currency, - comment, - paymentMethodType, - this.props.currentUserPersonalDetails.login, - participant, - ); + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { + IOU.sendMoneyElsewhere( + this.props.report, + amount, + currency, + comment, + this.props.currentUserPersonalDetails.login, + participant, + ); + return; + } + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { + IOU.sendMoneyViaPaypal( + this.props.report, + amount, + currency, + comment, + this.props.currentUserPersonalDetails.login, + participant, + ); + } } /** From 2c48c72898410ddbcc2fa4acf7d7be73a4e2dda6 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 22 Nov 2022 16:16:15 +0100 Subject: [PATCH 017/133] Add PayMoneyRequest command --- src/libs/actions/IOU.js | 96 +++++++++++++++++++++++++++++++- src/pages/iou/IOUDetailsModal.js | 32 ++++++++--- 2 files changed, 119 insertions(+), 9 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 12e86390502e..4ca07339a0a8 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -881,13 +881,107 @@ function sendMoneyViaPaypal(report, amount, currency, comment, managerEmail, rec asyncOpenURL(Promise.resolve(), buildPayPalPaymentUrl(amount, recipient.payPalMeAddress, currency)); } +function payMoneyRequest(chatReport, iouReport, recipient, paymentMethodType) { + const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; + + const optimisticPaidReportAction = ReportUtils.buildOptimisticIOUReportAction( + newSequenceNumber, + CONST.IOU.REPORT_ACTION_TYPE.PAY, + iouReport.total, + iouReport.currency, + '', + [recipient], + paymentMethodType, + '', + iouReport.reportID, + ); + + // First, add data that will be used in all cases + const optimisticData = [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, + value: { + ...chatReport, + lastVisitedTimestamp: Date.now(), + lastReadSequenceNumber: newSequenceNumber, + maxSequenceNumber: newSequenceNumber, + lastMessageText: optimisticPaidReportAction.message[0].text, + lastMessageHtml: optimisticPaidReportAction.message[0].html, + hasOutstandingIOU: false, + iouReportID: iouReport.reportID, + }, + }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + value: { + [optimisticPaidReportAction.sequenceNumber]: { + ...optimisticPaidReportAction, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, + }, + }, + }, + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_IOUS}${iouReport.reportID}`, + value: iouReport, + }, + ]; + + const successData = [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + value: { + [optimisticPaidReportAction.sequenceNumber]: { + pendingAction: null, + }, + }, + }, + ]; + + const failureData = [ + { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, + value: { + [optimisticPaidReportAction.sequenceNumber]: { + ...optimisticPaidReportAction, + pendingAction: null, + }, + }, + }, + ]; + + API.write('PayMoneyRequest', { + iouReportID: iouReport.reportID, + paidReportActionID: optimisticPaidReportAction.reportActionID, + paymentMethodType, + clientID: optimisticPaidReportAction.sequenceNumber, + }, {optimisticData, successData, failureData}); +} + +function payMoneyRequestElsewhere(chatReport, iouReport, recipient) { + payMoneyRequest(chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.ELSEWHERE); +} + +function payMoneyRequestViaPaypal(chatReport, iouReport, recipient) { + payMoneyRequest(chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.PAYPAL_ME); + asyncOpenURL(Promise.resolve(), buildPayPalPaymentUrl( + iouReport.total, recipient.payPalMeAddress, iouReport.currency, + )); +} + export { cancelMoneyRequest, splitBill, splitBillAndOpenReport, requestMoney, payIOUReport, - setIOUSelectedCurrency, sendMoneyElsewhere, sendMoneyViaPaypal, + payMoneyRequestElsewhere, + payMoneyRequestViaPaypal, + setIOUSelectedCurrency, }; diff --git a/src/pages/iou/IOUDetailsModal.js b/src/pages/iou/IOUDetailsModal.js index 17369e94891e..f47f49b2525a 100644 --- a/src/pages/iou/IOUDetailsModal.js +++ b/src/pages/iou/IOUDetailsModal.js @@ -99,14 +99,27 @@ class IOUDetailsModal extends Component { * @param {String} paymentMethodType */ performIOUPayment(paymentMethodType) { - IOU.payIOUReport({ - chatReportID: this.props.route.params.chatReportID, - reportID: this.props.route.params.iouReportID, - paymentMethodType, - amount: this.props.iouReport.total, - currency: this.props.iouReport.currency, - requestorPayPalMeAddress: this.props.iouReport.submitterPayPalMeAddress, - }); + const recipient = { + login: this.props.iouReport.ownerEmail, + payPalMeAddress: this.props.iouReport.submitterPayPalMeAddress, + }; + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { + IOU.payMoneyRequestElsewhere( + this.props.chatReport, + this.props.iouReport, + recipient, + ); + return; + } + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { + IOU.payMoneyRequestViaPaypal( + this.props.chatReport, + this.props.iouReport, + recipient, + ); + } } render() { @@ -166,6 +179,9 @@ export default compose( iou: { key: ONYXKEYS.IOU, }, + chatReport: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.chatReportID}`, + }, iouReport: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_IOUS}${route.params.iouReportID}`, }, From 6e72edcd4674a66b769b8ac3cb50aaa0d938dd6f Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 22 Nov 2022 17:09:54 +0100 Subject: [PATCH 018/133] Improve comment Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 68adf102d297..659618cb364a 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -669,7 +669,7 @@ function buildOptimisticReportAction(sequenceNumber, text, file) { * @param {String} chatReportID - Report ID of the chat where the IOU is. * @param {String} currency - IOU currency. * @param {String} locale - Locale where the IOU is created - * @param {Boolean} isSendingMoney - Whether we're requesting or sending money + * @param {Boolean} isSendingMoney - If we send money the IOU should be created as settled * * @returns {Object} */ From f6d293ac1fc7fac61feabf6656ee7c81de1d9b0c Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 22 Nov 2022 17:13:54 +0100 Subject: [PATCH 019/133] Add JSDocs to the new methods --- src/libs/actions/IOU.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 4ca07339a0a8..f709a6ba79a5 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -881,6 +881,12 @@ function sendMoneyViaPaypal(report, amount, currency, comment, managerEmail, rec asyncOpenURL(Promise.resolve(), buildPayPalPaymentUrl(amount, recipient.payPalMeAddress, currency)); } +/** + * @param {Object} chatReport + * @param {Object} iouReport + * @param {Object} recipient + * @param {String} paymentMethodType + */ function payMoneyRequest(chatReport, iouReport, recipient, paymentMethodType) { const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; @@ -962,10 +968,20 @@ function payMoneyRequest(chatReport, iouReport, recipient, paymentMethodType) { }, {optimisticData, successData, failureData}); } +/** + * @param {Object} chatReport + * @param {Object} iouReport + * @param {Object} recipient + */ function payMoneyRequestElsewhere(chatReport, iouReport, recipient) { payMoneyRequest(chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.ELSEWHERE); } +/** + * @param {Object} chatReport + * @param {Object} iouReport + * @param {Object} recipient + */ function payMoneyRequestViaPaypal(chatReport, iouReport, recipient) { payMoneyRequest(chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.PAYPAL_ME); asyncOpenURL(Promise.resolve(), buildPayPalPaymentUrl( From 2776c3a3725ccc61bc943cde14a3ad468f2fb0f1 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 22 Nov 2022 17:43:09 +0100 Subject: [PATCH 020/133] Add clarifying comment --- src/libs/ReportUtils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 659618cb364a..5360a268c0b6 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -679,6 +679,8 @@ function buildOptimisticIOUReport(ownerEmail, userEmail, total, chatReportID, cu style: 'currency', currency, }); + + // stateNum 2: report is settled (submitted) return { cachedTotal: formattedTotal, chatReportID, From ce716bc215e47267a4c36a990bdc78ce0bb7d3b2 Mon Sep 17 00:00:00 2001 From: miroslav Date: Wed, 23 Nov 2022 22:09:38 +0100 Subject: [PATCH 021/133] fix material diff on ReportActionsSkeletonView --- src/components/ReportActionsSkeletonView/index.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/ReportActionsSkeletonView/index.js b/src/components/ReportActionsSkeletonView/index.js index 022bc5f59ad4..650e352fa40b 100644 --- a/src/components/ReportActionsSkeletonView/index.js +++ b/src/components/ReportActionsSkeletonView/index.js @@ -32,11 +32,7 @@ const ReportActionsSkeletonView = (props) => { skeletonViewLines.push(); } } - return ( - <> - {skeletonViewLines} - - ); + return <>{skeletonViewLines}; }; ReportActionsSkeletonView.displayName = 'ReportActionsSkeletonView'; From 4164f9993384b607fc78831fa97bb74136a227b4 Mon Sep 17 00:00:00 2001 From: miroslav Date: Wed, 23 Nov 2022 22:10:12 +0100 Subject: [PATCH 022/133] remove line break diff --- src/components/ReportActionsSkeletonView/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ReportActionsSkeletonView/index.js b/src/components/ReportActionsSkeletonView/index.js index 650e352fa40b..4f7055d98938 100644 --- a/src/components/ReportActionsSkeletonView/index.js +++ b/src/components/ReportActionsSkeletonView/index.js @@ -38,5 +38,4 @@ const ReportActionsSkeletonView = (props) => { ReportActionsSkeletonView.displayName = 'ReportActionsSkeletonView'; ReportActionsSkeletonView.propTypes = propTypes; ReportActionsSkeletonView.defaultProps = defaultProps; - export default ReportActionsSkeletonView; From 4f16c9e967772c746c8372ff0cad86864e3a95be Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 25 Nov 2022 21:38:42 +0100 Subject: [PATCH 023/133] Use a seperate function for each payment method --- src/libs/actions/IOU.js | 136 +++++++++++++++++++++++++--------------- 1 file changed, 85 insertions(+), 51 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 8d17206a871e..60a55cb39ad6 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -731,8 +731,9 @@ function payIOUReport({ * @param {String} paymentMethodType * @param {String} managerEmail - Email of the person sending the money * @param {Object} recipient - The user receiving the money + * @returns {Object} */ -function sendMoney(report, amount, currency, comment, paymentMethodType, managerEmail, recipient) { +function getSendMoneyParams(report, amount, currency, comment, paymentMethodType, managerEmail, recipient) { const newIOUReportDetails = JSON.stringify({ amount, currency, @@ -843,44 +844,20 @@ function sendMoney(report, amount, currency, comment, paymentMethodType, manager optimisticData[2].onyxMethod = CONST.ONYX.METHOD.SET; } - API.write('SendMoney', { - iouReportID: optimisticIOUReport.reportID, - chatReportID: chatReport.reportID, - paidReportActionID: optimisticPaidReportAction.reportActionID, - paymentMethodType, - transactionID: optimisticPaidReportAction.originalMessage.IOUTransactionID, - clientID: optimisticPaidReportAction.sequenceNumber, - newIOUReportDetails, - }, {optimisticData, successData, failureData}); - - Navigation.navigate(ROUTES.getReportRoute(chatReport.reportID)); -} - -/** - * @param {Object} report - * @param {Number} amount - * @param {String} currency - * @param {String} comment - * @param {String} managerEmail - Email of the person sending the money - * @param {Object} recipient - The user receiving the money - */ -function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, recipient) { - const paymentMethodType = CONST.IOU.PAYMENT_TYPE.ELSEWHERE; - sendMoney(report, amount, currency, comment, paymentMethodType, managerEmail, recipient); -} - -/** - * @param {Object} report - * @param {Number} amount - * @param {String} currency - * @param {String} comment - * @param {String} managerEmail - Email of the person sending the money - * @param {Object} recipient - The user receiving the money - */ -function sendMoneyViaPaypal(report, amount, currency, comment, managerEmail, recipient) { - const paymentMethodType = CONST.IOU.PAYMENT_TYPE.PAYPAL_ME; - sendMoney(report, amount, currency, comment, paymentMethodType, managerEmail, recipient); - asyncOpenURL(Promise.resolve(), buildPayPalPaymentUrl(amount, recipient.payPalMeAddress, currency)); + return { + params: { + iouReportID: optimisticIOUReport.reportID, + chatReportID: chatReport.reportID, + paidReportActionID: optimisticPaidReportAction.reportActionID, + paymentMethodType, + transactionID: optimisticPaidReportAction.originalMessage.IOUTransactionID, + clientID: optimisticPaidReportAction.sequenceNumber, + newIOUReportDetails, + }, + optimisticData, + successData, + failureData, + }; } /** @@ -888,8 +865,9 @@ function sendMoneyViaPaypal(report, amount, currency, comment, managerEmail, rec * @param {Object} iouReport * @param {Object} recipient * @param {String} paymentMethodType + * @returns {Object} */ -function payMoneyRequest(chatReport, iouReport, recipient, paymentMethodType) { +function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMethodType) { const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; const optimisticPaidReportAction = ReportUtils.buildOptimisticIOUReportAction( @@ -962,12 +940,55 @@ function payMoneyRequest(chatReport, iouReport, recipient, paymentMethodType) { }, ]; - API.write('PayMoneyRequest', { - iouReportID: iouReport.reportID, - paidReportActionID: optimisticPaidReportAction.reportActionID, - paymentMethodType, - clientID: optimisticPaidReportAction.sequenceNumber, - }, {optimisticData, successData, failureData}); + return { + params: { + iouReportID: iouReport.reportID, + paidReportActionID: optimisticPaidReportAction.reportActionID, + paymentMethodType, + clientID: optimisticPaidReportAction.sequenceNumber, + }, + optimisticData, + successData, + failureData, + }; +} + +/** + * @param {Object} report + * @param {Number} amount + * @param {String} currency + * @param {String} comment + * @param {String} managerEmail - Email of the person sending the money + * @param {Object} recipient - The user receiving the money + */ +function sendMoneyElsewhere(report, amount, currency, comment, managerEmail, recipient) { + const { + params, optimisticData, successData, failureData, + } = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.ELSEWHERE, managerEmail, recipient); + + API.write('SendMoneyElsewhere', params, {optimisticData, successData, failureData}); + + Navigation.navigate(ROUTES.getReportRoute(params.chatReportID)); +} + +/** + * @param {Object} report + * @param {Number} amount + * @param {String} currency + * @param {String} comment + * @param {String} managerEmail - Email of the person sending the money + * @param {Object} recipient - The user receiving the money + */ +function sendMoneyViaPaypal(report, amount, currency, comment, managerEmail, recipient) { + const { + params, optimisticData, successData, failureData, + } = getSendMoneyParams(report, amount, currency, comment, CONST.IOU.PAYMENT_TYPE.PAYPAL_ME, managerEmail, recipient); + + API.write('SendMoneyViaPaypal', params, {optimisticData, successData, failureData}); + + Navigation.navigate(ROUTES.getReportRoute(params.chatReportID)); + + asyncOpenURL(Promise.resolve(), buildPayPalPaymentUrl(amount, recipient.payPalMeAddress, currency)); } /** @@ -976,7 +997,15 @@ function payMoneyRequest(chatReport, iouReport, recipient, paymentMethodType) { * @param {Object} recipient */ function payMoneyRequestElsewhere(chatReport, iouReport, recipient) { - payMoneyRequest(chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.ELSEWHERE); + const { + params, optimisticData, successData, failureData, + } = getPayMoneyRequestParams( + chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + ); + + API.write('PayMoneyRequestElsewhere', params, {optimisticData, successData, failureData}); + + Navigation.navigate(ROUTES.getReportRoute(params.chatReportID)); } /** @@ -985,10 +1014,15 @@ function payMoneyRequestElsewhere(chatReport, iouReport, recipient) { * @param {Object} recipient */ function payMoneyRequestViaPaypal(chatReport, iouReport, recipient) { - payMoneyRequest(chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.PAYPAL_ME); - asyncOpenURL(Promise.resolve(), buildPayPalPaymentUrl( - iouReport.total, recipient.payPalMeAddress, iouReport.currency, - )); + const { + params, optimisticData, successData, failureData, + } = getPayMoneyRequestParams( + chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.PAYPAL_ME, + ); + + API.write('PayMoneyRequestViaPaypal', params, {optimisticData, successData, failureData}); + + Navigation.navigate(ROUTES.getReportRoute(params.chatReportID)); } export { From 8bbd68c9b50bb594f91f4a13c01bc1eed0bfd98e Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 28 Nov 2022 14:04:09 +0100 Subject: [PATCH 024/133] Add generic error messaged to failed payIOU request --- src/libs/actions/IOU.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 60a55cb39ad6..3c4dff38e70b 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -820,6 +820,9 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType [optimisticPaidReportAction.sequenceNumber]: { ...optimisticPaidReportAction, pendingAction: null, + errors: { + [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericCreateFailureMessage'), + }, }, }, }, @@ -935,6 +938,9 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho [optimisticPaidReportAction.sequenceNumber]: { ...optimisticPaidReportAction, pendingAction: null, + errors: { + [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericCreateFailureMessage'), + }, }, }, }, From 53bff3fc753489463b836c3b726e875bec0508a2 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 29 Nov 2022 01:11:08 +0100 Subject: [PATCH 025/133] Allow errored sendMoney report actions to be deleted --- src/libs/actions/IOU.js | 1 - src/pages/home/report/ReportActionItem.js | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 3c4dff38e70b..550c96b3bfdf 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -819,7 +819,6 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType value: { [optimisticPaidReportAction.sequenceNumber]: { ...optimisticPaidReportAction, - pendingAction: null, errors: { [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericCreateFailureMessage'), }, diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 5223f50b1637..66dc7bfb079a 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -196,7 +196,12 @@ class ReportActionItem extends Component { { if (this.props.action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD) { - ReportActions.deleteOptimisticReportAction(this.props.report.reportID, this.props.action.clientID); + const sequenceNumber = this.props.action.actionName + === CONST.REPORT.ACTIONS.TYPE.IOU + ? this.props.action + .sequenceNumber + : this.props.action.clientID; + ReportActions.deleteOptimisticReportAction(this.props.report.reportID, sequenceNumber); } else { ReportActions.clearReportActionErrors(this.props.report.reportID, this.props.action.sequenceNumber); } From ae4a3585eefa95b19c25b09fe4521304328c217d Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 29 Nov 2022 01:21:44 +0100 Subject: [PATCH 026/133] Fix style Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- src/libs/actions/IOU.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 550c96b3bfdf..73ce6283e66c 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1021,9 +1021,7 @@ function payMoneyRequestElsewhere(chatReport, iouReport, recipient) { function payMoneyRequestViaPaypal(chatReport, iouReport, recipient) { const { params, optimisticData, successData, failureData, - } = getPayMoneyRequestParams( - chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.PAYPAL_ME, - ); + } = getPayMoneyRequestParams(chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.PAYPAL_ME); API.write('PayMoneyRequestViaPaypal', params, {optimisticData, successData, failureData}); From 781f8674ca7356704bcf0eab1251ba1ef83ba50b Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 29 Nov 2022 02:26:02 +0100 Subject: [PATCH 027/133] Update generic error message --- src/libs/actions/IOU.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 73ce6283e66c..2224ecca979f 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -938,7 +938,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho ...optimisticPaidReportAction, pendingAction: null, errors: { - [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericCreateFailureMessage'), + [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.other'), }, }, }, From b27c956421fc0217a22f6fdb8f6f7d311dd65cc0 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 30 Nov 2022 02:28:54 +0100 Subject: [PATCH 028/133] Fix navigation to report after settling up --- src/libs/actions/IOU.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 2224ecca979f..e974622f0f24 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1010,7 +1010,7 @@ function payMoneyRequestElsewhere(chatReport, iouReport, recipient) { API.write('PayMoneyRequestElsewhere', params, {optimisticData, successData, failureData}); - Navigation.navigate(ROUTES.getReportRoute(params.chatReportID)); + Navigation.navigate(ROUTES.getReportRoute(chatReport.reportID)); } /** From dfcfb07a384916c679212418b3b88666d4d25327 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 30 Nov 2022 02:35:48 +0100 Subject: [PATCH 029/133] Fix settlment button visible after settling up offline --- src/libs/actions/IOU.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index e974622f0f24..c0b69e3b5648 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -913,7 +913,11 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho { onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_IOUS}${iouReport.reportID}`, - value: iouReport, + value: { + ...iouReport, + hasOutstandingIOU: false, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + }, }, ]; From 36d4382e3608d976103be83c923f1ddbd498fe71 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 30 Nov 2022 14:17:30 +0100 Subject: [PATCH 030/133] Make code more readable --- src/libs/ReportUtils.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index bb7bc043de79..3372051e5113 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -689,7 +689,7 @@ function buildOptimisticIOUReport(ownerEmail, userEmail, total, chatReportID, cu currency, }); - // stateNum 2: report is settled (submitted) + // If we're sending money, hasOutstandingIOU should be false return { cachedTotal: formattedTotal, chatReportID, @@ -699,7 +699,9 @@ function buildOptimisticIOUReport(ownerEmail, userEmail, total, chatReportID, cu ownerEmail, reportID: generateReportID(), state: CONST.REPORT.STATE.SUBMITTED, - stateNum: isSendingMoney ? 2 : 1, + stateNum: isSendingMoney + ? CONST.REPORT.STATE_NUM.SUBMITTED + : CONST.REPORT.STATE_NUM.PROCESSING, total, }; } From 0880140f581d04f7b42914d9e427ea89e526b61e Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 30 Nov 2022 16:11:12 +0100 Subject: [PATCH 031/133] Use correct chatReportID for navigation --- src/libs/actions/IOU.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index c0b69e3b5648..4acbf98d455d 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1029,7 +1029,7 @@ function payMoneyRequestViaPaypal(chatReport, iouReport, recipient) { API.write('PayMoneyRequestViaPaypal', params, {optimisticData, successData, failureData}); - Navigation.navigate(ROUTES.getReportRoute(params.chatReportID)); + Navigation.navigate(ROUTES.getReportRoute(chatReport.reportID)); } export { From 6b483c6ced9c3a42592206f44d43c7184e043bda Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 30 Nov 2022 16:15:41 +0100 Subject: [PATCH 032/133] Add navigation to PayPal.me in PayMoneyRequest --- src/libs/actions/IOU.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 4acbf98d455d..a3e578441d14 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1030,6 +1030,8 @@ function payMoneyRequestViaPaypal(chatReport, iouReport, recipient) { API.write('PayMoneyRequestViaPaypal', params, {optimisticData, successData, failureData}); Navigation.navigate(ROUTES.getReportRoute(chatReport.reportID)); + + asyncOpenURL(Promise.resolve(), buildPayPalPaymentUrl(iouReport.total, recipient.payPalMeAddress, iouReport.currency)); } export { From 6fe2785f674a5a6933663a88dc47c02a6d336ea9 Mon Sep 17 00:00:00 2001 From: miroslav Date: Wed, 30 Nov 2022 16:49:39 +0100 Subject: [PATCH 033/133] disable user interactions in dummy composer --- src/pages/home/ReportScreen.js | 54 ++++++++++++-------- src/pages/home/report/ReportActionCompose.js | 13 ++--- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index ece13cebe88b..f2943cff584e 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -236,7 +236,7 @@ class ReportScreen extends React.Component { {}} report={{reportID: '0'}} reportActions={{}} @@ -297,33 +297,43 @@ class ReportScreen extends React.Component { }} > {(this.isReportReadyForDisplay() && !isLoadingInitialReportActions) && ( - + <> + + + )} {/* Note: The report should be allowed to mount even if the initial report actions are not loaded. If we prevent rendering the report while they are loading then we'll unnecessarily unmount the ReportActionsView which will clear the new marker lines initial state. */} {(!this.isReportReadyForDisplay() || isLoadingInitialReportActions) && ( - + <> + + {}} + report={{reportID: '0'}} + reportActions={{}} + /> + )} - - diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 37e5602ca692..8362263cae60 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -518,6 +518,7 @@ class ReportActionCompose extends React.Component { const isBlockedFromConcierge = ReportUtils.chatIncludesConcierge(this.props.report) && User.isBlockedFromConcierge(this.props.blockedFromConcierge); const inputPlaceholder = this.getInputPlaceholder(); const hasExceededMaxCommentLength = this.comment.length > CONST.MAX_COMMENT_LENGTH; + const isUserInteractionDisabled = this.props.reportID === '0'; return ( @@ -576,7 +577,7 @@ class ReportActionCompose extends React.Component { }} style={styles.composerSizeButton} underlayColor={themeColors.componentBG} - disabled={isBlockedFromConcierge} + disabled={isBlockedFromConcierge || isUserInteractionDisabled} > @@ -594,7 +595,7 @@ class ReportActionCompose extends React.Component { }} style={styles.chatItemAttachButton} underlayColor={themeColors.componentBG} - disabled={isBlockedFromConcierge} + disabled={isBlockedFromConcierge || isUserInteractionDisabled} > @@ -664,7 +665,7 @@ class ReportActionCompose extends React.Component { onPasteFile={displayFileInModal} shouldClear={this.state.textInputShouldClear} onClear={() => this.setTextInputShouldClear(false)} - isDisabled={isComposeDisabled || isBlockedFromConcierge} + isDisabled={isComposeDisabled || isBlockedFromConcierge || isUserInteractionDisabled} selection={this.state.selection} onSelectionChange={this.onSelectionChange} isFullComposerAvailable={this.state.isFullComposerAvailable} @@ -678,7 +679,7 @@ class ReportActionCompose extends React.Component { {canUseTouchScreen() && this.props.isMediumScreenWidth ? null : ( this.focus(true)} onEmojiSelected={this.addEmojiToTextBox} /> @@ -696,7 +697,7 @@ class ReportActionCompose extends React.Component { // Keep focus on the composer when Send message is clicked. // eslint-disable-next-line react/jsx-props-no-multi-spaces onMouseDown={e => e.preventDefault()} - disabled={this.state.isCommentEmpty || isBlockedFromConcierge || hasExceededMaxCommentLength} + disabled={this.state.isCommentEmpty || isBlockedFromConcierge || isUserInteractionDisabled || hasExceededMaxCommentLength} hitSlop={{ top: 3, right: 3, bottom: 3, left: 3, }} From 26e3faf94ce959e69a22e669ad792b1de1323b66 Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Wed, 30 Nov 2022 13:34:04 -0800 Subject: [PATCH 034/133] change report action mini menu button radius --- src/styles/styles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/styles.js b/src/styles/styles.js index f492b7cf0b19..27d09335bd68 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -1927,7 +1927,7 @@ const styles = { ...spacing.p1, ...spacing.mv1, ...spacing.mh1, - ...{borderRadius: variables.componentBorderRadiusSmall}, + ...{borderRadius: variables.buttonBorderRadius}, }, reportActionSystemMessageContainer: { From 552d5d3da2df952ab4cc54b352a9a93f5db4a31f Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Wed, 30 Nov 2022 13:46:40 -0800 Subject: [PATCH 035/133] fixed popover --- src/styles/getTooltipStyles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/getTooltipStyles.js b/src/styles/getTooltipStyles.js index 8fbfb3217d3e..57f749549f25 100644 --- a/src/styles/getTooltipStyles.js +++ b/src/styles/getTooltipStyles.js @@ -116,7 +116,7 @@ export default function getTooltipStyles( tooltipWrapperStyle: { position: 'fixed', backgroundColor: themeColors.heading, - borderRadius: variables.buttonBorderRadius, + borderRadius: variables.componentBorderRadiusNormal, ...tooltipVerticalPadding, ...spacing.ph2, zIndex: variables.tooltipzIndex, From a9fd55456e9f072253c797b1da7d4a86eb13bcb6 Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Wed, 30 Nov 2022 14:30:54 -0800 Subject: [PATCH 036/133] smaller border radius for link popovers --- src/styles/getTooltipStyles.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/getTooltipStyles.js b/src/styles/getTooltipStyles.js index 57f749549f25..134fd75795d0 100644 --- a/src/styles/getTooltipStyles.js +++ b/src/styles/getTooltipStyles.js @@ -116,7 +116,7 @@ export default function getTooltipStyles( tooltipWrapperStyle: { position: 'fixed', backgroundColor: themeColors.heading, - borderRadius: variables.componentBorderRadiusNormal, + borderRadius: variables.componentBorderRadiusSmall, ...tooltipVerticalPadding, ...spacing.ph2, zIndex: variables.tooltipzIndex, From 6313845532c60e9c668be450364e3d7bc5810ea4 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Thu, 1 Dec 2022 17:29:01 +0100 Subject: [PATCH 037/133] Renaming --- src/libs/actions/IOU.js | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index a3e578441d14..77d9bc27a439 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -755,7 +755,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientEmail, managerEmail, amount, chatReport.reportID, currency, preferredLocale, true); const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; - const optimisticPaidReportAction = ReportUtils.buildOptimisticIOUReportAction( + const optimsticReportActionID = ReportUtils.buildOptimisticIOUReportAction( newSequenceNumber, CONST.IOU.REPORT_ACTION_TYPE.PAY, amount, @@ -777,8 +777,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType lastVisitedTimestamp: Date.now(), lastReadSequenceNumber: newSequenceNumber, maxSequenceNumber: newSequenceNumber, - lastMessageText: optimisticPaidReportAction.message[0].text, - lastMessageHtml: optimisticPaidReportAction.message[0].html, + lastMessageText: optimsticReportActionID.message[0].text, + lastMessageHtml: optimsticReportActionID.message[0].html, hasOutstandingIOU: false, iouReportID: optimisticIOUReport.reportID, }, @@ -787,8 +787,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimisticPaidReportAction.sequenceNumber]: { - ...optimisticPaidReportAction, + [optimsticReportActionID.sequenceNumber]: { + ...optimsticReportActionID, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -805,7 +805,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimisticPaidReportAction.sequenceNumber]: { + [optimsticReportActionID.sequenceNumber]: { pendingAction: null, }, }, @@ -817,8 +817,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimisticPaidReportAction.sequenceNumber]: { - ...optimisticPaidReportAction, + [optimsticReportActionID.sequenceNumber]: { + ...optimsticReportActionID, errors: { [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericCreateFailureMessage'), }, @@ -850,10 +850,10 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType params: { iouReportID: optimisticIOUReport.reportID, chatReportID: chatReport.reportID, - paidReportActionID: optimisticPaidReportAction.reportActionID, + reportActionID: optimsticReportActionID.reportActionID, paymentMethodType, - transactionID: optimisticPaidReportAction.originalMessage.IOUTransactionID, - clientID: optimisticPaidReportAction.sequenceNumber, + transactionID: optimsticReportActionID.originalMessage.IOUTransactionID, + clientID: optimsticReportActionID.sequenceNumber, newIOUReportDetails, }, optimisticData, @@ -872,7 +872,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMethodType) { const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; - const optimisticPaidReportAction = ReportUtils.buildOptimisticIOUReportAction( + const optimsticReportActionID = ReportUtils.buildOptimisticIOUReportAction( newSequenceNumber, CONST.IOU.REPORT_ACTION_TYPE.PAY, iouReport.total, @@ -894,8 +894,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho lastVisitedTimestamp: Date.now(), lastReadSequenceNumber: newSequenceNumber, maxSequenceNumber: newSequenceNumber, - lastMessageText: optimisticPaidReportAction.message[0].text, - lastMessageHtml: optimisticPaidReportAction.message[0].html, + lastMessageText: optimsticReportActionID.message[0].text, + lastMessageHtml: optimsticReportActionID.message[0].html, hasOutstandingIOU: false, iouReportID: iouReport.reportID, }, @@ -904,8 +904,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimisticPaidReportAction.sequenceNumber]: { - ...optimisticPaidReportAction, + [optimsticReportActionID.sequenceNumber]: { + ...optimsticReportActionID, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -926,7 +926,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimisticPaidReportAction.sequenceNumber]: { + [optimsticReportActionID.sequenceNumber]: { pendingAction: null, }, }, @@ -938,8 +938,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimisticPaidReportAction.sequenceNumber]: { - ...optimisticPaidReportAction, + [optimsticReportActionID.sequenceNumber]: { + ...optimsticReportActionID, pendingAction: null, errors: { [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.other'), @@ -952,9 +952,9 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho return { params: { iouReportID: iouReport.reportID, - paidReportActionID: optimisticPaidReportAction.reportActionID, + reportActionID: optimsticReportActionID.reportActionID, paymentMethodType, - clientID: optimisticPaidReportAction.sequenceNumber, + clientID: optimsticReportActionID.sequenceNumber, }, optimisticData, successData, From cc3df115a2cf907c729ddc0f9c4a5f850711628a Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Thu, 1 Dec 2022 20:23:19 +0100 Subject: [PATCH 038/133] Fix typo --- src/libs/actions/IOU.js | 43 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 77d9bc27a439..641eb4e3e1c7 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -755,7 +755,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientEmail, managerEmail, amount, chatReport.reportID, currency, preferredLocale, true); const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; - const optimsticReportActionID = ReportUtils.buildOptimisticIOUReportAction( + const optimsticReportAction = ReportUtils.buildOptimisticIOUReportAction( newSequenceNumber, CONST.IOU.REPORT_ACTION_TYPE.PAY, amount, @@ -777,9 +777,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType lastVisitedTimestamp: Date.now(), lastReadSequenceNumber: newSequenceNumber, maxSequenceNumber: newSequenceNumber, - lastMessageText: optimsticReportActionID.message[0].text, - lastMessageHtml: optimsticReportActionID.message[0].html, - hasOutstandingIOU: false, + lastMessageText: optimsticReportAction.message[0].text, + lastMessageHtml: optimsticReportAction.message[0].html, iouReportID: optimisticIOUReport.reportID, }, }, @@ -787,8 +786,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportActionID.sequenceNumber]: { - ...optimsticReportActionID, + [optimsticReportAction.sequenceNumber]: { + ...optimsticReportAction, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -805,7 +804,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportActionID.sequenceNumber]: { + [optimsticReportAction.sequenceNumber]: { pendingAction: null, }, }, @@ -817,8 +816,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportActionID.sequenceNumber]: { - ...optimsticReportActionID, + [optimsticReportAction.sequenceNumber]: { + ...optimsticReportAction, errors: { [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericCreateFailureMessage'), }, @@ -850,10 +849,10 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType params: { iouReportID: optimisticIOUReport.reportID, chatReportID: chatReport.reportID, - reportActionID: optimsticReportActionID.reportActionID, + reportActionID: optimsticReportAction.reportActionID, paymentMethodType, - transactionID: optimsticReportActionID.originalMessage.IOUTransactionID, - clientID: optimsticReportActionID.sequenceNumber, + transactionID: optimsticReportAction.originalMessage.IOUTransactionID, + clientID: optimsticReportAction.sequenceNumber, newIOUReportDetails, }, optimisticData, @@ -872,7 +871,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMethodType) { const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; - const optimsticReportActionID = ReportUtils.buildOptimisticIOUReportAction( + const optimsticReportAction = ReportUtils.buildOptimisticIOUReportAction( newSequenceNumber, CONST.IOU.REPORT_ACTION_TYPE.PAY, iouReport.total, @@ -894,8 +893,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho lastVisitedTimestamp: Date.now(), lastReadSequenceNumber: newSequenceNumber, maxSequenceNumber: newSequenceNumber, - lastMessageText: optimsticReportActionID.message[0].text, - lastMessageHtml: optimsticReportActionID.message[0].html, + lastMessageText: optimsticReportAction.message[0].text, + lastMessageHtml: optimsticReportAction.message[0].html, hasOutstandingIOU: false, iouReportID: iouReport.reportID, }, @@ -904,8 +903,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportActionID.sequenceNumber]: { - ...optimsticReportActionID, + [optimsticReportAction.sequenceNumber]: { + ...optimsticReportAction, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -926,7 +925,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportActionID.sequenceNumber]: { + [optimsticReportAction.sequenceNumber]: { pendingAction: null, }, }, @@ -938,8 +937,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportActionID.sequenceNumber]: { - ...optimsticReportActionID, + [optimsticReportAction.sequenceNumber]: { + ...optimsticReportAction, pendingAction: null, errors: { [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.other'), @@ -952,9 +951,9 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho return { params: { iouReportID: iouReport.reportID, - reportActionID: optimsticReportActionID.reportActionID, + reportActionID: optimsticReportAction.reportActionID, paymentMethodType, - clientID: optimsticReportActionID.sequenceNumber, + clientID: optimsticReportAction.sequenceNumber, }, optimisticData, successData, From 8e425f1c419c46bdc49915bed4d212c7597d6b13 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 2 Dec 2022 00:37:43 +0100 Subject: [PATCH 039/133] Delete deprecated methods --- src/libs/actions/IOU.js | 64 -------------------------------- src/libs/deprecatedAPI.js | 27 -------------- src/pages/iou/IOUDetailsModal.js | 4 +- 3 files changed, 2 insertions(+), 93 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 641eb4e3e1c7..5213bafb4735 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -660,69 +660,6 @@ function buildPayPalPaymentUrl(amount, submitterPayPalMeAddress, currency) { return `https://paypal.me/${submitterPayPalMeAddress}/${(amount / 100)}${currency}`; } -/** - * Pays an IOU Report and then retrieves the iou and chat reports to trigger updates to the UI. - * - * @param {Object} params - * @param {Number} params.chatReportID - * @param {String} params.reportID - * @param {String} params.paymentMethodType - one of CONST.IOU.PAYMENT_TYPE - * @param {Number} params.amount - * @param {String} params.currency - * @param {String} [params.requestorPayPalMeAddress] - * @param {String} [params.newIOUReportDetails] - Extra details required only for send money flow - * - * @return {Promise} - */ -function payIOUReport({ - chatReportID, - reportID, - paymentMethodType, - amount, - currency, - requestorPayPalMeAddress, - newIOUReportDetails, -}) { - Onyx.merge(ONYXKEYS.IOU, {loading: true, error: false}); - - const payIOUPromise = paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY - ? DeprecatedAPI.PayWithWallet({reportID, newIOUReportDetails}) - : DeprecatedAPI.PayIOU({reportID, paymentMethodType, newIOUReportDetails}); - - // Build the url for Paypal.me if they have selected it instead of a manual settlement or Expensify Wallet - let url; - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { - url = buildPayPalPaymentUrl(amount, requestorPayPalMeAddress, currency); - } - - const promiseWithHandlers = payIOUPromise - .then((response) => { - if (response.jsonCode !== 200) { - switch (response.message) { - case 'You cannot pay via Expensify Wallet until you have either a verified deposit bank account or debit card.': - Growl.error(Localize.translateLocal('bankAccount.error.noDefaultDepositAccountOrDebitCardAvailable'), 5000); - break; - case 'This report doesn\'t have reimbursable expenses.': - Growl.error(Localize.translateLocal('iou.noReimbursableExpenses'), 5000); - break; - default: - Growl.error(response.message, 5000); - } - Onyx.merge(ONYXKEYS.IOU, {error: true}); - return; - } - - const chatReportStuff = response.reports[chatReportID]; - const iouReportStuff = response.reports[reportID]; - Report.syncChatAndIOUReports(chatReportStuff, iouReportStuff); - }) - .finally(() => { - Onyx.merge(ONYXKEYS.IOU, {loading: false}); - }); - asyncOpenURL(promiseWithHandlers, url); - return promiseWithHandlers; -} - /** * @param {Object} report * @param {Number} amount @@ -1038,7 +975,6 @@ export { splitBill, splitBillAndOpenReport, requestMoney, - payIOUReport, sendMoneyElsewhere, sendMoneyViaPaypal, payMoneyRequestElsewhere, diff --git a/src/libs/deprecatedAPI.js b/src/libs/deprecatedAPI.js index 1dd77c6eb5f0..7433e376ea6e 100644 --- a/src/libs/deprecatedAPI.js +++ b/src/libs/deprecatedAPI.js @@ -125,31 +125,6 @@ function Graphite_Timer(parameters) { return Network.post(commandName, parameters); } -/** - * @param {Object} parameters - * @param {Number} parameters.reportID - * @param {String} parameters.paymentMethodType - * @param {Object} [parameters.newIOUReportDetails] - * @returns {Promise} - */ -function PayIOU(parameters) { - const commandName = 'PayIOU'; - requireParameters(['reportID', 'paymentMethodType'], parameters, commandName); - return Network.post(commandName, parameters); -} - -/** - * @param {Object} parameters - * @param {Number} parameters.reportID - * @param {Object} [parameters.newIOUReportDetails] - * @returns {Promise} - */ -function PayWithWallet(parameters) { - const commandName = 'PayWithWallet'; - requireParameters(['reportID'], parameters, commandName); - return Network.post(commandName, parameters); -} - /** * @param {Object} parameters * @param {String} parameters.emailList @@ -326,8 +301,6 @@ export { GetStatementPDF, GetIOUReport, Graphite_Timer, - PayIOU, - PayWithWallet, PersonalDetails_GetForEmails, PersonalDetails_Update, ResendValidateCode, diff --git a/src/pages/iou/IOUDetailsModal.js b/src/pages/iou/IOUDetailsModal.js index f47f49b2525a..ed6332a450d4 100644 --- a/src/pages/iou/IOUDetailsModal.js +++ b/src/pages/iou/IOUDetailsModal.js @@ -98,7 +98,7 @@ class IOUDetailsModal extends Component { /** * @param {String} paymentMethodType */ - performIOUPayment(paymentMethodType) { + payMoneyRequest(paymentMethodType) { const recipient = { login: this.props.iouReport.ownerEmail, payPalMeAddress: this.props.iouReport.submitterPayPalMeAddress, @@ -152,7 +152,7 @@ class IOUDetailsModal extends Component { this.performIOUPayment(paymentMethodType)} + onPress={paymentMethodType => this.payMoneyRequest(paymentMethodType)} shouldShowPaypal={Boolean(lodashGet(this.props, 'iouReport.submitterPayPalMeAddress'))} currency={lodashGet(this.props, 'iouReport.currency')} enablePaymentsRoute={ROUTES.IOU_DETAILS_ENABLE_PAYMENTS} From dec1ab612db9dcca68d9f284f7912c27ee7db98a Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Thu, 1 Dec 2022 16:53:27 -0800 Subject: [PATCH 040/133] styled icons --- src/components/ContextMenuItem.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/ContextMenuItem.js b/src/components/ContextMenuItem.js index 96f28164e166..f6f3d0c43a6a 100644 --- a/src/components/ContextMenuItem.js +++ b/src/components/ContextMenuItem.js @@ -1,6 +1,6 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; -import {Pressable} from 'react-native'; +import {Pressable, View} from 'react-native'; import MenuItem from './MenuItem'; import Tooltip from './Tooltip'; import Icon from './Icon'; @@ -87,10 +87,12 @@ class ContextMenuItem extends Component { } > {({hovered, pressed}) => ( - + + + )} From ddbe82114435b11a1fc03f5c2f6bb3d7d81a4f08 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 2 Dec 2022 01:54:13 +0100 Subject: [PATCH 041/133] Use appropriate error message --- src/libs/actions/IOU.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 5e1e74849792..5253027e850a 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -758,7 +758,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType [optimsticReportAction.sequenceNumber]: { ...optimsticReportAction, errors: { - [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.genericCreateFailureMessage'), + [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.other'), }, }, }, From c85ece43c92c5b6942dc61fdd7177c8c7fb5ba25 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 2 Dec 2022 10:13:21 +0700 Subject: [PATCH 042/133] Remove shouldComponentUpdate --- src/components/Avatar.js | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/src/components/Avatar.js b/src/components/Avatar.js index 57530e3007c4..a0f1dbf43b57 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -1,4 +1,4 @@ -import React, {Component} from 'react'; +import React, {PureComponent} from 'react'; import {View, Image} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; @@ -47,7 +47,7 @@ const defaultProps = { fallbackIcon: Expensicons.FallbackAvatar, }; -class Avatar extends Component { +class Avatar extends PureComponent { constructor(props) { super(props); this.state = { @@ -55,30 +55,6 @@ class Avatar extends Component { }; } - shouldComponentUpdate(nextProps, nextState) { - if ( - lodashGet(this.props.network, 'isOffline') - && !lodashGet(nextProps.network, 'isOffline') - ) { - return true; - } - if (this.props.source !== nextProps.source) { - return true; - } - if (this.state.imageError !== nextState.imageError) { - return true; - } - - if (this.props.fill !== nextProps.fill) { - return true; - } - if (this.props.size !== nextProps.size) { - return true; - } - - return false; - } - componentDidUpdate(prevProps) { if ( !this.state.imageError || !lodashGet(prevProps.network, 'isOffline') From 9611bf99eb9ed057ee8f1d2e269b5e9f495e03e4 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 2 Dec 2022 10:24:12 +0700 Subject: [PATCH 043/133] fix linting --- src/components/Avatar.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Avatar.js b/src/components/Avatar.js index a0f1dbf43b57..52679823cfec 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -56,9 +56,9 @@ class Avatar extends PureComponent { } componentDidUpdate(prevProps) { + const isReconnecting = prevProps.network.isOffline && !this.props.network.isOffline; if ( - !this.state.imageError || !lodashGet(prevProps.network, 'isOffline') - || lodashGet(this.props.network, 'isOffline') + !this.state.imageError || !isReconnecting ) { return; } From 222c7404b19578cbefadf1087b2d2e6fb22f34d5 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 2 Dec 2022 17:28:37 +0700 Subject: [PATCH 044/133] fix linting and merge with main --- src/components/Avatar.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/Avatar.js b/src/components/Avatar.js index 52679823cfec..e3434bb980c7 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -2,7 +2,6 @@ import React, {PureComponent} from 'react'; import {View, Image} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; -import lodashGet from 'lodash/get'; import stylePropTypes from '../styles/stylePropTypes'; import Icon from './Icon'; import themeColors from '../styles/themes/default'; @@ -57,9 +56,7 @@ class Avatar extends PureComponent { componentDidUpdate(prevProps) { const isReconnecting = prevProps.network.isOffline && !this.props.network.isOffline; - if ( - !this.state.imageError || !isReconnecting - ) { + if (!this.state.imageError || !isReconnecting) { return; } this.setState({imageError: false}); From f767df88665e7e5fce0b4e232ef7421b00cd2f23 Mon Sep 17 00:00:00 2001 From: miroslav Date: Fri, 2 Dec 2022 11:49:18 +0100 Subject: [PATCH 045/133] introduce shouldDisableCompose prop in ReportFooter --- src/pages/home/ReportScreen.js | 10 ++-------- src/pages/home/report/ReportActionCompose.js | 15 +++++++-------- src/pages/home/report/ReportFooter.js | 17 ++++++++++++----- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 0b0e970ccee5..8ceada8112ca 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -238,11 +238,8 @@ class ReportScreen extends React.Component { {}} - report={{reportID: '0'}} - reportActions={{}} /> @@ -325,11 +322,8 @@ class ReportScreen extends React.Component { containerHeight={this.state.skeletonViewContainerHeight} /> {}} - report={{reportID: '0'}} - reportActions={{}} /> )} diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index a7958bbe97d8..3b6f36dcd534 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -86,7 +86,7 @@ const propTypes = { isFocused: PropTypes.bool.isRequired, /** Is the composer full size */ - isComposerFullSize: PropTypes.bool.isRequired, + isComposerFullSize: PropTypes.bool, // The NVP describing a user's block status blockedFromConcierge: PropTypes.shape({ @@ -525,7 +525,6 @@ class ReportActionCompose extends React.Component { const isBlockedFromConcierge = ReportUtils.chatIncludesConcierge(this.props.report) && User.isBlockedFromConcierge(this.props.blockedFromConcierge); const inputPlaceholder = this.getInputPlaceholder(); const hasExceededMaxCommentLength = this.comment.length > CONST.MAX_COMMENT_LENGTH; - const isUserInteractionDisabled = this.props.reportID === '0'; return ( @@ -584,7 +583,7 @@ class ReportActionCompose extends React.Component { }} style={styles.composerSizeButton} underlayColor={themeColors.componentBG} - disabled={isBlockedFromConcierge || isUserInteractionDisabled} + disabled={isBlockedFromConcierge || this.props.disabled} > @@ -602,7 +601,7 @@ class ReportActionCompose extends React.Component { }} style={styles.chatItemAttachButton} underlayColor={themeColors.componentBG} - disabled={isBlockedFromConcierge || isUserInteractionDisabled} + disabled={isBlockedFromConcierge || this.props.disabled} > @@ -672,7 +671,7 @@ class ReportActionCompose extends React.Component { onPasteFile={displayFileInModal} shouldClear={this.state.textInputShouldClear} onClear={() => this.setTextInputShouldClear(false)} - isDisabled={isComposeDisabled || isBlockedFromConcierge || isUserInteractionDisabled} + isDisabled={isComposeDisabled || isBlockedFromConcierge || this.props.disabled} selection={this.state.selection} onSelectionChange={this.onSelectionChange} isFullComposerAvailable={this.state.isFullComposerAvailable} @@ -686,7 +685,7 @@ class ReportActionCompose extends React.Component { {canUseTouchScreen() && this.props.isMediumScreenWidth ? null : ( this.focus(true)} onEmojiSelected={this.addEmojiToTextBox} /> @@ -704,7 +703,7 @@ class ReportActionCompose extends React.Component { // Keep focus on the composer when Send message is clicked. // eslint-disable-next-line react/jsx-props-no-multi-spaces onMouseDown={e => e.preventDefault()} - disabled={this.state.isCommentEmpty || isBlockedFromConcierge || isUserInteractionDisabled || hasExceededMaxCommentLength} + disabled={this.state.isCommentEmpty || isBlockedFromConcierge || this.props.disabled || hasExceededMaxCommentLength} hitSlop={{ top: 3, right: 3, bottom: 3, left: 3, }} diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index de0d47ed8186..3aa2feff5f80 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -21,16 +21,16 @@ import reportPropTypes from '../../reportPropTypes'; const propTypes = { /** Report object for the current report */ - report: reportPropTypes.isRequired, + report: reportPropTypes, /** Report actions for the current report */ - reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)).isRequired, + reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), /** Offline status */ isOffline: PropTypes.bool.isRequired, /** Callback fired when the comment is submitted */ - onSubmitComment: PropTypes.func.isRequired, + onSubmitComment: PropTypes.func, /** Any errors associated with an attempt to create a chat */ // eslint-disable-next-line react/forbid-prop-types @@ -42,13 +42,20 @@ const propTypes = { /** Whether the composer input should be shown */ shouldShowComposeInput: PropTypes.bool, + /** Whether user interactions should be disabled */ + shouldDisableCompose: PropTypes.bool, + ...windowDimensionsPropTypes, }; const defaultProps = { - shouldShowComposeInput: true, + report: {reportID: '0'}, + reportActions: {}, + onSubmitComment: () => {}, errors: {}, pendingAction: null, + shouldShowComposeInput: true, + shouldDisableCompose: false, }; class ReportFooter extends React.Component { @@ -94,12 +101,12 @@ class ReportFooter extends React.Component { contentContainerStyle={this.props.isComposerFullSize ? styles.flex1 : {}} > From 05bfe3a734d5af60202b3032797299a108ec463c Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 2 Dec 2022 13:32:02 +0100 Subject: [PATCH 046/133] Cleanup --- src/libs/actions/IOU.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 5253027e850a..f5223666e242 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -5,10 +5,8 @@ import Str from 'expensify-common/lib/str'; import CONST from '../../CONST'; import ONYXKEYS from '../../ONYXKEYS'; import ROUTES from '../../ROUTES'; -import * as DeprecatedAPI from '../deprecatedAPI'; import * as Report from './Report'; import Navigation from '../Navigation/Navigation'; -import Growl from '../Growl'; import * as Localize from '../Localize'; import asyncOpenURL from '../asyncOpenURL'; import * as API from '../API'; From 04af65083d8579530b70aa26ee2cb70dfd0557f1 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 2 Dec 2022 14:03:04 +0100 Subject: [PATCH 047/133] Apply requested changes --- src/libs/ReportUtils.js | 4 +-- src/libs/actions/IOU.js | 58 +++++++++++++++---------------- src/libs/actions/ReportActions.js | 14 -------- 3 files changed, 31 insertions(+), 45 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 95af3bc2d923..73ce12ef9f58 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -689,12 +689,12 @@ function buildOptimisticIOUReport(ownerEmail, userEmail, total, chatReportID, cu currency, }); - // If we're sending money, hasOutstandingIOU should be false return { + // If we're sending money, hasOutstandingIOU should be false + hasOutstandingIOU: !isSendingMoney, cachedTotal: formattedTotal, chatReportID, currency, - hasOutstandingIOU: !isSendingMoney, managerEmail: userEmail, ownerEmail, reportID: generateReportID(), diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index f5223666e242..61a2d7197806 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -156,7 +156,7 @@ function requestMoney(report, amount, currency, recipientEmail, participant, com // Now, let's add the data we need just when we are creating a new chat report if (isNewChat) { - const optimisticCreateAction = ReportUtils.buildOptimisticCreatedReportAction(recipientEmail); + const optimisticCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(recipientEmail); // Change the method to set for new reports because it doesn't exist yet, is faster, // and we need the data to be available when we navigate to the chat page @@ -167,7 +167,7 @@ function requestMoney(report, amount, currency, recipientEmail, participant, com }; optimisticData[1].onyxMethod = CONST.ONYX.METHOD.SET; optimisticData[1].value = { - ...optimisticCreateAction, + ...optimisticCreatedAction, ...optimisticData[1].value, }; optimisticData[2].onyxMethod = CONST.ONYX.METHOD.SET; @@ -674,13 +674,13 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType const newIOUReportDetails = JSON.stringify({ amount, currency, - requestorEmail: recipient.login, + requestorEmail: OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login), comment, idempotencyKey: Str.guid(), }); const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login); - let chatReport = lodashGet(report, 'reportID', null) ? report : null; + let chatReport = report.reportID ? report : null; let isNewChat = false; if (!chatReport) { chatReport = ReportUtils.getChatByParticipants([recipientEmail]); @@ -690,9 +690,11 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType isNewChat = true; } const optimisticIOUReport = ReportUtils.buildOptimisticIOUReport(recipientEmail, managerEmail, amount, chatReport.reportID, currency, preferredLocale, true); + + // This will be deprecated soon, in case the migration happens before this PR is merged we'll need to adjust the code here const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; - const optimsticReportAction = ReportUtils.buildOptimisticIOUReportAction( + const optimsticIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( newSequenceNumber, CONST.IOU.REPORT_ACTION_TYPE.PAY, amount, @@ -714,8 +716,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType lastVisitedTimestamp: Date.now(), lastReadSequenceNumber: newSequenceNumber, maxSequenceNumber: newSequenceNumber, - lastMessageText: optimsticReportAction.message[0].text, - lastMessageHtml: optimsticReportAction.message[0].html, + lastMessageText: optimsticIOUReportAction.message[0].text, + lastMessageHtml: optimsticIOUReportAction.message[0].html, iouReportID: optimisticIOUReport.reportID, }, }, @@ -723,8 +725,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportAction.sequenceNumber]: { - ...optimsticReportAction, + [optimsticIOUReportAction.sequenceNumber]: { + ...optimsticIOUReportAction, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -741,7 +743,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportAction.sequenceNumber]: { + [optimsticIOUReportAction.sequenceNumber]: { pendingAction: null, }, }, @@ -753,8 +755,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportAction.sequenceNumber]: { - ...optimsticReportAction, + [optimsticIOUReportAction.sequenceNumber]: { + ...optimsticIOUReportAction, errors: { [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.other'), }, @@ -786,10 +788,10 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType params: { iouReportID: optimisticIOUReport.reportID, chatReportID: chatReport.reportID, - reportActionID: optimsticReportAction.reportActionID, + reportActionID: optimsticIOUReportAction.reportActionID, paymentMethodType, - transactionID: optimsticReportAction.originalMessage.IOUTransactionID, - clientID: optimsticReportAction.sequenceNumber, + transactionID: optimsticIOUReportAction.originalMessage.IOUTransactionID, + clientID: optimsticIOUReportAction.sequenceNumber, newIOUReportDetails, }, optimisticData, @@ -808,7 +810,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMethodType) { const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; - const optimsticReportAction = ReportUtils.buildOptimisticIOUReportAction( + const optimsticIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( newSequenceNumber, CONST.IOU.REPORT_ACTION_TYPE.PAY, iouReport.total, @@ -820,7 +822,6 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho iouReport.reportID, ); - // First, add data that will be used in all cases const optimisticData = [ { onyxMethod: CONST.ONYX.METHOD.MERGE, @@ -830,8 +831,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho lastVisitedTimestamp: Date.now(), lastReadSequenceNumber: newSequenceNumber, maxSequenceNumber: newSequenceNumber, - lastMessageText: optimsticReportAction.message[0].text, - lastMessageHtml: optimsticReportAction.message[0].html, + lastMessageText: optimsticIOUReportAction.message[0].text, + lastMessageHtml: optimsticIOUReportAction.message[0].html, hasOutstandingIOU: false, iouReportID: iouReport.reportID, }, @@ -840,8 +841,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportAction.sequenceNumber]: { - ...optimsticReportAction, + [optimsticIOUReportAction.sequenceNumber]: { + ...optimsticIOUReportAction, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -862,7 +863,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportAction.sequenceNumber]: { + [optimsticIOUReportAction.sequenceNumber]: { pendingAction: null, }, }, @@ -874,8 +875,9 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticReportAction.sequenceNumber]: { - ...optimsticReportAction, + [optimsticIOUReportAction.sequenceNumber]: { + hasOutstandingIOU: true, + stateNum: CONST.REPORT.STATE_NUM.PROCESSING, pendingAction: null, errors: { [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.other'), @@ -888,9 +890,9 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho return { params: { iouReportID: iouReport.reportID, - reportActionID: optimsticReportAction.reportActionID, + reportActionID: optimsticIOUReportAction.reportActionID, paymentMethodType, - clientID: optimsticReportAction.sequenceNumber, + clientID: optimsticIOUReportAction.sequenceNumber, }, optimisticData, successData, @@ -944,9 +946,7 @@ function sendMoneyViaPaypal(report, amount, currency, comment, managerEmail, rec function payMoneyRequestElsewhere(chatReport, iouReport, recipient) { const { params, optimisticData, successData, failureData, - } = getPayMoneyRequestParams( - chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.ELSEWHERE, - ); + } = getPayMoneyRequestParams(chatReport, iouReport, recipient, CONST.IOU.PAYMENT_TYPE.ELSEWHERE); API.write('PayMoneyRequestElsewhere', params, {optimisticData, successData, failureData}); diff --git a/src/libs/actions/ReportActions.js b/src/libs/actions/ReportActions.js index 828cdecdda1d..c56bcabaae58 100644 --- a/src/libs/actions/ReportActions.js +++ b/src/libs/actions/ReportActions.js @@ -23,21 +23,7 @@ function clearReportActionErrors(reportID, sequenceNumber) { }); } -/** - * This method clears the errors for a chat where send money action was done - * @param {String} chatReportID - * @param {String} reportActionID - */ -function clearSendMoneyErrors(chatReportID, reportActionID) { - Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, { - [reportActionID]: { - errors: null, - }, - }); -} - export { clearReportActionErrors, deleteOptimisticReportAction, - clearSendMoneyErrors, }; From 8272d1d62a9426a424917058d663709f2eab9b52 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 2 Dec 2022 14:05:20 +0100 Subject: [PATCH 048/133] Fix typo --- src/libs/actions/IOU.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 61a2d7197806..c1e62a536f77 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -767,7 +767,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType // Now, let's add the data we need just when we are creating a new chat report if (isNewChat) { - const optimisticCreateAction = ReportUtils.buildOptimisticCreatedReportAction(recipientEmail); + const optimisticCreatedAction = ReportUtils.buildOptimisticCreatedReportAction(recipientEmail); // Change the method to set for new reports because it doesn't exist yet, is faster, // and we need the data to be available when we navigate to the chat page @@ -778,7 +778,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType }; optimisticData[1].onyxMethod = CONST.ONYX.METHOD.SET; optimisticData[1].value = { - ...optimisticCreateAction, + ...optimisticCreatedAction, ...optimisticData[1].value, }; optimisticData[2].onyxMethod = CONST.ONYX.METHOD.SET; From b457ad03282409f7bc1f9d45a98d819048db11c1 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 2 Dec 2022 14:14:17 +0100 Subject: [PATCH 049/133] Deprecate REPORT_IOUS Onyx key --- src/libs/actions/IOU.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index c1e62a536f77..541294ea2b08 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -733,7 +733,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType }, { onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_IOUS}${optimisticIOUReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${optimisticIOUReport.reportID}`, value: optimisticIOUReport, }, ]; @@ -849,7 +849,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho }, { onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_IOUS}${iouReport.reportID}`, + key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport.reportID}`, value: { ...iouReport, hasOutstandingIOU: false, From 39d28840c759dfca2c5e30d5c6e93ab6f02a38c7 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 2 Dec 2022 14:29:01 +0100 Subject: [PATCH 050/133] Fix IOUBadge changing when we send money --- src/libs/actions/IOU.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 541294ea2b08..3305df41af09 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -718,7 +718,6 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType maxSequenceNumber: newSequenceNumber, lastMessageText: optimsticIOUReportAction.message[0].text, lastMessageHtml: optimsticIOUReportAction.message[0].html, - iouReportID: optimisticIOUReport.reportID, }, }, { From d614a79f108030576f64a8914e069fecbbac006a Mon Sep 17 00:00:00 2001 From: miroslav Date: Fri, 2 Dec 2022 15:38:15 +0100 Subject: [PATCH 051/133] add disabled in propType of ReportActionCompose --- src/pages/home/report/ReportActionCompose.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 3b6f36dcd534..c4025995e65c 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -88,6 +88,9 @@ const propTypes = { /** Is the composer full size */ isComposerFullSize: PropTypes.bool, + /** Whether user interactions should be disabled */ + disabled: PropTypes.bool, + // The NVP describing a user's block status blockedFromConcierge: PropTypes.shape({ // The date that the user will be unblocked From 2de2def0a3684fd71e458f2c7b0ef649e0bf5089 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 2 Dec 2022 16:11:19 +0100 Subject: [PATCH 052/133] Keep deprecated payWithWallet as it should be removed in a different PR --- src/libs/actions/IOU.js | 62 ++++++++++++++++++++++++++++++++ src/libs/deprecatedAPI.js | 13 +++++++ src/pages/iou/IOUDetailsModal.js | 12 +++++++ 3 files changed, 87 insertions(+) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 3305df41af09..31e37bf46d5d 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -5,8 +5,10 @@ import Str from 'expensify-common/lib/str'; import CONST from '../../CONST'; import ONYXKEYS from '../../ONYXKEYS'; import ROUTES from '../../ROUTES'; +import * as DeprecatedAPI from '../deprecatedAPI'; import * as Report from './Report'; import Navigation from '../Navigation/Navigation'; +import Growl from '../Growl'; import * as Localize from '../Localize'; import asyncOpenURL from '../asyncOpenURL'; import * as API from '../API'; @@ -660,6 +662,65 @@ function buildPayPalPaymentUrl(amount, submitterPayPalMeAddress, currency) { return `https://paypal.me/${submitterPayPalMeAddress}/${(amount / 100)}${currency}`; } +/** + * Pays an IOU Report and then retrieves the iou and chat reports to trigger updates to the UI. + * + * @param {Object} params + * @param {Number} params.chatReportID + * @param {String} params.reportID + * @param {String} params.paymentMethodType - one of CONST.IOU.PAYMENT_TYPE + * @param {Number} params.amount + * @param {String} params.currency + * @param {String} [params.requestorPayPalMeAddress] + * @param {String} [params.newIOUReportDetails] - Extra details required only for send money flow + * + * @return {Promise} + */ +function payIOUReport({ + chatReportID, + reportID, + paymentMethodType, + amount, + currency, + requestorPayPalMeAddress, + newIOUReportDetails, +}) { + Onyx.merge(ONYXKEYS.IOU, {loading: true, error: false}); + + // Build the url for Paypal.me if they have selected it instead of a manual settlement or Expensify Wallet + let url; + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { + url = buildPayPalPaymentUrl(amount, requestorPayPalMeAddress, currency); + } + + const promiseWithHandlers = DeprecatedAPI.PayWithWallet({reportID, newIOUReportDetails}) + .then((response) => { + if (response.jsonCode !== 200) { + switch (response.message) { + case 'You cannot pay via Expensify Wallet until you have either a verified deposit bank account or debit card.': + Growl.error(Localize.translateLocal('bankAccount.error.noDefaultDepositAccountOrDebitCardAvailable'), 5000); + break; + case 'This report doesn\'t have reimbursable expenses.': + Growl.error(Localize.translateLocal('iou.noReimbursableExpenses'), 5000); + break; + default: + Growl.error(response.message, 5000); + } + Onyx.merge(ONYXKEYS.IOU, {error: true}); + return; + } + + const chatReportStuff = response.reports[chatReportID]; + const iouReportStuff = response.reports[reportID]; + Report.syncChatAndIOUReports(chatReportStuff, iouReportStuff); + }) + .finally(() => { + Onyx.merge(ONYXKEYS.IOU, {loading: false}); + }); + asyncOpenURL(promiseWithHandlers, url); + return promiseWithHandlers; +} + /** * @param {Object} report * @param {Number} amount @@ -974,6 +1035,7 @@ export { splitBill, splitBillAndOpenReport, requestMoney, + payIOUReport, sendMoneyElsewhere, sendMoneyViaPaypal, payMoneyRequestElsewhere, diff --git a/src/libs/deprecatedAPI.js b/src/libs/deprecatedAPI.js index 5f77d0daa8f2..61731c29208f 100644 --- a/src/libs/deprecatedAPI.js +++ b/src/libs/deprecatedAPI.js @@ -75,6 +75,18 @@ function Get(parameters, shouldUseSecure = false) { return Network.post(commandName, parameters, CONST.NETWORK.METHOD.POST, shouldUseSecure); } +/** + * @param {Object} parameters + * @param {Number} parameters.reportID + * @param {Object} [parameters.newIOUReportDetails] + * @returns {Promise} + */ +function PayWithWallet(parameters) { + const commandName = 'PayWithWallet'; + requireParameters(['reportID'], parameters, commandName); + return Network.post(commandName, parameters); +} + /** * @param {Object} parameters * @param {Object} parameters.details @@ -138,6 +150,7 @@ export { DeleteLogin, Get, GetStatementPDF, + PayWithWallet, PersonalDetails_Update, ResendValidateCode, SetNameValuePair, diff --git a/src/pages/iou/IOUDetailsModal.js b/src/pages/iou/IOUDetailsModal.js index 6a632bfe32df..0d45271ab5b1 100644 --- a/src/pages/iou/IOUDetailsModal.js +++ b/src/pages/iou/IOUDetailsModal.js @@ -119,6 +119,18 @@ class IOUDetailsModal extends Component { this.props.iouReport, recipient, ); + return; + } + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { + IOU.payIOUReport({ + chatReportID: this.props.route.params.chatReportID, + reportID: this.props.route.params.iouReportID, + paymentMethodType, + amount: this.props.iouReport.total, + currency: this.props.iouReport.currency, + requestorPayPalMeAddress: this.props.iouReport.submitterPayPalMeAddress, + }); } } From 61fb7f7e2f28e0afbb659c50c79c7080e442cbb4 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 2 Dec 2022 22:39:56 +0700 Subject: [PATCH 053/133] revert import --- 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 e3434bb980c7..a236c63b2cb5 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -1,5 +1,5 @@ import React, {PureComponent} from 'react'; -import {View, Image} from 'react-native'; +import {Image, View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; import stylePropTypes from '../styles/stylePropTypes'; From 281d32bc174de6ea0ec445209d824eb96aaf3138 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 2 Dec 2022 17:01:44 +0100 Subject: [PATCH 054/133] Update report's lastActionCreated in IOU flows --- src/libs/actions/IOU.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 31e37bf46d5d..6baf452ca300 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -775,6 +775,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType value: { ...chatReport, lastVisitedTimestamp: Date.now(), + lastActionCreated: optimsticIOUReportAction.created, lastReadSequenceNumber: newSequenceNumber, maxSequenceNumber: newSequenceNumber, lastMessageText: optimsticIOUReportAction.message[0].text, @@ -889,6 +890,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho value: { ...chatReport, lastVisitedTimestamp: Date.now(), + lastActionCreated: optimsticIOUReportAction.created, lastReadSequenceNumber: newSequenceNumber, maxSequenceNumber: newSequenceNumber, lastMessageText: optimsticIOUReportAction.message[0].text, From 7bba84b6a01d0aa5e2d639a4b0d8014a733d1abe Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Fri, 2 Dec 2022 17:16:34 +0100 Subject: [PATCH 055/133] Fix typo --- src/libs/actions/IOU.js | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 6baf452ca300..fca07e1d2904 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -755,7 +755,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType // This will be deprecated soon, in case the migration happens before this PR is merged we'll need to adjust the code here const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; - const optimsticIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( + const optimisticIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( newSequenceNumber, CONST.IOU.REPORT_ACTION_TYPE.PAY, amount, @@ -775,19 +775,19 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType value: { ...chatReport, lastVisitedTimestamp: Date.now(), - lastActionCreated: optimsticIOUReportAction.created, + lastActionCreated: optimisticIOUReportAction.created, lastReadSequenceNumber: newSequenceNumber, maxSequenceNumber: newSequenceNumber, - lastMessageText: optimsticIOUReportAction.message[0].text, - lastMessageHtml: optimsticIOUReportAction.message[0].html, + lastMessageText: optimisticIOUReportAction.message[0].text, + lastMessageHtml: optimisticIOUReportAction.message[0].html, }, }, { onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticIOUReportAction.sequenceNumber]: { - ...optimsticIOUReportAction, + [optimisticIOUReportAction.sequenceNumber]: { + ...optimisticIOUReportAction, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -804,7 +804,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticIOUReportAction.sequenceNumber]: { + [optimisticIOUReportAction.sequenceNumber]: { pendingAction: null, }, }, @@ -816,8 +816,8 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticIOUReportAction.sequenceNumber]: { - ...optimsticIOUReportAction, + [optimisticIOUReportAction.sequenceNumber]: { + ...optimisticIOUReportAction, errors: { [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.other'), }, @@ -849,10 +849,10 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType params: { iouReportID: optimisticIOUReport.reportID, chatReportID: chatReport.reportID, - reportActionID: optimsticIOUReportAction.reportActionID, + reportActionID: optimisticIOUReportAction.reportActionID, paymentMethodType, - transactionID: optimsticIOUReportAction.originalMessage.IOUTransactionID, - clientID: optimsticIOUReportAction.sequenceNumber, + transactionID: optimisticIOUReportAction.originalMessage.IOUTransactionID, + clientID: optimisticIOUReportAction.sequenceNumber, newIOUReportDetails, }, optimisticData, @@ -871,7 +871,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMethodType) { const newSequenceNumber = Report.getMaxSequenceNumber(chatReport.reportID) + 1; - const optimsticIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( + const optimisticIOUReportAction = ReportUtils.buildOptimisticIOUReportAction( newSequenceNumber, CONST.IOU.REPORT_ACTION_TYPE.PAY, iouReport.total, @@ -890,11 +890,11 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho value: { ...chatReport, lastVisitedTimestamp: Date.now(), - lastActionCreated: optimsticIOUReportAction.created, + lastActionCreated: optimisticIOUReportAction.created, lastReadSequenceNumber: newSequenceNumber, maxSequenceNumber: newSequenceNumber, - lastMessageText: optimsticIOUReportAction.message[0].text, - lastMessageHtml: optimsticIOUReportAction.message[0].html, + lastMessageText: optimisticIOUReportAction.message[0].text, + lastMessageHtml: optimisticIOUReportAction.message[0].html, hasOutstandingIOU: false, iouReportID: iouReport.reportID, }, @@ -903,8 +903,8 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticIOUReportAction.sequenceNumber]: { - ...optimsticIOUReportAction, + [optimisticIOUReportAction.sequenceNumber]: { + ...optimisticIOUReportAction, pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, }, }, @@ -925,7 +925,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticIOUReportAction.sequenceNumber]: { + [optimisticIOUReportAction.sequenceNumber]: { pendingAction: null, }, }, @@ -937,7 +937,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho onyxMethod: CONST.ONYX.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { - [optimsticIOUReportAction.sequenceNumber]: { + [optimisticIOUReportAction.sequenceNumber]: { hasOutstandingIOU: true, stateNum: CONST.REPORT.STATE_NUM.PROCESSING, pendingAction: null, @@ -952,9 +952,9 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho return { params: { iouReportID: iouReport.reportID, - reportActionID: optimsticIOUReportAction.reportActionID, + reportActionID: optimisticIOUReportAction.reportActionID, paymentMethodType, - clientID: optimsticIOUReportAction.sequenceNumber, + clientID: optimisticIOUReportAction.sequenceNumber, }, optimisticData, successData, From 569c02f6550b283ef89b343a9c54b49e493102d3 Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Fri, 2 Dec 2022 14:45:27 -0800 Subject: [PATCH 056/133] smaller icons --- src/components/ContextMenuItem.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/components/ContextMenuItem.js b/src/components/ContextMenuItem.js index f6f3d0c43a6a..e6362ecf6654 100644 --- a/src/components/ContextMenuItem.js +++ b/src/components/ContextMenuItem.js @@ -87,12 +87,11 @@ class ContextMenuItem extends Component { } > {({hovered, pressed}) => ( - - - + )} From a49c1d894e37c27c9e53c71d443f0b8f4a8a0fdb Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Fri, 2 Dec 2022 14:45:55 -0800 Subject: [PATCH 057/133] slight improvement on helper function --- src/styles/StyleUtils.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index ebae48a3f81f..ac7332da9b24 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -1,4 +1,4 @@ -import _ from 'underscore'; +import _, { isNull } from 'underscore'; import CONST from '../CONST'; import fontFamily from './fontFamily'; import themeColors from './themes/default'; @@ -297,10 +297,14 @@ function getAnimatedFABStyle(rotate, backgroundColor) { /** * @param {Number} width - * @param {Number} height + * @param {Number | null} height * @returns {Object} */ -function getWidthAndHeightStyle(width, height) { +function getWidthAndHeightStyle(width, height = null) { + if(isNull(height)) { + height = width; + } + return { width, height, From 4becf7fc48e2705870cd27f14ab1029831881aef Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Sat, 3 Dec 2022 01:33:28 +0100 Subject: [PATCH 058/133] Fix optimistic IOU payment messages --- src/libs/ReportUtils.js | 28 ++++++++++++++++++++++++---- src/libs/actions/IOU.js | 1 + 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 73ce12ef9f58..da0e6fd26a72 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -712,15 +712,32 @@ function buildOptimisticIOUReport(ownerEmail, userEmail, total, chatReportID, cu * @param {Array} participants - List of logins for the IOU participants, excluding the current user login * @param {String} comment - IOU comment * @param {String} currency - IOU currency + * @param {String} paymentType - IOU paymentMethodType. Can be oneOf(Elsewhere, Expensify, PayPal.me) + * @param {Boolean} isSettlingUp - Whether we are settling up an IOU * @returns {Array} */ -function getIOUReportActionMessage(type, total, participants, comment, currency) { +function getIOUReportActionMessage(type, total, participants, comment, currency, paymentType = '', isSettlingUp = false) { const amount = NumberFormatUtils.format(preferredLocale, total / 100, {style: 'currency', currency}); const displayNames = _.map(participants, participant => getDisplayNameForParticipant(participant.login, true)); const who = displayNames.length < 3 ? displayNames.join(' and ') : `${displayNames.slice(0, -1).join(', ')}, and ${_.last(displayNames)}`; + let paymentMethodMessage; + switch (paymentType) { + case CONST.IOU.PAYMENT_TYPE.EXPENSIFY: + paymentMethodMessage = 'using wallet'; + break; + case CONST.IOU.PAYMENT_TYPE.ELSEWHERE: + paymentMethodMessage = 'elsewhere'; + break; + case CONST.IOU.PAYMENT_TYPE.PAYPAL_ME: + paymentMethodMessage = 'using PayPal.me'; + break; + default: + break; + } + let iouMessage; switch (type) { case CONST.IOU.REPORT_ACTION_TYPE.CREATE: @@ -736,7 +753,9 @@ function getIOUReportActionMessage(type, total, participants, comment, currency) iouMessage = `Declined the ${amount} request${comment && ` for ${comment}`}`; break; case CONST.IOU.REPORT_ACTION_TYPE.PAY: - iouMessage = `Paid ${amount} to ${who}${comment && ` for ${comment}`}`; + iouMessage = isSettlingUp + ? `Settled up ${paymentMethodMessage}` + : `Sent ${amount}${comment && ` for ${comment}`} ${paymentMethodMessage}`; break; default: break; @@ -762,10 +781,11 @@ function getIOUReportActionMessage(type, total, participants, comment, currency) * @param {String} paymentType - Only required if the IOUReportAction type is 'pay'. Can be oneOf(elsewhere, payPal, Expensify). * @param {String} iouTransactionID - Only required if the IOUReportAction type is oneOf(cancel, decline). Generates a randomID as default. * @param {String} iouReportID - Only required if the IOUReportActions type is oneOf(decline, cancel, pay). Generates a randomID as default. + * @param {String} isSettlingUp - Whether we are settling up an IOU. * * @returns {Object} */ -function buildOptimisticIOUReportAction(sequenceNumber, type, amount, currency, comment, participants, paymentType = '', iouTransactionID = '', iouReportID = '') { +function buildOptimisticIOUReportAction(sequenceNumber, type, amount, currency, comment, participants, paymentType = '', iouTransactionID = '', iouReportID = '', isSettlingUp) { const IOUTransactionID = iouTransactionID || NumberUtils.rand64(); const IOUReportID = iouReportID || generateReportID(); const originalMessage = { @@ -800,7 +820,7 @@ function buildOptimisticIOUReportAction(sequenceNumber, type, amount, currency, clientID: NumberUtils.generateReportActionClientID(), isAttachment: false, originalMessage, - message: getIOUReportActionMessage(type, amount, participants, comment, currency), + message: getIOUReportActionMessage(type, amount, participants, comment, currency, paymentType, isSettlingUp), person: [{ style: 'strong', text: lodashGet(currentUserPersonalDetails, 'displayName', currentUserEmail), diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index fca07e1d2904..40efba0ca643 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -881,6 +881,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho paymentMethodType, '', iouReport.reportID, + true, ); const optimisticData = [ From 2f56555015588d4eadd0a01ab485285935ca65f1 Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 5 Dec 2022 14:04:21 +0100 Subject: [PATCH 059/133] Do not show placeholder in the timezone select --- src/components/OptionsSelector/BaseOptionsSelector.js | 2 +- src/pages/settings/Profile/TimezoneSelectPage.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js index a951830b9d05..0e46a9c17309 100755 --- a/src/components/OptionsSelector/BaseOptionsSelector.js +++ b/src/components/OptionsSelector/BaseOptionsSelector.js @@ -239,7 +239,7 @@ class BaseOptionsSelector extends Component { value={this.props.value} label={this.props.textInputLabel} onChangeText={this.props.onChangeText} - placeholder={this.props.placeholderText || this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} + placeholder={_.isUndefined(this.props.placeholderText) ? this.props.translate('optionsSelector.nameEmailOrPhoneNumber') : this.props.placeholderText} onBlur={(e) => { if (!this.props.shouldFocusOnSelectRow) { return; diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index 62cb212d60a4..e0df35aa5947 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -87,6 +87,7 @@ class TimezoneSelectPage extends Component { onSelectRow={this.saveSelectedTimezone} optionHoveredStyle={styles.hoveredComponentBG} sections={[{data: this.state.timezoneOptions}]} + placeholderText={''} shouldHaveOptionSeparator /> From d79a500cbd66faeb2d23a6e453c64923fb7198cf Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 5 Dec 2022 14:04:32 +0100 Subject: [PATCH 060/133] style --- src/pages/settings/Profile/TimezoneSelectPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index e0df35aa5947..e8ba941f6892 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -87,7 +87,7 @@ class TimezoneSelectPage extends Component { onSelectRow={this.saveSelectedTimezone} optionHoveredStyle={styles.hoveredComponentBG} sections={[{data: this.state.timezoneOptions}]} - placeholderText={''} + placeholderText="" shouldHaveOptionSeparator /> From cc4c99c90ad79d36cb01880801723c1c14617c7c Mon Sep 17 00:00:00 2001 From: Alberto Date: Mon, 5 Dec 2022 17:14:33 +0100 Subject: [PATCH 061/133] Reduce the room name length --- src/CONST.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.js b/src/CONST.js index 935ce523f78d..05a9d67d6328 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -318,7 +318,7 @@ const CONST = { }, RESERVED_ROOM_NAMES: ['#admins', '#announce'], MAX_PREVIEW_AVATARS: 4, - MAX_ROOM_NAME_LENGTH: 80, + MAX_ROOM_NAME_LENGTH: 79, LAST_MESSAGE_TEXT_MAX_LENGTH: 200, OWNER_EMAIL_FAKE: '__FAKE__', DEFAULT_REPORT_NAME: 'Chat Report', From 253dc6d91b572db1c28a34f1352f775a603efa03 Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Mon, 5 Dec 2022 11:41:58 -0800 Subject: [PATCH 062/133] added view wrapper --- src/components/ContextMenuItem.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/ContextMenuItem.js b/src/components/ContextMenuItem.js index e6362ecf6654..c87fc5e9b4c3 100644 --- a/src/components/ContextMenuItem.js +++ b/src/components/ContextMenuItem.js @@ -8,6 +8,7 @@ import styles from '../styles/styles'; import * as StyleUtils from '../styles/StyleUtils'; import getButtonState from '../libs/getButtonState'; import withDelayToggleButtonState, {withDelayToggleButtonStatePropTypes} from './withDelayToggleButtonState'; +import variables from '../styles/variables'; const propTypes = { /** Icon Component */ @@ -87,11 +88,13 @@ class ContextMenuItem extends Component { } > {({hovered, pressed}) => ( - + + + )} From 7422783bbd127fd9d214461736c2d4d1417d4b55 Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Mon, 5 Dec 2022 11:59:18 -0800 Subject: [PATCH 063/133] better syntax --- src/styles/StyleUtils.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index ac7332da9b24..6b4292e395c7 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -1,4 +1,4 @@ -import _, { isNull } from 'underscore'; +import _ from 'underscore'; import CONST from '../CONST'; import fontFamily from './fontFamily'; import themeColors from './themes/default'; @@ -301,13 +301,9 @@ function getAnimatedFABStyle(rotate, backgroundColor) { * @returns {Object} */ function getWidthAndHeightStyle(width, height = null) { - if(isNull(height)) { - height = width; - } - return { width, - height, + height: height ?? width, }; } From a8530b64bac3456b11ceb30fcfe887564e74f354 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Mon, 5 Dec 2022 15:33:47 -0500 Subject: [PATCH 064/133] update shape --- src/styles/styles.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/styles/styles.js b/src/styles/styles.js index 0f28f63d84da..0c12797dbfe1 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -2778,9 +2778,10 @@ const styles = { }, cardMenuItem: { - paddingHorizontal: 0, - borderRadius: variables.componentBorderRadiusNormal, - paddingVertical: 12, + paddingHorizontal: 8, + borderRadius: variables.buttonBorderRadius, + height: variables.componentSizeLarge, + alignItems: 'center', }, callRequestSection: { From 2e2f26d9544baecc543113b56748b1dce0890689 Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Mon, 5 Dec 2022 14:18:42 -0800 Subject: [PATCH 065/133] set width only --- src/components/AvatarCropModal/AvatarCropModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AvatarCropModal/AvatarCropModal.js b/src/components/AvatarCropModal/AvatarCropModal.js index fe893d63e451..762aff252738 100644 --- a/src/components/AvatarCropModal/AvatarCropModal.js +++ b/src/components/AvatarCropModal/AvatarCropModal.js @@ -315,7 +315,7 @@ const AvatarCropModal = (props) => { translateX={translateX} rotation={rotation} /> - + Date: Mon, 5 Dec 2022 14:24:25 -0800 Subject: [PATCH 066/133] lint --- src/components/AvatarCropModal/AvatarCropModal.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/AvatarCropModal/AvatarCropModal.js b/src/components/AvatarCropModal/AvatarCropModal.js index 762aff252738..8770d08c4688 100644 --- a/src/components/AvatarCropModal/AvatarCropModal.js +++ b/src/components/AvatarCropModal/AvatarCropModal.js @@ -28,7 +28,6 @@ import ImageCropView from './ImageCropView'; import Slider from './Slider'; import cropOrRotateImage from '../../libs/cropOrRotateImage'; import HeaderGap from '../HeaderGap'; -import * as StyleUtils from '../../styles/StyleUtils'; const propTypes = { /** Link to image for cropping */ From 335ca1928fc99d55b7bfc70df4c003530d05e3a3 Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Mon, 5 Dec 2022 14:25:36 -0800 Subject: [PATCH 067/133] es lint --- src/styles/StyleUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index 6b4292e395c7..3075e6decb1b 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -303,7 +303,7 @@ function getAnimatedFABStyle(rotate, backgroundColor) { function getWidthAndHeightStyle(width, height = null) { return { width, - height: height ?? width, + height: height != null ? height : width, }; } From 9531504bf52f7ce554252ef3bc2d6bc98997fcb1 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Mon, 5 Dec 2022 18:46:23 -0500 Subject: [PATCH 068/133] move arrow to the right --- src/pages/ReportSettingsPage.js | 2 +- src/styles/styles.js | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pages/ReportSettingsPage.js b/src/pages/ReportSettingsPage.js index b5001160f86e..f6521a8f81d6 100644 --- a/src/pages/ReportSettingsPage.js +++ b/src/pages/ReportSettingsPage.js @@ -209,7 +209,7 @@ class ReportSettingsPage extends Component { onPress={this.validateAndUpdatePolicyRoomName} style={[styles.ml2, styles.mnw25]} textStyles={[styles.label]} - innerStyles={[styles.ph5]} + innerStyles={[styles.ph5, styles.saveButtonPadding]} isDisabled={shouldDisableRename} /> )} diff --git a/src/styles/styles.js b/src/styles/styles.js index 0c12797dbfe1..718caf966a5c 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -385,7 +385,7 @@ const styles = { borderRadius: variables.buttonBorderRadius, height: variables.componentSizeLarge, paddingTop: 8, - paddingRight: 18, + paddingRight: 10, paddingBottom: 8, paddingLeft: 18, backgroundColor: themeColors.buttonDefaultBG, @@ -2778,7 +2778,8 @@ const styles = { }, cardMenuItem: { - paddingHorizontal: 8, + paddingLeft: 8, + paddingRight: 0, borderRadius: variables.buttonBorderRadius, height: variables.componentSizeLarge, alignItems: 'center', @@ -2791,6 +2792,10 @@ const styles = { marginHorizontal: 0, marginBottom: 0, }, + + saveButtonPadding: { + paddingRight: 18, + }, }; export default styles; From 2b03e4944712f66067dc7ffae13a2a32835f80b0 Mon Sep 17 00:00:00 2001 From: Daniel Gale-Rosen Date: Tue, 6 Dec 2022 10:43:37 -0500 Subject: [PATCH 069/133] clean up save button styles --- src/pages/ReportSettingsPage.js | 2 +- src/styles/styles.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/ReportSettingsPage.js b/src/pages/ReportSettingsPage.js index f6521a8f81d6..818e35786dc4 100644 --- a/src/pages/ReportSettingsPage.js +++ b/src/pages/ReportSettingsPage.js @@ -209,7 +209,7 @@ class ReportSettingsPage extends Component { onPress={this.validateAndUpdatePolicyRoomName} style={[styles.ml2, styles.mnw25]} textStyles={[styles.label]} - innerStyles={[styles.ph5, styles.saveButtonPadding]} + innerStyles={[styles.saveButtonPadding]} isDisabled={shouldDisableRename} /> )} diff --git a/src/styles/styles.js b/src/styles/styles.js index 718caf966a5c..bb2250577aba 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -2794,6 +2794,7 @@ const styles = { }, saveButtonPadding: { + paddingLeft: 18, paddingRight: 18, }, }; From a4e8edd735d3059731463a90305ee88801c6d707 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 6 Dec 2022 12:09:17 -0700 Subject: [PATCH 070/133] move colors to colors file --- src/components/Picker/index.js | 6 +++--- src/styles/colors.js | 3 +++ src/styles/themes/default.js | 1 + src/styles/variables.js | 1 - 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/Picker/index.js b/src/components/Picker/index.js index e49abef260c2..ac86378af8ef 100644 --- a/src/components/Picker/index.js +++ b/src/components/Picker/index.js @@ -8,7 +8,7 @@ import * as Expensicons from '../Icon/Expensicons'; import FormHelpMessage from '../FormHelpMessage'; import Text from '../Text'; import styles from '../../styles/styles'; -import variables from '../../styles/variables'; +import themeColors from '../../styles/themes/default'; import pickerStyles from './pickerStyles'; const propTypes = { @@ -108,12 +108,12 @@ class Picker extends PureComponent { // so we might need to color accordingly so it doesn't blend with the background. this.placeholder = _.isEmpty(this.props.placeholder) ? {} : { ...this.props.placeholder, - color: variables.pickerOptionsTextColor, + color: themeColors.pickerOptionsTextColor, }; this.items = _.map(this.props.items, item => ( { ...item, - color: variables.pickerOptionsTextColor, + color: themeColors.pickerOptionsTextColor, } )); } diff --git a/src/styles/colors.js b/src/styles/colors.js index 484b4716259b..df71ea96f426 100644 --- a/src/styles/colors.js +++ b/src/styles/colors.js @@ -34,6 +34,9 @@ export default { greenDefaultButtonPressed: '#467164', greenDefaultButtonDisabled: '#8BA69E', + // Picker option text color, we set this to avoid white on white dropdowns in Windows + midnight: '#002140', + // DEPRECATED COLORS. Do not reference these colors. Will be deleted in color switch PR. gray1: '#FAFAFA', gray2: '#ECECEC', diff --git a/src/styles/themes/default.js b/src/styles/themes/default.js index 5b9981574b25..cb5140aea633 100644 --- a/src/styles/themes/default.js +++ b/src/styles/themes/default.js @@ -57,6 +57,7 @@ const darkTheme = { heroCard: colors.blue, uploadPreviewActivityIndicator: colors.greenHighlightBackground, checkBox: colors.green, + pickerOptionsTextColor: colors.midnight, }; const oldTheme = { diff --git a/src/styles/variables.js b/src/styles/variables.js index d43a0a29464b..0860d3ff9431 100644 --- a/src/styles/variables.js +++ b/src/styles/variables.js @@ -80,5 +80,4 @@ export default { INACTIVE_LABEL_TRANSLATE_Y: getValueUsingPixelRatio(16, 21), sliderBarHeight: 8, sliderKnobSize: 26, - pickerOptionsTextColor: '#002140', }; From 733e83350cdcf4a61d898204d73ac8c907d82788 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Tue, 6 Dec 2022 13:04:24 -0700 Subject: [PATCH 071/133] update items on render --- src/components/Picker/index.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/components/Picker/index.js b/src/components/Picker/index.js index ac86378af8ef..62cb9c2b427e 100644 --- a/src/components/Picker/index.js +++ b/src/components/Picker/index.js @@ -110,12 +110,6 @@ class Picker extends PureComponent { ...this.props.placeholder, color: themeColors.pickerOptionsTextColor, }; - this.items = _.map(this.props.items, item => ( - { - ...item, - color: themeColors.pickerOptionsTextColor, - } - )); } componentDidMount() { @@ -171,7 +165,9 @@ class Picker extends PureComponent { )} ({...item, color: themeColors.pickerOptionsTextColor}))} style={this.props.size === 'normal' ? pickerStyles(this.props.isDisabled) : styles.pickerSmall} useNativeAndroidPickerStyle={false} placeholder={this.placeholder} From 243c2c8d8abe1052f9333cc3eb7a0c9f2cde1794 Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Tue, 6 Dec 2022 13:41:16 -0800 Subject: [PATCH 072/133] better utils funciton name --- src/styles/StyleUtils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index 3075e6decb1b..5f4c42a46dbe 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -171,7 +171,7 @@ function getZoomSizingStyle(isZoomed, imgWidth, imgHeight, zoomScale, containerH * @param {Number} width * @return {Object} */ -function getAutoGrowTextInputStyle(width) { +function getWidthStyle(width) { return { width, }; @@ -548,7 +548,7 @@ export { getNavigationDrawerType, getZoomCursorStyle, getZoomSizingStyle, - getAutoGrowTextInputStyle, + getWidthStyle, getBackgroundAndBorderStyle, getBackgroundColorStyle, getBackgroundColorWithOpacityStyle, From 39ce70b45df3a3763e5568f4511a7fad2e22f604 Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Tue, 6 Dec 2022 13:41:23 -0800 Subject: [PATCH 073/133] use new name --- src/components/AvatarCropModal/AvatarCropModal.js | 5 +++-- src/components/TextInput/BaseTextInput.js | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/AvatarCropModal/AvatarCropModal.js b/src/components/AvatarCropModal/AvatarCropModal.js index 8770d08c4688..f0aff89bb630 100644 --- a/src/components/AvatarCropModal/AvatarCropModal.js +++ b/src/components/AvatarCropModal/AvatarCropModal.js @@ -28,7 +28,8 @@ import ImageCropView from './ImageCropView'; import Slider from './Slider'; import cropOrRotateImage from '../../libs/cropOrRotateImage'; import HeaderGap from '../HeaderGap'; - +import * as StyleUtils from '../../styles/StyleUtils'; + const propTypes = { /** Link to image for cropping */ imageUri: PropTypes.string, @@ -314,7 +315,7 @@ const AvatarCropModal = (props) => { translateX={translateX} rotation={rotation} /> - + ({...finalStyles, ...s}), {}); From bb44b739463326bc342d1743d5f7030a59a05f6d Mon Sep 17 00:00:00 2001 From: Luke Donahue Date: Tue, 6 Dec 2022 14:06:53 -0800 Subject: [PATCH 074/133] trailing space --- src/components/AvatarCropModal/AvatarCropModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AvatarCropModal/AvatarCropModal.js b/src/components/AvatarCropModal/AvatarCropModal.js index f0aff89bb630..cfe0f91a965a 100644 --- a/src/components/AvatarCropModal/AvatarCropModal.js +++ b/src/components/AvatarCropModal/AvatarCropModal.js @@ -29,7 +29,7 @@ import Slider from './Slider'; import cropOrRotateImage from '../../libs/cropOrRotateImage'; import HeaderGap from '../HeaderGap'; import * as StyleUtils from '../../styles/StyleUtils'; - + const propTypes = { /** Link to image for cropping */ imageUri: PropTypes.string, From 173964e353029ec50b4917e086301f00e3a0f89e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Tue, 6 Dec 2022 19:25:12 -0600 Subject: [PATCH 075/133] add new checklist item to use ScrollView --- .github/PULL_REQUEST_TEMPLATE.md | 1 + contributingGuides/REVIEWER_CHECKLIST.md | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 5d1d2c8f5417..3fb390caa646 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -106,6 +106,7 @@ This is a checklist for PR authors. Please make sure to complete all tasks and c - [ ] The style can't be created with an existing [StyleUtils](https://github.com/Expensify/App/blob/main/src/styles/StyleUtils.js) function (i.e. `StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG`) - [ ] If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like `Avatar` is modified, I verified that `Avatar` is working as expected in all cases) - [ ] If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected. +- [ ] If a new page is added, I verified it's using the `ScrollView` component to make it scrollable in landscape mode or when more elements are added to the page. - [ ] I have checked off every checkbox in the PR author checklist, including those that don't apply to this PR. ### Screenshots/Videos diff --git a/contributingGuides/REVIEWER_CHECKLIST.md b/contributingGuides/REVIEWER_CHECKLIST.md index 7d0889742f52..fdf49a685163 100644 --- a/contributingGuides/REVIEWER_CHECKLIST.md +++ b/contributingGuides/REVIEWER_CHECKLIST.md @@ -45,6 +45,7 @@ - [ ] The style can't be created with an existing [StyleUtils](https://github.com/Expensify/App/blob/main/src/styles/StyleUtils.js) function (i.e. `StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG`) - [ ] If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like `Avatar` is modified, I verified that `Avatar` is working as expected in all cases) - [ ] If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected. +- [ ] If a new page is added, I verified it's using the `ScrollView` component to make it scrollable in landscape mode or when more elements are added to the page. - [ ] I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR. ### Screenshots/Videos From 0e46562f1c00304facb7bcae121794a5eec09a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Ch=C3=A1vez?= Date: Tue, 6 Dec 2022 19:44:58 -0600 Subject: [PATCH 076/133] update new checklist item --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- contributingGuides/REVIEWER_CHECKLIST.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3fb390caa646..e41288bbbf12 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -106,7 +106,7 @@ This is a checklist for PR authors. Please make sure to complete all tasks and c - [ ] The style can't be created with an existing [StyleUtils](https://github.com/Expensify/App/blob/main/src/styles/StyleUtils.js) function (i.e. `StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG`) - [ ] If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like `Avatar` is modified, I verified that `Avatar` is working as expected in all cases) - [ ] If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected. -- [ ] If a new page is added, I verified it's using the `ScrollView` component to make it scrollable in landscape mode or when more elements are added to the page. +- [ ] If a new page is added, I verified it's using the `ScrollView` component to make it scrollable when more elements are added to the page. - [ ] I have checked off every checkbox in the PR author checklist, including those that don't apply to this PR. ### Screenshots/Videos diff --git a/contributingGuides/REVIEWER_CHECKLIST.md b/contributingGuides/REVIEWER_CHECKLIST.md index fdf49a685163..c56c99dce556 100644 --- a/contributingGuides/REVIEWER_CHECKLIST.md +++ b/contributingGuides/REVIEWER_CHECKLIST.md @@ -45,7 +45,7 @@ - [ ] The style can't be created with an existing [StyleUtils](https://github.com/Expensify/App/blob/main/src/styles/StyleUtils.js) function (i.e. `StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG`) - [ ] If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like `Avatar` is modified, I verified that `Avatar` is working as expected in all cases) - [ ] If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected. -- [ ] If a new page is added, I verified it's using the `ScrollView` component to make it scrollable in landscape mode or when more elements are added to the page. +- [ ] If a new page is added, I verified it's using the `ScrollView` component to make it scrollable when more elements are added to the page. - [ ] I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR. ### Screenshots/Videos From d21408f790579be677f62b0621b548cc1cfb28f7 Mon Sep 17 00:00:00 2001 From: shonsirsha Date: Wed, 7 Dec 2022 05:10:05 +0100 Subject: [PATCH 077/133] fix: minor restyle password protection pdf form --- src/components/PDFView/PDFPasswordForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PDFView/PDFPasswordForm.js b/src/components/PDFView/PDFPasswordForm.js index 482e31405ef0..5661d5d49b0b 100644 --- a/src/components/PDFView/PDFPasswordForm.js +++ b/src/components/PDFView/PDFPasswordForm.js @@ -102,7 +102,7 @@ class PDFPasswordForm extends Component { From a4c2a574a23c8eb3761ad2867939c9592125e683 Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 7 Dec 2022 13:27:23 +0100 Subject: [PATCH 078/133] default to empty string and populate in different components --- src/components/OptionsSelector/BaseOptionsSelector.js | 2 +- src/pages/NewChatPage.js | 1 + src/pages/SearchPage.js | 1 + .../iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js | 1 + src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js | 1 + src/pages/settings/Profile/TimezoneSelectPage.js | 1 - src/pages/workspace/WorkspaceInvitePage.js | 1 + 7 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js index 0e46a9c17309..5538aca1db3f 100755 --- a/src/components/OptionsSelector/BaseOptionsSelector.js +++ b/src/components/OptionsSelector/BaseOptionsSelector.js @@ -239,7 +239,7 @@ class BaseOptionsSelector extends Component { value={this.props.value} label={this.props.textInputLabel} onChangeText={this.props.onChangeText} - placeholder={_.isUndefined(this.props.placeholderText) ? this.props.translate('optionsSelector.nameEmailOrPhoneNumber') : this.props.placeholderText} + placeholder={this.props.placeholderText} onBlur={(e) => { if (!this.props.shouldFocusOnSelectRow) { return; diff --git a/src/pages/NewChatPage.js b/src/pages/NewChatPage.js index 5f79c634d930..634e5a20b500 100755 --- a/src/pages/NewChatPage.js +++ b/src/pages/NewChatPage.js @@ -254,6 +254,7 @@ class NewChatPage extends Component { shouldShowConfirmButton={this.props.isGroupChat} confirmButtonText={this.props.translate('newChatPage.createGroup')} onConfirmSelection={this.props.isGroupChat ? this.createGroup : () => {}} + placeholderText = {this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} /> )} diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js index 6ec57cd0c991..b5d67ed684d6 100755 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -184,6 +184,7 @@ class SearchPage extends Component { hideAdditionalOptionStates showTitleTooltip shouldShowOptions={didScreenTransitionEnd} + placeholderText = {this.props.translate('common.search')} /> diff --git a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js index fb68f8571fa1..6723e545a2b0 100755 --- a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js +++ b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js @@ -139,6 +139,7 @@ class IOUParticipantsRequest extends Component { headerMessage={headerMessage} hideAdditionalOptionStates forceTextUnreadStyle + placeholderText = {this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} /> ); } diff --git a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js index 76a694b664ae..15dce2a97e00 100755 --- a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js +++ b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js @@ -226,6 +226,7 @@ class IOUParticipantsSplit extends Component { shouldShowConfirmButton confirmButtonText={this.props.translate('common.next')} onConfirmSelection={this.finalizeParticipants} + placeholderText = {this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} /> diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js index e8ba941f6892..62cb212d60a4 100644 --- a/src/pages/settings/Profile/TimezoneSelectPage.js +++ b/src/pages/settings/Profile/TimezoneSelectPage.js @@ -87,7 +87,6 @@ class TimezoneSelectPage extends Component { onSelectRow={this.saveSelectedTimezone} optionHoveredStyle={styles.hoveredComponentBG} sections={[{data: this.state.timezoneOptions}]} - placeholderText="" shouldHaveOptionSeparator /> diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js index fbabe111ac26..872539a5bc58 100644 --- a/src/pages/workspace/WorkspaceInvitePage.js +++ b/src/pages/workspace/WorkspaceInvitePage.js @@ -298,6 +298,7 @@ class WorkspaceInvitePage extends React.Component { hideAdditionalOptionStates forceTextUnreadStyle shouldFocusOnSelectRow + placeholderText = {this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} /> )} From 4a0801fd601ba14fa80a4293f8f95773e818c2da Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 7 Dec 2022 13:54:47 +0100 Subject: [PATCH 079/133] change placeholder --- src/pages/SearchPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js index b5d67ed684d6..b41a491f6aae 100755 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -184,7 +184,7 @@ class SearchPage extends Component { hideAdditionalOptionStates showTitleTooltip shouldShowOptions={didScreenTransitionEnd} - placeholderText = {this.props.translate('common.search')} + placeholderText = {this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} /> From 0b884c17c2b83f7288db75315ddb861c045b8b70 Mon Sep 17 00:00:00 2001 From: Alberto Date: Wed, 7 Dec 2022 14:08:02 +0100 Subject: [PATCH 080/133] style --- src/pages/NewChatPage.js | 2 +- src/pages/SearchPage.js | 2 +- .../iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js | 2 +- src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js | 2 +- src/pages/workspace/WorkspaceInvitePage.js | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/NewChatPage.js b/src/pages/NewChatPage.js index 634e5a20b500..392e9e40081b 100755 --- a/src/pages/NewChatPage.js +++ b/src/pages/NewChatPage.js @@ -254,7 +254,7 @@ class NewChatPage extends Component { shouldShowConfirmButton={this.props.isGroupChat} confirmButtonText={this.props.translate('newChatPage.createGroup')} onConfirmSelection={this.props.isGroupChat ? this.createGroup : () => {}} - placeholderText = {this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} + placeholderText={this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} /> )} diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js index b41a491f6aae..e443a507feb6 100755 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -184,7 +184,7 @@ class SearchPage extends Component { hideAdditionalOptionStates showTitleTooltip shouldShowOptions={didScreenTransitionEnd} - placeholderText = {this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} + placeholderText={this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} /> diff --git a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js index 6723e545a2b0..55bf29b012d9 100755 --- a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js +++ b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js @@ -139,7 +139,7 @@ class IOUParticipantsRequest extends Component { headerMessage={headerMessage} hideAdditionalOptionStates forceTextUnreadStyle - placeholderText = {this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} + placeholderText={this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} /> ); } diff --git a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js index 15dce2a97e00..2af2997268cc 100755 --- a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js +++ b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js @@ -226,7 +226,7 @@ class IOUParticipantsSplit extends Component { shouldShowConfirmButton confirmButtonText={this.props.translate('common.next')} onConfirmSelection={this.finalizeParticipants} - placeholderText = {this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} + placeholderText={this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} /> diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js index 872539a5bc58..9c48e0208545 100644 --- a/src/pages/workspace/WorkspaceInvitePage.js +++ b/src/pages/workspace/WorkspaceInvitePage.js @@ -298,7 +298,7 @@ class WorkspaceInvitePage extends React.Component { hideAdditionalOptionStates forceTextUnreadStyle shouldFocusOnSelectRow - placeholderText = {this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} + placeholderText={this.props.translate('optionsSelector.nameEmailOrPhoneNumber')} /> )} From 5bd5b2e679f7168f7d967934af6d8afa1ce1a291 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Wed, 7 Dec 2022 07:45:43 -0700 Subject: [PATCH 081/133] Remove mode prop that was always set to "default" --- src/components/OptionRow.js | 29 ++++--------------- src/components/OptionsList/BaseOptionsList.js | 10 +++---- .../OptionsList/optionsListPropTypes.js | 4 --- src/pages/ReportParticipantsPage.js | 1 - 4 files changed, 10 insertions(+), 34 deletions(-) diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js index 0dff86fc2a43..3f77754ebb2f 100644 --- a/src/components/OptionRow.js +++ b/src/components/OptionRow.js @@ -51,9 +51,6 @@ const propTypes = { /** Whether to show the title tooltip */ showTitleTooltip: PropTypes.bool, - /** Toggle between compact and default view */ - mode: PropTypes.oneOf(_.values(CONST.OPTION_MODE)), - /** Whether this option should be disabled */ isDisabled: PropTypes.bool, @@ -71,7 +68,6 @@ const defaultProps = { isSelected: false, boldStyle: false, showTitleTooltip: false, - mode: 'default', onSelectRow: () => {}, isDisabled: false, optionIsFocused: false, @@ -86,22 +82,10 @@ const OptionRow = (props) => { : styles.sidebarLinkText; const textUnreadStyle = (props.boldStyle) ? [textStyle, styles.sidebarLinkTextBold] : [textStyle]; - const displayNameStyle = StyleUtils.combineStyles(props.mode === CONST.OPTION_MODE.COMPACT - ? [styles.optionDisplayName, ...textUnreadStyle, styles.optionDisplayNameCompact, styles.mr2] - : [styles.optionDisplayName, ...textUnreadStyle], props.style); - const alternateTextStyle = StyleUtils.combineStyles(props.mode === CONST.OPTION_MODE.COMPACT - ? [textStyle, styles.optionAlternateText, styles.textLabelSupporting, styles.optionAlternateTextCompact] - : [textStyle, styles.optionAlternateText, styles.textLabelSupporting], props.style); - const contentContainerStyles = props.mode === CONST.OPTION_MODE.COMPACT - ? [styles.flex1, styles.flexRow, styles.overflowHidden, styles.alignItemsCenter] - : [styles.flex1]; - const sidebarInnerRowStyle = StyleSheet.flatten(props.mode === CONST.OPTION_MODE.COMPACT ? [ - styles.chatLinkRowPressable, - styles.flexGrow1, - styles.optionItemAvatarNameWrapper, - styles.optionRowCompact, - styles.justifyContentCenter, - ] : [ + const displayNameStyle = [styles.optionDisplayName, ...textUnreadStyle, props.style]; + const alternateTextStyle = [textStyle, styles.optionAlternateText, styles.textLabelSupporting, props.style]; + const contentContainerStyles = [styles.flex1]; + const sidebarInnerRowStyle = StyleSheet.flatten([ styles.chatLinkRowPressable, styles.flexGrow1, styles.optionItemAvatarNameWrapper, @@ -169,12 +153,12 @@ const OptionRow = (props) => { secondaryAvatar={props.option.icons[1]} mainTooltip={props.option.ownerEmail} secondaryTooltip={props.option.subtitle} - size={props.mode === CONST.OPTION_MODE.COMPACT ? CONST.AVATAR_SIZE.SMALL : CONST.AVATAR_SIZE.DEFAULT} + size={CONST.AVATAR_SIZE.DEFAULT} /> ) : ( prevProps.optionIsFocused === nextProps.optionIsFocused && prevProps.isSelected === nextProps.isSelected - && prevProps.mode === nextProps.mode && prevProps.option.alternateText === nextProps.option.alternateText && prevProps.option.descriptiveText === nextProps.option.descriptiveText && _.isEqual(prevProps.option.icons, nextProps.option.icons) diff --git a/src/components/OptionsList/BaseOptionsList.js b/src/components/OptionsList/BaseOptionsList.js index f7b716e4f544..3de630dde272 100644 --- a/src/components/OptionsList/BaseOptionsList.js +++ b/src/components/OptionsList/BaseOptionsList.js @@ -40,7 +40,6 @@ class BaseOptionsList extends Component { this.buildFlatSectionArray = this.buildFlatSectionArray.bind(this); this.extractKey = this.extractKey.bind(this); this.onViewableItemsChanged = this.onViewableItemsChanged.bind(this); - this.viewabilityConfig = {viewAreaCoveragePercentThreshold: 95}; this.didLayout = false; this.flattenedData = this.buildFlatSectionArray(); @@ -106,7 +105,7 @@ class BaseOptionsList extends Component { * @returns {Array} */ buildFlatSectionArray() { - const optionHeight = this.props.optionMode === CONST.OPTION_MODE.COMPACT ? variables.optionRowHeightCompact : variables.optionRowHeight; + const optionHeight = variables.optionRowHeight; let offset = 0; // Start with just an empty list header @@ -159,7 +158,6 @@ class BaseOptionsList extends Component { return ( - {this.props.headerMessage ? ( + {this.props.headerMessage && ( {this.props.headerMessage} - ) : null} + )} diff --git a/src/components/OptionsList/optionsListPropTypes.js b/src/components/OptionsList/optionsListPropTypes.js index ced1fb399ccb..755c0dbe8da0 100644 --- a/src/components/OptionsList/optionsListPropTypes.js +++ b/src/components/OptionsList/optionsListPropTypes.js @@ -64,9 +64,6 @@ const propTypes = { /** Whether to show the title tooltip */ showTitleTooltip: PropTypes.bool, - /** Toggle between compact and default view of the option */ - optionMode: PropTypes.oneOf(_.values(CONST.OPTION_MODE)), - /** Whether to disable the interactivity of the list's option row(s) */ isDisabled: PropTypes.bool, @@ -92,7 +89,6 @@ const defaultProps = { headerMessage: '', innerRef: null, showTitleTooltip: false, - optionMode: undefined, isDisabled: false, onLayout: undefined, shouldHaveOptionSeparator: false, diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.js index 6de09a18ff7b..97a1aa2c8925 100755 --- a/src/pages/ReportParticipantsPage.js +++ b/src/pages/ReportParticipantsPage.js @@ -99,7 +99,6 @@ const ReportParticipantsPage = (props) => { hideSectionHeaders showTitleTooltip disableFocusOptions - optionMode="default" boldStyle optionHoveredStyle={styles.hoveredComponentBG} /> From 5ce44dca5b7c837c56c1c2239b1690f597442997 Mon Sep 17 00:00:00 2001 From: b1tjoy <103875612+b1tjoy@users.noreply.github.com> Date: Wed, 7 Dec 2022 22:49:24 +0800 Subject: [PATCH 082/133] fix copy and paste text inconsistent on mWeb --- src/libs/Clipboard/index.js | 16 +--- src/libs/Clipboard/index.website.js | 80 ++++++++++++++++++++ src/libs/Clipboard/miscClipboardFunctions.js | 19 +++++ 3 files changed, 102 insertions(+), 13 deletions(-) create mode 100644 src/libs/Clipboard/index.website.js create mode 100644 src/libs/Clipboard/miscClipboardFunctions.js diff --git a/src/libs/Clipboard/index.js b/src/libs/Clipboard/index.js index 502fd3075577..60c3cff2fb72 100644 --- a/src/libs/Clipboard/index.js +++ b/src/libs/Clipboard/index.js @@ -1,8 +1,7 @@ -// on Web/desktop this import will be replaced with `react-native-web` -import {Clipboard} from 'react-native-web'; -import lodashGet from 'lodash/get'; +import MiscClipboardFunctions from './miscClipboardFunctions'; -const canSetHtml = () => lodashGet(navigator, 'clipboard.write'); +const canSetHtml = MiscClipboardFunctions.canSetHtml; +const setString = MiscClipboardFunctions.setString; /** * Writes the content as HTML if the web client supports it. @@ -27,15 +26,6 @@ const setHtml = (html, text) => { ]); }; -/** - * Sets a string on the Clipboard object via react-native-web - * - * @param {String} text - */ -const setString = (text) => { - Clipboard.setString(text); -}; - export default { setString, canSetHtml, diff --git a/src/libs/Clipboard/index.website.js b/src/libs/Clipboard/index.website.js new file mode 100644 index 000000000000..30e2afc4fe18 --- /dev/null +++ b/src/libs/Clipboard/index.website.js @@ -0,0 +1,80 @@ +import CONST from '../../CONST'; +import * as Browser from '../Browser'; +import MiscClipboardFunctions from './miscClipboardFunctions'; + +const canSetHtml = MiscClipboardFunctions.canSetHtml; +const setString = MiscClipboardFunctions.setString; + +/** + * Deprecated method to write the content as HTML to clipboard. + * @param {String} html HTML representation + * @param {String} text Plain text representation + */ +const copyToClipboardDeprecated = (html, text) => { + const node = document.createElement('span'); + node.textContent = html; + node.style.all = 'unset'; + node.style.opacity = '0'; + node.style.position = 'absolute'; + node.style.whiteSpace = 'pre-wrap'; + node.style.userSelect = 'text'; + node.addEventListener('copy', (e) => { + e.stopPropagation(); + e.preventDefault(); + e.clipboardData.clearData(); + e.clipboardData.setData('text/html', html); + e.clipboardData.setData('text/plain', text); + }); + document.body.appendChild(node); + + const selection = window.getSelection(); + selection.removeAllRanges(); + const range = document.createRange(); + range.selectNodeContents(node); + selection.addRange(range); + + try { + document.execCommand('copy'); + // eslint-disable-next-line no-empty + } catch (e) {} + + selection.removeAllRanges(); + document.body.removeChild(node); +}; + +/** + * Writes the content as HTML if the web client supports it. + * @param {String} html HTML representation + * @param {String} text Plain text representation + */ +const setHtml = (html, text) => { + if (!html || !text) { + return; + } + + if (!canSetHtml()) { + throw new Error('clipboard.write is not supported on this platform, thus HTML cannot be copied.'); + } + + if (CONST.BROWSER.SAFARI === Browser.getBrowser()) { + // Safari sanitize "text/html" data before writing to the pasteboard when using Clipboard API, + // whitespaces in the start of line are stripped away. We use the deprecated method to copy + // contents as HTML and keep whitespaces in the start of line on Safari. + // See https://webkit.org/blog/10855/async-clipboard-api/ for more details. + copyToClipboardDeprecated(html, text); + } else { + navigator.clipboard.write([ + // eslint-disable-next-line no-undef + new ClipboardItem({ + 'text/html': new Blob([html], {type: 'text/html'}), + 'text/plain': new Blob([text], {type: 'text/plain'}), + }), + ]); + } +}; + +export default { + setString, + canSetHtml, + setHtml, +}; diff --git a/src/libs/Clipboard/miscClipboardFunctions.js b/src/libs/Clipboard/miscClipboardFunctions.js new file mode 100644 index 000000000000..259e98a7f5d8 --- /dev/null +++ b/src/libs/Clipboard/miscClipboardFunctions.js @@ -0,0 +1,19 @@ +// on Web/desktop this import will be replaced with `react-native-web` +import {Clipboard} from 'react-native-web'; +import lodashGet from 'lodash/get'; + +const canSetHtml = () => lodashGet(navigator, 'clipboard.write'); + +/** + * Sets a string on the Clipboard object via react-native-web + * + * @param {String} text + */ +const setString = (text) => { + Clipboard.setString(text); +}; + +export default { + setString, + canSetHtml, +}; From 903c8792b8443389b904751c1297d36e5af03e80 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Wed, 7 Dec 2022 08:01:01 -0700 Subject: [PATCH 083/133] Remove options that are no longer used --- src/libs/OptionsListUtils.js | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 0942d799eda7..3efdddab24fd 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -439,7 +439,6 @@ function getOptions(reports, personalDetails, { includeMultipleParticipantReports = false, includePersonalDetails = false, includeRecentReports = false, - prioritizeDefaultRoomsInSearch = false, // When sortByReportTypeInSearch flag is true, recentReports will include the personalDetails options as well. sortByReportTypeInSearch = false, @@ -556,12 +555,6 @@ function getOptions(reports, personalDetails, { } } - // If we are prioritizing default rooms in search, do it only once we started something - if (prioritizeDefaultRoomsInSearch && searchValue !== '') { - const reportsSplitByDefaultChatRoom = _.partition(recentReportOptions, option => option.isChatRoom); - recentReportOptions = reportsSplitByDefaultChatRoom[0].concat(reportsSplitByDefaultChatRoom[1]); - } - if (includePersonalDetails) { // Next loop over all personal details removing any that are selectedUsers or recentChats _.each(allPersonalDetailsOptions, (personalDetailOption) => { @@ -649,11 +642,8 @@ function getSearchOptions( includeRecentReports: true, includeMultipleParticipantReports: true, maxRecentReportsToShow: 0, // Unlimited - prioritizePinnedReports: false, - prioritizeDefaultRoomsInSearch: false, sortByReportTypeInSearch: true, showChatPreviewLine: true, - showReportsWithNoComments: true, includePersonalDetails: true, forcePolicyNamePreview: true, }); From 774b6144e196b0c83c55d14f5fa653f046cf1a95 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Wed, 7 Dec 2022 08:36:42 -0700 Subject: [PATCH 084/133] Micro-optimize function with native sorting and for loops --- src/libs/ReportUtils.js | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index c7eba83e0b2a..69329a04a200 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -468,12 +468,26 @@ function getIcons(report, personalDetails, policies, defaultIcon = null) { ]; } - // Return avatar sources for Group chats - const sortedParticipants = _.map(report.participants, dmParticipant => ({ - firstName: lodashGet(personalDetails, [dmParticipant, 'firstName'], ''), - avatar: lodashGet(personalDetails, [dmParticipant, 'avatar']) || getDefaultAvatar(dmParticipant), - })).sort((first, second) => first.firstName - second.firstName); - return _.map(sortedParticipants, item => item.avatar); + const participantDetails = []; + for (let i = 0; i < report.participants.length; i++) { + const login = report.participants[i]; + participantDetails.push([ + login, + lodashGet(personalDetails, [login, 'firstName'], ''), + lodashGet(personalDetails, [login, 'avatar']) || getDefaultAvatar(login), + ]); + } + + // Sort all logins by first name (which is the second element in the array) + const sortedParticipantDetails = participantDetails.sort((a, b) => a[1] - b[1]); + + // Now that things are sorted, gather only the avatars (third element in the array) and return those + const avatars = []; + for (let i = 0; i < sortedParticipantDetails.length; i++) { + avatars.push(sortedParticipantDetails[i][2]); + } + + return avatars; } /** @@ -570,7 +584,13 @@ function getReportName(report, policies = {}) { const participants = (report && report.participants) || []; const participantsWithoutCurrentUser = _.without(participants, sessionEmail); const isMultipleParticipantReport = participantsWithoutCurrentUser.length > 1; - return _.map(participantsWithoutCurrentUser, login => getDisplayNameForParticipant(login, isMultipleParticipantReport)).join(', '); + + const displayNames = []; + for (let i = 0; i < participantsWithoutCurrentUser.length; i++) { + const login = participantsWithoutCurrentUser[i]; + displayNames.push(getDisplayNameForParticipant(login, isMultipleParticipantReport)); + } + return displayNames.join(', '); } /** From fd11e185a76d75260ead253bee0e04b4f81ca83a Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Wed, 7 Dec 2022 09:02:49 -0700 Subject: [PATCH 085/133] Micro-optimize --- src/libs/ReportUtils.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 69329a04a200..837181b0d7b5 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -170,11 +170,11 @@ function isAnnounceRoom(report) { * @returns {Boolean} */ function isDefaultRoom(report) { - return _.contains([ + return [ CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, CONST.REPORT.CHAT_TYPE.DOMAIN_ALL, - ], lodashGet(report, ['chatType'], '')); + ].indexOf(report ? report.chatType : '') > -1; } /** @@ -184,7 +184,7 @@ function isDefaultRoom(report) { * @returns {Boolean} */ function isDomainRoom(report) { - return lodashGet(report, ['chatType'], '') === CONST.REPORT.CHAT_TYPE.DOMAIN_ALL; + return (report ? report.chatType : '') === CONST.REPORT.CHAT_TYPE.DOMAIN_ALL; } /** From 01aa33dafff4be812deb9195603fadb2e80edd99 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 7 Dec 2022 17:51:18 +0100 Subject: [PATCH 086/133] Fix method argument --- src/libs/actions/IOU.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 40efba0ca643..2c7d2fdcd188 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -762,7 +762,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType currency, comment, [recipient], - CONST.IOU.PAYMENT_TYPE.ELSEWHERE, + paymentMethodType, '', optimisticIOUReport.reportID, ); From 3ec36251b35cb8e088279ff103958e7e53a50efc Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 7 Dec 2022 17:55:00 +0100 Subject: [PATCH 087/133] Small improvement --- src/libs/actions/IOU.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 2c7d2fdcd188..3bf61d8d0a60 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -732,15 +732,16 @@ function payIOUReport({ * @returns {Object} */ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType, managerEmail, recipient) { + const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login); + const newIOUReportDetails = JSON.stringify({ amount, currency, - requestorEmail: OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login), + requestorEmail: recipientEmail, comment, idempotencyKey: Str.guid(), }); - const recipientEmail = OptionsListUtils.addSMSDomainIfPhoneNumber(recipient.login); let chatReport = report.reportID ? report : null; let isNewChat = false; if (!chatReport) { From 3f8913af2be342922fee6af7a3648bf40b2b398d Mon Sep 17 00:00:00 2001 From: Puneet Date: Wed, 7 Dec 2022 22:49:08 +0530 Subject: [PATCH 088/133] navigate to workspaces on back button press --- src/pages/workspace/WorkspaceInitialPage.js | 5 ++++- src/pages/workspace/WorkspaceInvitePage.js | 6 +++++- src/pages/workspace/WorkspaceMembersPage.js | 5 ++++- src/pages/workspace/WorkspacePageWithSections.js | 5 ++++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/pages/workspace/WorkspaceInitialPage.js b/src/pages/workspace/WorkspaceInitialPage.js index 7ed41d0e2b83..241d275ccf7d 100644 --- a/src/pages/workspace/WorkspaceInitialPage.js +++ b/src/pages/workspace/WorkspaceInitialPage.js @@ -148,7 +148,10 @@ class WorkspaceInitialPage extends React.Component { return ( - + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES)} + > {({didScreenTransitionEnd}) => ( - + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES)} + > <> - + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES)} + > - + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES)} + > Date: Wed, 7 Dec 2022 22:54:12 +0530 Subject: [PATCH 089/133] remove FullPageNotFoundView --- src/pages/workspace/WorkspaceSettingsPage.js | 127 +++++++++---------- 1 file changed, 62 insertions(+), 65 deletions(-) diff --git a/src/pages/workspace/WorkspaceSettingsPage.js b/src/pages/workspace/WorkspaceSettingsPage.js index 9916619518c6..d890a3996dd2 100644 --- a/src/pages/workspace/WorkspaceSettingsPage.js +++ b/src/pages/workspace/WorkspaceSettingsPage.js @@ -20,7 +20,6 @@ import WorkspacePageWithSections from './WorkspacePageWithSections'; import withPolicy, {policyPropTypes, policyDefaultProps} from './withPolicy'; import {withNetwork} from '../../components/OnyxProvider'; import OfflineWithFeedback from '../../components/OfflineWithFeedback'; -import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView'; import Form from '../../components/Form'; const propTypes = { @@ -72,72 +71,70 @@ class WorkspaceSettingsPage extends React.Component { render() { return ( - - - {hasVBA => ( -
+ {hasVBA => ( + + Policy.clearAvatarErrors(this.props.policy.id)} > - Policy.clearAvatarErrors(this.props.policy.id)} - > - ( - - )} - fallbackIcon={Expensicons.FallbackWorkspaceAvatar} - style={[styles.mb3]} - anchorPosition={{top: 172, right: 18}} - isUsingDefaultAvatar={!lodashGet(this.props.policy, 'avatar', null)} - onImageSelected={file => Policy.updateWorkspaceAvatar(lodashGet(this.props.policy, 'id', ''), file)} - onImageRemoved={() => Policy.deleteWorkspaceAvatar(lodashGet(this.props.policy, 'id', ''))} - /> - - - - - ( + - - - {this.props.translate('workspace.editor.currencyInputHelpText')} - - - - )} -
-
+ )} + fallbackIcon={Expensicons.FallbackWorkspaceAvatar} + style={[styles.mb3]} + anchorPosition={{top: 172, right: 18}} + isUsingDefaultAvatar={!lodashGet(this.props.policy, 'avatar', null)} + onImageSelected={file => Policy.updateWorkspaceAvatar(lodashGet(this.props.policy, 'id', ''), file)} + onImageRemoved={() => Policy.deleteWorkspaceAvatar(lodashGet(this.props.policy, 'id', ''))} + /> + + + + + + + + {this.props.translate('workspace.editor.currencyInputHelpText')} + + + + )} + ); } } From 368e48d27c698f7c8aa835cb9300d60747578e09 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 11:27:31 -0700 Subject: [PATCH 090/133] add created param to markCommentAsUnread --- src/libs/actions/Report.js | 4 +++- .../home/report/ContextMenu/ContextMenuActions.js | 2 +- tests/actions/ReportTest.js | 10 +++++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index e5e75e84a200..f00aa61171f3 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -690,13 +690,15 @@ function readNewestAction(reportID) { * Sets the last read comment on a report * * @param {String} reportID + * @param {String} created * @param {Number} sequenceNumber */ -function markCommentAsUnread(reportID, sequenceNumber) { +function markCommentAsUnread(reportID, created, sequenceNumber) { const newLastReadSequenceNumber = sequenceNumber - 1; API.write('MarkAsUnread', { reportID, + created, sequenceNumber, }, { diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 2b7878949ef1..c4075aa5fbb2 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -152,7 +152,7 @@ export default [ successIcon: Expensicons.Checkmark, shouldShow: type => type === CONTEXT_MENU_TYPES.REPORT_ACTION, onPress: (closePopover, {reportAction, reportID}) => { - Report.markCommentAsUnread(reportID, reportAction.sequenceNumber); + Report.markCommentAsUnread(reportID, reportAction.created, reportAction.sequenceNumber); if (closePopover) { hideContextMenu(true, ReportActionComposeFocusManager.focus); } diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 6cfba6aca324..078e3e604aea 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -206,6 +206,7 @@ describe('actions/Report', () => { it('should be updated correctly when new comments are added, deleted or marked as unread', () => { const REPORT_ID = 1; let report; + const reportActionCreated = DateUtils.getDBTime(); Onyx.connect({ key: `${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, callback: val => report = val, @@ -260,7 +261,7 @@ describe('actions/Report', () => { person: [{type: 'TEXT', style: 'strong', text: 'Test User'}], sequenceNumber: 1, shouldShow: true, - created: DateUtils.getDBTime(), + created: reportActionCreated, }, }, }, @@ -280,7 +281,7 @@ describe('actions/Report', () => { expect(ReportUtils.isUnread(report)).toBe(false); // When the user manually marks a message as "unread" - Report.markCommentAsUnread(REPORT_ID, 1); + Report.markCommentAsUnread(REPORT_ID, reportActionCreated, 1); return waitForPromisesToResolve(); }) .then(() => { @@ -354,16 +355,19 @@ describe('actions/Report', () => { 2: { ...USER_1_BASE_ACTION, message: [{type: 'COMMENT', html: 'Current User Comment 1', text: 'Current User Comment 1'}], + created: DateUtils.getDBTime(), sequenceNumber: 2, }, 3: { ...USER_1_BASE_ACTION, message: [{type: 'COMMENT', html: 'Current User Comment 2', text: 'Current User Comment 2'}], + created: DateUtils.getDBTime(), sequenceNumber: 3, }, 4: { ...USER_1_BASE_ACTION, message: [{type: 'COMMENT', html: 'Current User Comment 3', text: 'Current User Comment 3'}], + created: DateUtils.getDBTime(), sequenceNumber: 4, }, }, @@ -383,7 +387,7 @@ describe('actions/Report', () => { expect(ReportUtils.isUnread(report)).toBe(false); // When the user manually marks a message as "unread" - Report.markCommentAsUnread(REPORT_ID, 3); + Report.markCommentAsUnread(REPORT_ID, USER_1_BASE_ACTION.created, 3); return waitForPromisesToResolve(); }) .then(() => { From ae9d8709dcb590201af581262f0ccd86defbf141 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 11:37:14 -0700 Subject: [PATCH 091/133] update tests --- tests/actions/ReportTest.js | 63 ++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 078e3e604aea..a5a7d92aba97 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -206,7 +206,7 @@ describe('actions/Report', () => { it('should be updated correctly when new comments are added, deleted or marked as unread', () => { const REPORT_ID = 1; let report; - const reportActionCreated = DateUtils.getDBTime(); + let reportActionCreated; Onyx.connect({ key: `${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, callback: val => report = val, @@ -233,6 +233,7 @@ describe('actions/Report', () => { .then(() => TestHelper.setPersonalDetails(USER_1_LOGIN, USER_1_ACCOUNT_ID)) .then(() => { // When a Pusher event is handled for a new report comment + reportActionCreated = DateUtils.getDBTime(); channel.emit(Pusher.TYPE.ONYX_API_UPDATE, [ { onyxMethod: CONST.ONYX.METHOD.MERGE, @@ -330,6 +331,36 @@ describe('actions/Report', () => { reportActionID: 'derp', }; + const optimisticReportActions = { + onyxMethod: CONST.ONYX.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${REPORT_ID}`, + value: { + [_.toArray(reportActions)[1].clientID]: null, + [_.toArray(reportActions)[2].clientID]: null, + [_.toArray(reportActions)[3].clientID]: null, + 2: { + ...USER_1_BASE_ACTION, + message: [{type: 'COMMENT', html: 'Current User Comment 1', text: 'Current User Comment 1'}], + created: DateUtils.getDBTime(), + sequenceNumber: 2, + }, + 3: { + ...USER_1_BASE_ACTION, + message: [{type: 'COMMENT', html: 'Current User Comment 2', text: 'Current User Comment 2'}], + created: DateUtils.getDBTime(), + sequenceNumber: 3, + }, + 4: { + ...USER_1_BASE_ACTION, + message: [{type: 'COMMENT', html: 'Current User Comment 3', text: 'Current User Comment 3'}], + created: DateUtils.getDBTime(), + sequenceNumber: 4, + }, + }, + }; + reportActionCreated = DateUtils.getDBTime(); + optimisticReportActions.value[4].created = reportActionCreated; + // When we emit the events for these pending created actions to update them to not pending channel.emit(Pusher.TYPE.ONYX_API_UPDATE, [ { @@ -345,33 +376,7 @@ describe('actions/Report', () => { lastReadSequenceNumber: 4, }, }, - { - onyxMethod: CONST.ONYX.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${REPORT_ID}`, - value: { - [_.toArray(reportActions)[1].clientID]: null, - [_.toArray(reportActions)[2].clientID]: null, - [_.toArray(reportActions)[3].clientID]: null, - 2: { - ...USER_1_BASE_ACTION, - message: [{type: 'COMMENT', html: 'Current User Comment 1', text: 'Current User Comment 1'}], - created: DateUtils.getDBTime(), - sequenceNumber: 2, - }, - 3: { - ...USER_1_BASE_ACTION, - message: [{type: 'COMMENT', html: 'Current User Comment 2', text: 'Current User Comment 2'}], - created: DateUtils.getDBTime(), - sequenceNumber: 3, - }, - 4: { - ...USER_1_BASE_ACTION, - message: [{type: 'COMMENT', html: 'Current User Comment 3', text: 'Current User Comment 3'}], - created: DateUtils.getDBTime(), - sequenceNumber: 4, - }, - }, - }, + optimisticReportActions, ]); return waitForPromisesToResolve(); @@ -387,7 +392,7 @@ describe('actions/Report', () => { expect(ReportUtils.isUnread(report)).toBe(false); // When the user manually marks a message as "unread" - Report.markCommentAsUnread(REPORT_ID, USER_1_BASE_ACTION.created, 3); + Report.markCommentAsUnread(REPORT_ID, reportActionCreated, 3); return waitForPromisesToResolve(); }) .then(() => { From 75a290fa16dffacb06bd09177f9b0b38dc9c9e56 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 11:41:48 -0700 Subject: [PATCH 092/133] update more tests --- tests/ui/UnreadIndicatorsTest.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index b4ba16870cf7..138c5a5286da 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -109,6 +109,8 @@ const USER_B_EMAIL = 'user_b@test.com'; const USER_C_ACCOUNT_ID = 3; const USER_C_EMAIL = 'user_c@test.com'; const MOMENT_FORMAT = 'YYYY-MM-DD HH:mm:ss.SSS'; +let reportAction3Created; +let reportAction9Created; /** * Sets up a test with a logged in user that has one unread chat from another user. Returns the test instance. @@ -127,6 +129,8 @@ function signInAndGetAppWithUnreadChat() { }) .then(() => { const MOMENT_TEN_MINUTES_AGO = moment().subtract(10, 'minutes'); + reportAction3Created = MOMENT_TEN_MINUTES_AGO.add(30, 'seconds').format(MOMENT_FORMAT); + reportAction9Created = MOMENT_TEN_MINUTES_AGO.add(90, 'seconds').format(MOMENT_FORMAT); // Simulate setting an unread report and personal details Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { @@ -160,13 +164,13 @@ function signInAndGetAppWithUnreadChat() { }, 1: TestHelper.buildTestReportComment(USER_B_EMAIL, 1, MOMENT_TEN_MINUTES_AGO.add(10, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 2: TestHelper.buildTestReportComment(USER_B_EMAIL, 2, MOMENT_TEN_MINUTES_AGO.add(20, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), - 3: TestHelper.buildTestReportComment(USER_B_EMAIL, 3, MOMENT_TEN_MINUTES_AGO.add(30, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), + 3: TestHelper.buildTestReportComment(USER_B_EMAIL, 3, reportAction3Created, USER_B_ACCOUNT_ID), 4: TestHelper.buildTestReportComment(USER_B_EMAIL, 4, MOMENT_TEN_MINUTES_AGO.add(40, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 5: TestHelper.buildTestReportComment(USER_B_EMAIL, 5, MOMENT_TEN_MINUTES_AGO.add(50, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 6: TestHelper.buildTestReportComment(USER_B_EMAIL, 6, MOMENT_TEN_MINUTES_AGO.add(60, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 7: TestHelper.buildTestReportComment(USER_B_EMAIL, 7, MOMENT_TEN_MINUTES_AGO.add(70, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 8: TestHelper.buildTestReportComment(USER_B_EMAIL, 8, MOMENT_TEN_MINUTES_AGO.add(80, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), - 9: TestHelper.buildTestReportComment(USER_B_EMAIL, 9, MOMENT_TEN_MINUTES_AGO.add(90, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), + 9: TestHelper.buildTestReportComment(USER_B_EMAIL, 9, reportAction9Created, USER_B_ACCOUNT_ID), }); Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, { [USER_B_EMAIL]: TestHelper.buildPersonalDetails(USER_B_EMAIL, USER_B_ACCOUNT_ID, 'B'), @@ -358,7 +362,7 @@ describe('Unread Indicators', () => { .then(() => { // It's difficult to trigger marking a report comment as unread since we would have to mock the long press event and then // another press on the context menu item so we will do it via the action directly and then test if the UI has updated properly - Report.markCommentAsUnread(REPORT_ID, 3); + Report.markCommentAsUnread(REPORT_ID, reportAction3Created, 3); return waitForPromisesToResolve(); }) .then(() => { @@ -467,7 +471,7 @@ describe('Unread Indicators', () => { expect(unreadIndicator).toHaveLength(0); // Mark a previous comment as unread and verify the unread action indicator returns - Report.markCommentAsUnread(REPORT_ID, 9); + Report.markCommentAsUnread(REPORT_ID, reportAction9Created, 9); return waitForPromisesToResolve(); }) .then(() => { From e8c622e2aa7a64f82df4f32d99d33892b86ff53d Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 11:55:06 -0700 Subject: [PATCH 093/133] add created to readNewestAction --- src/libs/actions/Report.js | 4 +++- src/pages/home/report/ReportActionsView.js | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index f00aa61171f3..9a86d6c30436 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -666,12 +666,14 @@ function openPaymentDetailsPage(chatReportID, iouReportID) { * Marks the new report actions as read * * @param {String} reportID + * @param {String} created */ -function readNewestAction(reportID) { +function readNewestAction(reportID, created) { const sequenceNumber = getMaxSequenceNumber(reportID); API.write('ReadNewestAction', { reportID, + created, sequenceNumber, }, { diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index ff8304bcd281..8eef3412b1ae 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -115,7 +115,7 @@ class ReportActionsView extends React.Component { // If the user is scrolled up and no new line marker is set we will set it otherwise we will do nothing so the new marker // stays in it's previous position. if (this.currentScrollOffset === 0) { - Report.readNewestAction(this.props.report.reportID); + Report.readNewestAction(this.props.report.reportID, _.last(this.props.reportActions).created); this.setState({newMarkerSequenceNumber: 0}); } else if (this.state.newMarkerSequenceNumber === 0) { this.setState({newMarkerSequenceNumber: currentLastSequenceNumber}); @@ -300,7 +300,7 @@ class ReportActionsView extends React.Component { scrollToUnreadMsgAndMarkReportAsRead() { ReportScrollManager.scrollToIndex({animated: true, index: this.props.report.maxSequenceNumber - this.state.newMarkerSequenceNumber}, false); - Report.readNewestAction(this.props.report.reportID); + Report.readNewestAction(this.props.report.reportID, _.last(this.props.reportActions).created); } /** From 4f5c25d475db82bd7152d262cbae1fc50b03ab48 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 12:11:00 -0700 Subject: [PATCH 094/133] convert to array --- src/pages/home/report/ReportActionsView.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index 8eef3412b1ae..72aa95ac824b 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -115,7 +115,7 @@ class ReportActionsView extends React.Component { // If the user is scrolled up and no new line marker is set we will set it otherwise we will do nothing so the new marker // stays in it's previous position. if (this.currentScrollOffset === 0) { - Report.readNewestAction(this.props.report.reportID, _.last(this.props.reportActions).created); + Report.readNewestAction(this.props.report.reportID, _.last(_.toArray(this.props.reportActions)).created); this.setState({newMarkerSequenceNumber: 0}); } else if (this.state.newMarkerSequenceNumber === 0) { this.setState({newMarkerSequenceNumber: currentLastSequenceNumber}); @@ -300,7 +300,7 @@ class ReportActionsView extends React.Component { scrollToUnreadMsgAndMarkReportAsRead() { ReportScrollManager.scrollToIndex({animated: true, index: this.props.report.maxSequenceNumber - this.state.newMarkerSequenceNumber}, false); - Report.readNewestAction(this.props.report.reportID, _.last(this.props.reportActions).created); + Report.readNewestAction(this.props.report.reportID, _.last(_.toArray(this.props.reportActions)).created); } /** From 36cf1e18acf7994d13a4123c1f025a7d1bf1d5eb Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 12:56:57 -0700 Subject: [PATCH 095/133] subtract 1 millisecond --- 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 9a86d6c30436..bbfb5f554911 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -700,7 +700,7 @@ function markCommentAsUnread(reportID, created, sequenceNumber) { API.write('MarkAsUnread', { reportID, - created, + created: DateUtils.getDBTime(new Date(created) - 1), sequenceNumber, }, { From 8d461f63545e0cae3d1177f37d74e60f05bcb90f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 13:02:58 -0700 Subject: [PATCH 096/133] add comment --- src/libs/actions/Report.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index bbfb5f554911..86ae3e6becd5 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -700,6 +700,8 @@ function markCommentAsUnread(reportID, created, sequenceNumber) { API.write('MarkAsUnread', { reportID, + + // We need to subtract 1 millisecond so that the lastRead is updated to just before this reportAction's created date created: DateUtils.getDBTime(new Date(created) - 1), sequenceNumber, }, From bc15a964e968407969ff79555d752f8cd3f67974 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 13:09:53 -0700 Subject: [PATCH 097/133] update comment --- 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 86ae3e6becd5..7cc9a022fc46 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -701,7 +701,7 @@ function markCommentAsUnread(reportID, created, sequenceNumber) { { reportID, - // We need to subtract 1 millisecond so that the lastRead is updated to just before this reportAction's created date + // We subtract 1 millisecond so that the lastRead is updated to just before this reportAction's created date created: DateUtils.getDBTime(new Date(created) - 1), sequenceNumber, }, From 38b76cf792ac99f158a4d4aa5023287d4e3d4f7b Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 13:23:07 -0700 Subject: [PATCH 098/133] rename test vars --- tests/actions/ReportTest.js | 14 +++++++------- tests/ui/UnreadIndicatorsTest.js | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index a5a7d92aba97..9f3e8e478ceb 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -206,7 +206,7 @@ describe('actions/Report', () => { it('should be updated correctly when new comments are added, deleted or marked as unread', () => { const REPORT_ID = 1; let report; - let reportActionCreated; + let reportActionCreatedDate; Onyx.connect({ key: `${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, callback: val => report = val, @@ -233,7 +233,7 @@ describe('actions/Report', () => { .then(() => TestHelper.setPersonalDetails(USER_1_LOGIN, USER_1_ACCOUNT_ID)) .then(() => { // When a Pusher event is handled for a new report comment - reportActionCreated = DateUtils.getDBTime(); + reportActionCreatedDate = DateUtils.getDBTime(); channel.emit(Pusher.TYPE.ONYX_API_UPDATE, [ { onyxMethod: CONST.ONYX.METHOD.MERGE, @@ -262,7 +262,7 @@ describe('actions/Report', () => { person: [{type: 'TEXT', style: 'strong', text: 'Test User'}], sequenceNumber: 1, shouldShow: true, - created: reportActionCreated, + created: reportActionCreatedDate, }, }, }, @@ -282,7 +282,7 @@ describe('actions/Report', () => { expect(ReportUtils.isUnread(report)).toBe(false); // When the user manually marks a message as "unread" - Report.markCommentAsUnread(REPORT_ID, reportActionCreated, 1); + Report.markCommentAsUnread(REPORT_ID, reportActionCreatedDate, 1); return waitForPromisesToResolve(); }) .then(() => { @@ -358,8 +358,8 @@ describe('actions/Report', () => { }, }, }; - reportActionCreated = DateUtils.getDBTime(); - optimisticReportActions.value[4].created = reportActionCreated; + reportActionCreatedDate = DateUtils.getDBTime(); + optimisticReportActions.value[4].created = reportActionCreatedDate; // When we emit the events for these pending created actions to update them to not pending channel.emit(Pusher.TYPE.ONYX_API_UPDATE, [ @@ -392,7 +392,7 @@ describe('actions/Report', () => { expect(ReportUtils.isUnread(report)).toBe(false); // When the user manually marks a message as "unread" - Report.markCommentAsUnread(REPORT_ID, reportActionCreated, 3); + Report.markCommentAsUnread(REPORT_ID, reportActionCreatedDate, 3); return waitForPromisesToResolve(); }) .then(() => { diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index 138c5a5286da..e8ad4895cc33 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -109,8 +109,8 @@ const USER_B_EMAIL = 'user_b@test.com'; const USER_C_ACCOUNT_ID = 3; const USER_C_EMAIL = 'user_c@test.com'; const MOMENT_FORMAT = 'YYYY-MM-DD HH:mm:ss.SSS'; -let reportAction3Created; -let reportAction9Created; +let reportAction3CreatedDate; +let reportAction9CreatedDate; /** * Sets up a test with a logged in user that has one unread chat from another user. Returns the test instance. @@ -129,8 +129,8 @@ function signInAndGetAppWithUnreadChat() { }) .then(() => { const MOMENT_TEN_MINUTES_AGO = moment().subtract(10, 'minutes'); - reportAction3Created = MOMENT_TEN_MINUTES_AGO.add(30, 'seconds').format(MOMENT_FORMAT); - reportAction9Created = MOMENT_TEN_MINUTES_AGO.add(90, 'seconds').format(MOMENT_FORMAT); + reportAction3CreatedDate = MOMENT_TEN_MINUTES_AGO.add(30, 'seconds').format(MOMENT_FORMAT); + reportAction9CreatedDate = MOMENT_TEN_MINUTES_AGO.add(90, 'seconds').format(MOMENT_FORMAT); // Simulate setting an unread report and personal details Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { @@ -164,13 +164,13 @@ function signInAndGetAppWithUnreadChat() { }, 1: TestHelper.buildTestReportComment(USER_B_EMAIL, 1, MOMENT_TEN_MINUTES_AGO.add(10, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 2: TestHelper.buildTestReportComment(USER_B_EMAIL, 2, MOMENT_TEN_MINUTES_AGO.add(20, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), - 3: TestHelper.buildTestReportComment(USER_B_EMAIL, 3, reportAction3Created, USER_B_ACCOUNT_ID), + 3: TestHelper.buildTestReportComment(USER_B_EMAIL, 3, reportAction3CreatedDate, USER_B_ACCOUNT_ID), 4: TestHelper.buildTestReportComment(USER_B_EMAIL, 4, MOMENT_TEN_MINUTES_AGO.add(40, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 5: TestHelper.buildTestReportComment(USER_B_EMAIL, 5, MOMENT_TEN_MINUTES_AGO.add(50, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 6: TestHelper.buildTestReportComment(USER_B_EMAIL, 6, MOMENT_TEN_MINUTES_AGO.add(60, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 7: TestHelper.buildTestReportComment(USER_B_EMAIL, 7, MOMENT_TEN_MINUTES_AGO.add(70, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 8: TestHelper.buildTestReportComment(USER_B_EMAIL, 8, MOMENT_TEN_MINUTES_AGO.add(80, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), - 9: TestHelper.buildTestReportComment(USER_B_EMAIL, 9, reportAction9Created, USER_B_ACCOUNT_ID), + 9: TestHelper.buildTestReportComment(USER_B_EMAIL, 9, reportAction9CreatedDate, USER_B_ACCOUNT_ID), }); Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, { [USER_B_EMAIL]: TestHelper.buildPersonalDetails(USER_B_EMAIL, USER_B_ACCOUNT_ID, 'B'), @@ -362,7 +362,7 @@ describe('Unread Indicators', () => { .then(() => { // It's difficult to trigger marking a report comment as unread since we would have to mock the long press event and then // another press on the context menu item so we will do it via the action directly and then test if the UI has updated properly - Report.markCommentAsUnread(REPORT_ID, reportAction3Created, 3); + Report.markCommentAsUnread(REPORT_ID, reportAction3CreatedDate, 3); return waitForPromisesToResolve(); }) .then(() => { @@ -471,7 +471,7 @@ describe('Unread Indicators', () => { expect(unreadIndicator).toHaveLength(0); // Mark a previous comment as unread and verify the unread action indicator returns - Report.markCommentAsUnread(REPORT_ID, reportAction9Created, 9); + Report.markCommentAsUnread(REPORT_ID, reportAction9CreatedDate, 9); return waitForPromisesToResolve(); }) .then(() => { From caec96cf83703f23355026794c8315be0ba5ff24 Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Wed, 7 Dec 2022 12:44:22 -0800 Subject: [PATCH 099/133] Handle error rendering --- src/components/PDFView/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/PDFView/index.js b/src/components/PDFView/index.js index 4fb45de1724d..1b6646ec49d6 100644 --- a/src/components/PDFView/index.js +++ b/src/components/PDFView/index.js @@ -9,6 +9,7 @@ import CONST from '../../CONST'; import PDFPasswordForm from './PDFPasswordForm'; import * as pdfViewPropTypes from './pdfViewPropTypes'; import withWindowDimensions from '../withWindowDimensions'; +import Text from '../Text'; class PDFView extends Component { constructor(props) { @@ -125,6 +126,7 @@ class PDFView extends Component { onLayout={event => this.setState({windowWidth: event.nativeEvent.layout.width})} > Failed to load PDF file.} loading={} file={this.props.sourceURL} options={{ From c2584bf1c7520f1d7570a9f22baf3121549a9625 Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Wed, 7 Dec 2022 13:01:26 -0800 Subject: [PATCH 100/133] Translate failed to load PDF error --- src/components/PDFView/index.js | 9 +++++++-- src/languages/en.js | 1 + src/languages/es.js | 1 + 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/PDFView/index.js b/src/components/PDFView/index.js index 1b6646ec49d6..fcead57588d9 100644 --- a/src/components/PDFView/index.js +++ b/src/components/PDFView/index.js @@ -9,7 +9,9 @@ import CONST from '../../CONST'; import PDFPasswordForm from './PDFPasswordForm'; import * as pdfViewPropTypes from './pdfViewPropTypes'; import withWindowDimensions from '../withWindowDimensions'; +import withLocalize from '../withLocalize'; import Text from '../Text'; +import compose from '../../libs/compose'; class PDFView extends Component { constructor(props) { @@ -126,7 +128,7 @@ class PDFView extends Component { onLayout={event => this.setState({windowWidth: event.nativeEvent.layout.width})} > Failed to load PDF file.} + error={{this.props.translate('attachmentView.failedToLoadPDF')}} loading={} file={this.props.sourceURL} options={{ @@ -163,4 +165,7 @@ class PDFView extends Component { PDFView.propTypes = pdfViewPropTypes.propTypes; PDFView.defaultProps = pdfViewPropTypes.defaultProps; -export default withWindowDimensions(PDFView); +export default compose( + withLocalize, + withWindowDimensions, +)(PDFView); diff --git a/src/languages/en.js b/src/languages/en.js index bd745b387245..283a75aab303 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -631,6 +631,7 @@ export default { unknownFilename: 'Unknown filename', passwordRequired: 'Please enter a password', passwordIncorrect: 'Incorrect password. Please try again.', + failedToLoadPDF: 'Failed to load PDF file.', pdfPasswordForm: { title: 'Password protected PDF', infoText: 'This PDF is password protected.', diff --git a/src/languages/es.js b/src/languages/es.js index 063faca6e4e2..2274968ea622 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -631,6 +631,7 @@ export default { unknownFilename: 'Archivo desconocido', passwordRequired: 'Por favor introduce tu contraseña', passwordIncorrect: 'Contraseña incorrecta. Por favor intenta de nuevo.', + failedToLoadPDF: 'Hubo un error al intentar cargar el PDF.', pdfPasswordForm: { title: 'PDF protegido con contraseña', infoText: 'Este PDF esta protegido con contraseña.', From 8a66b2dcde3c0432ee0c64a53d4aeea82c9743e3 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 14:06:09 -0700 Subject: [PATCH 101/133] fix tests --- tests/ui/UnreadIndicatorsTest.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index e8ad4895cc33..cb777bcd61e2 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -129,8 +129,8 @@ function signInAndGetAppWithUnreadChat() { }) .then(() => { const MOMENT_TEN_MINUTES_AGO = moment().subtract(10, 'minutes'); - reportAction3CreatedDate = MOMENT_TEN_MINUTES_AGO.add(30, 'seconds').format(MOMENT_FORMAT); - reportAction9CreatedDate = MOMENT_TEN_MINUTES_AGO.add(90, 'seconds').format(MOMENT_FORMAT); + reportAction3CreatedDate = MOMENT_TEN_MINUTES_AGO.clone().add(30, 'seconds').format(MOMENT_FORMAT); + reportAction9CreatedDate = MOMENT_TEN_MINUTES_AGO.clone().add(90, 'seconds').format(MOMENT_FORMAT); // Simulate setting an unread report and personal details Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { @@ -138,7 +138,7 @@ function signInAndGetAppWithUnreadChat() { reportName: CONST.REPORT.DEFAULT_REPORT_NAME, maxSequenceNumber: 9, lastReadSequenceNumber: 1, - lastActionCreated: DateUtils.getDBTime(MOMENT_TEN_MINUTES_AGO.utc().valueOf()), + lastActionCreated: DateUtils.getDBTime(MOMENT_TEN_MINUTES_AGO.clone().utc().valueOf()), lastMessageText: 'Test', participants: [USER_B_EMAIL], }); @@ -147,7 +147,7 @@ function signInAndGetAppWithUnreadChat() { actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, automatic: false, sequenceNumber: 0, - created: MOMENT_TEN_MINUTES_AGO.format(MOMENT_FORMAT), + created: MOMENT_TEN_MINUTES_AGO.clone().format(MOMENT_FORMAT), reportActionID: NumberUtils.rand64(), message: [ { @@ -162,14 +162,14 @@ function signInAndGetAppWithUnreadChat() { }, ], }, - 1: TestHelper.buildTestReportComment(USER_B_EMAIL, 1, MOMENT_TEN_MINUTES_AGO.add(10, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), - 2: TestHelper.buildTestReportComment(USER_B_EMAIL, 2, MOMENT_TEN_MINUTES_AGO.add(20, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), + 1: TestHelper.buildTestReportComment(USER_B_EMAIL, 1, MOMENT_TEN_MINUTES_AGO.clone().add(10, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), + 2: TestHelper.buildTestReportComment(USER_B_EMAIL, 2, MOMENT_TEN_MINUTES_AGO.clone().add(20, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 3: TestHelper.buildTestReportComment(USER_B_EMAIL, 3, reportAction3CreatedDate, USER_B_ACCOUNT_ID), - 4: TestHelper.buildTestReportComment(USER_B_EMAIL, 4, MOMENT_TEN_MINUTES_AGO.add(40, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), - 5: TestHelper.buildTestReportComment(USER_B_EMAIL, 5, MOMENT_TEN_MINUTES_AGO.add(50, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), - 6: TestHelper.buildTestReportComment(USER_B_EMAIL, 6, MOMENT_TEN_MINUTES_AGO.add(60, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), - 7: TestHelper.buildTestReportComment(USER_B_EMAIL, 7, MOMENT_TEN_MINUTES_AGO.add(70, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), - 8: TestHelper.buildTestReportComment(USER_B_EMAIL, 8, MOMENT_TEN_MINUTES_AGO.add(80, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), + 4: TestHelper.buildTestReportComment(USER_B_EMAIL, 4, MOMENT_TEN_MINUTES_AGO.clone().add(40, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), + 5: TestHelper.buildTestReportComment(USER_B_EMAIL, 5, MOMENT_TEN_MINUTES_AGO.clone().add(50, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), + 6: TestHelper.buildTestReportComment(USER_B_EMAIL, 6, MOMENT_TEN_MINUTES_AGO.clone().add(60, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), + 7: TestHelper.buildTestReportComment(USER_B_EMAIL, 7, MOMENT_TEN_MINUTES_AGO.clone().add(70, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), + 8: TestHelper.buildTestReportComment(USER_B_EMAIL, 8, MOMENT_TEN_MINUTES_AGO.clone().add(80, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID), 9: TestHelper.buildTestReportComment(USER_B_EMAIL, 9, reportAction9CreatedDate, USER_B_ACCOUNT_ID), }); Onyx.merge(ONYXKEYS.PERSONAL_DETAILS, { From 68fa690ce61469d61275a5329212e0ba8b087557 Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 7 Dec 2022 14:18:27 -0700 Subject: [PATCH 102/133] use db time --- 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 095b21081945..90dc443cb4f8 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -673,7 +673,7 @@ function readNewestAction(reportID, created) { API.write('ReadNewestAction', { reportID, - created, + created: DateUtils.getDBTime(created), sequenceNumber, }, { From 729f56c7798a1d6000cbd5d195ceff6d23d34c50 Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Wed, 7 Dec 2022 14:14:13 -0800 Subject: [PATCH 103/133] Handle failure to load PDF in IOS and Android --- src/components/PDFView/index.native.js | 36 +++++++++++++++++++------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/components/PDFView/index.native.js b/src/components/PDFView/index.native.js index cc4db7b97078..a11cc9304ee1 100644 --- a/src/components/PDFView/index.native.js +++ b/src/components/PDFView/index.native.js @@ -1,15 +1,17 @@ import React, {Component} from 'react'; -import {TouchableWithoutFeedback, View} from 'react-native'; +import {TouchableWithoutFeedback, StyleSheet, View} from 'react-native'; import PDF from 'react-native-pdf'; import KeyboardAvoidingView from '../KeyboardAvoidingView'; import styles from '../../styles/styles'; import * as StyleUtils from '../../styles/StyleUtils'; import FullScreenLoadingIndicator from '../FullscreenLoadingIndicator'; +import Text from '../Text'; import PDFPasswordForm from './PDFPasswordForm'; import * as pdfViewPropTypes from './pdfViewPropTypes'; import compose from '../../libs/compose'; import withWindowDimensions from '../withWindowDimensions'; import withKeyboardState from '../withKeyboardState'; +import withLocalize from '../withLocalize'; /** * On the native layer, we use react-native-pdf/PDF to display PDFs. If a PDF is @@ -33,17 +35,31 @@ class PDFView extends Component { shouldAttemptPdfLoad: true, shouldShowLoadingIndicator: true, isPasswordInvalid: false, + failedToLoadPDF: false, password: '', }; this.initiatePasswordChallenge = this.initiatePasswordChallenge.bind(this); this.attemptPdfLoadWithPassword = this.attemptPdfLoadWithPassword.bind(this); this.finishPdfLoad = this.finishPdfLoad.bind(this); + this.handleFailureToLoadPDF = this.handleFailureToLoadPDF.bind(this); } componentDidUpdate() { this.props.onToggleKeyboard(this.props.isShown); } + handleFailureToLoadPDF(error) { + if (error.message.match(/password/i)) { + this.initiatePasswordChallenge(); + return; + } + + this.setState({ + failedToLoadPDF: true, + shouldAttemptPdfLoad: false, + }); + } + /** * Initiate password challenge if message received from react-native-pdf/PDF * indicates that a password is required or invalid. @@ -51,16 +67,10 @@ class PDFView extends Component { * For a password challenge the message is "Password required or incorrect password." * Note that the message doesn't specify whether the password is simply empty or * invalid. - * - * @param {String} message */ - initiatePasswordChallenge({message}) { + initiatePasswordChallenge() { this.setState({shouldShowLoadingIndicator: false}); - if (!message.match(/password/i)) { - return; - } - // Render password form, and don't render PDF and loading indicator. this.setState({ shouldRequestPassword: true, @@ -129,6 +139,13 @@ class PDFView extends Component { return ( + {this.state.failedToLoadPDF && ( + + + {this.props.translate('attachmentView.failedToLoadPDF')} + + + )} {this.state.shouldAttemptPdfLoad && ( } source={{uri: this.props.sourceURL}} style={pdfStyles} - onError={this.initiatePasswordChallenge} + onError={this.handleFailureToLoadPDF} password={this.state.password} onLoadComplete={this.finishPdfLoad} /> @@ -163,4 +180,5 @@ PDFView.defaultProps = pdfViewPropTypes.defaultProps; export default compose( withWindowDimensions, withKeyboardState, + withLocalize, )(PDFView); From 83890cbd8fce6993d50e844ab7343ffe94835985 Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Wed, 7 Dec 2022 14:18:06 -0800 Subject: [PATCH 104/133] Remove unused import --- src/components/PDFView/index.native.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PDFView/index.native.js b/src/components/PDFView/index.native.js index a11cc9304ee1..bf2a632dc32e 100644 --- a/src/components/PDFView/index.native.js +++ b/src/components/PDFView/index.native.js @@ -1,5 +1,5 @@ import React, {Component} from 'react'; -import {TouchableWithoutFeedback, StyleSheet, View} from 'react-native'; +import {TouchableWithoutFeedback, View} from 'react-native'; import PDF from 'react-native-pdf'; import KeyboardAvoidingView from '../KeyboardAvoidingView'; import styles from '../../styles/styles'; From c5355eb9aad00e87b46a1a9bb813d7395f2cdcbf Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Wed, 7 Dec 2022 12:49:52 -1000 Subject: [PATCH 105/133] Fix incorporation date error --- 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 d57e6be6cc1a..41cd4dc06b9d 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -104,7 +104,7 @@ class CompanyStep extends React.Component { } if (!values.incorporationDate || !ValidationUtils.isValidPastDate(values.incorporationDate)) { - errors.incorporationDateFuture = this.props.translate('bankAccount.error.incorporationDateFuture'); + errors.incorporationDate = this.props.translate('bankAccount.error.incorporationDateFuture'); } if (!values.incorporationState) { From 1b150237ff2e85e813abfd230d33ae1cc24c80b4 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Thu, 8 Dec 2022 00:33:47 +0100 Subject: [PATCH 106/133] Remove unneeded code --- src/libs/actions/IOU.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 3bf61d8d0a60..0a6d0767676d 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -818,7 +818,6 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { [optimisticIOUReportAction.sequenceNumber]: { - ...optimisticIOUReportAction, errors: { [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.other'), }, From 2f2a2cd3c3e052765153365f44e85639b3f40046 Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Wed, 7 Dec 2022 16:54:41 -0800 Subject: [PATCH 107/133] Higher initial number to render --- src/components/OptionsList/BaseOptionsList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/OptionsList/BaseOptionsList.js b/src/components/OptionsList/BaseOptionsList.js index f7b716e4f544..d2172bb4466f 100644 --- a/src/components/OptionsList/BaseOptionsList.js +++ b/src/components/OptionsList/BaseOptionsList.js @@ -229,7 +229,7 @@ class BaseOptionsList extends Component { getItemLayout={this.getItemLayout} renderSectionHeader={this.renderSectionHeader} extraData={this.props.focusedIndex} - initialNumToRender={5} + initialNumToRender={12} maxToRenderPerBatch={5} windowSize={5} viewabilityConfig={this.viewabilityConfig} From 797b353f2c6aee0521c1be724117ecbf563a2d92 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Thu, 8 Dec 2022 01:44:30 +0000 Subject: [PATCH 108/133] Update version to 1.2.37-0 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 4 ++-- ios/NewExpensifyTests/Info.plist | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 51a571a10c0a..e786e27a7136 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -156,8 +156,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001023604 - versionName "1.2.36-4" + versionCode 1001023700 + versionName "1.2.37-0" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 985d07759945..5b955cd7e739 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.36 + 1.2.37 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.36.4 + 1.2.37.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 6b4f494ff64b..a65379f25781 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.2.36 + 1.2.37 CFBundleSignature ???? CFBundleVersion - 1.2.36.4 + 1.2.37.0 diff --git a/package-lock.json b/package-lock.json index 654bcc91c693..e7c7570c679c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.2.36-4", + "version": "1.2.37-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.2.36-4", + "version": "1.2.37-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 511929dab0cf..55f8b2b27283 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.2.36-4", + "version": "1.2.37-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From e7d78baf4b1946a753f8c18d9268f5beb0d8b734 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Thu, 8 Dec 2022 04:03:07 +0100 Subject: [PATCH 109/133] Fix IOU Preview still showing after failed pay request --- src/components/ReportActionItem/IOUAction.js | 40 ++++++++++++-------- src/libs/actions/IOU.js | 4 +- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/components/ReportActionItem/IOUAction.js b/src/components/ReportActionItem/IOUAction.js index 71717dad1faf..affa1035eb64 100644 --- a/src/components/ReportActionItem/IOUAction.js +++ b/src/components/ReportActionItem/IOUAction.js @@ -25,6 +25,9 @@ const propTypes = { chatReport: PropTypes.shape({ /** The participants of this report */ participants: PropTypes.arrayOf(PropTypes.string), + + /** Whether the chat report has an outstanding IOU */ + hasOutstandingIOU: PropTypes.bool.isRequired, }), /** Whether the IOU is hovered so we can modify its style */ @@ -43,6 +46,12 @@ const IOUAction = (props) => { const launchDetailsModal = () => { Navigation.navigate(ROUTES.getIouDetailsRoute(props.chatReportID, props.action.originalMessage.IOUReportID)); }; + + const shouldShowIOUPreview = ( + props.isMostRecentIOUReportAction + && Boolean(props.action.originalMessage.IOUReportID) + && props.chatReport.hasOutstandingIOU) || props.action.originalMessage.type === 'pay'; + return ( <> { shouldAllowViewDetails={Boolean(props.action.originalMessage.IOUReportID)} onViewDetailsPressed={launchDetailsModal} /> - {((props.isMostRecentIOUReportAction && Boolean(props.action.originalMessage.IOUReportID)) - || (props.action.originalMessage.type === 'pay')) && ( - + {shouldShowIOUPreview && ( + )} ); diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 0a6d0767676d..0157dc590eff 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -897,7 +897,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho lastMessageText: optimisticIOUReportAction.message[0].text, lastMessageHtml: optimisticIOUReportAction.message[0].html, hasOutstandingIOU: false, - iouReportID: iouReport.reportID, + iouReportID: null, }, }, { @@ -939,8 +939,6 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`, value: { [optimisticIOUReportAction.sequenceNumber]: { - hasOutstandingIOU: true, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, pendingAction: null, errors: { [DateUtils.getMicroseconds()]: Localize.translateLocal('iou.error.other'), From 4c78be6e261ac6dc474387a110f9f1d568d8e5ed Mon Sep 17 00:00:00 2001 From: b1tjoy <103875612+b1tjoy@users.noreply.github.com> Date: Thu, 8 Dec 2022 12:17:38 +0800 Subject: [PATCH 110/133] convert setHTMLSync to normal function and move it to index.js --- src/libs/Clipboard/index.js | 77 ++++++++++++++++--- src/libs/Clipboard/index.website.js | 80 -------------------- src/libs/Clipboard/miscClipboardFunctions.js | 19 ----- 3 files changed, 67 insertions(+), 109 deletions(-) delete mode 100644 src/libs/Clipboard/index.website.js delete mode 100644 src/libs/Clipboard/miscClipboardFunctions.js diff --git a/src/libs/Clipboard/index.js b/src/libs/Clipboard/index.js index 60c3cff2fb72..fb3e6654e413 100644 --- a/src/libs/Clipboard/index.js +++ b/src/libs/Clipboard/index.js @@ -1,7 +1,47 @@ -import MiscClipboardFunctions from './miscClipboardFunctions'; +// on Web/desktop this import will be replaced with `react-native-web` +import {Clipboard} from 'react-native-web'; +import lodashGet from 'lodash/get'; +import CONST from '../../CONST'; +import * as Browser from '../Browser'; -const canSetHtml = MiscClipboardFunctions.canSetHtml; -const setString = MiscClipboardFunctions.setString; +const canSetHtml = () => lodashGet(navigator, 'clipboard.write'); + +/** + * Deprecated method to write the content as HTML to clipboard. + * @param {String} html HTML representation + * @param {String} text Plain text representation + */ +function setHTMLSync(html, text) { + const node = document.createElement('span'); + node.textContent = html; + node.style.all = 'unset'; + node.style.opacity = '0'; + node.style.position = 'absolute'; + node.style.whiteSpace = 'pre-wrap'; + node.style.userSelect = 'text'; + node.addEventListener('copy', (e) => { + e.stopPropagation(); + e.preventDefault(); + e.clipboardData.clearData(); + e.clipboardData.setData('text/html', html); + e.clipboardData.setData('text/plain', text); + }); + document.body.appendChild(node); + + const selection = window.getSelection(); + selection.removeAllRanges(); + const range = document.createRange(); + range.selectNodeContents(node); + selection.addRange(range); + + try { + document.execCommand('copy'); + // eslint-disable-next-line no-empty + } catch (e) {} + + selection.removeAllRanges(); + document.body.removeChild(node); +} /** * Writes the content as HTML if the web client supports it. @@ -17,13 +57,30 @@ const setHtml = (html, text) => { throw new Error('clipboard.write is not supported on this platform, thus HTML cannot be copied.'); } - navigator.clipboard.write([ - // eslint-disable-next-line no-undef - new ClipboardItem({ - 'text/html': new Blob([html], {type: 'text/html'}), - 'text/plain': new Blob([text], {type: 'text/plain'}), - }), - ]); + if (CONST.BROWSER.SAFARI === Browser.getBrowser()) { + // Safari sanitize "text/html" data before writing to the pasteboard when using Clipboard API, + // whitespaces in the start of line are stripped away. We use the deprecated method to copy + // contents as HTML and keep whitespaces in the start of line on Safari. + // See https://webkit.org/blog/10855/async-clipboard-api/ for more details. + setHTMLSync(html, text); + } else { + navigator.clipboard.write([ + // eslint-disable-next-line no-undef + new ClipboardItem({ + 'text/html': new Blob([html], {type: 'text/html'}), + 'text/plain': new Blob([text], {type: 'text/plain'}), + }), + ]); + } +}; + +/** + * Sets a string on the Clipboard object via react-native-web + * + * @param {String} text + */ +const setString = (text) => { + Clipboard.setString(text); }; export default { diff --git a/src/libs/Clipboard/index.website.js b/src/libs/Clipboard/index.website.js deleted file mode 100644 index 30e2afc4fe18..000000000000 --- a/src/libs/Clipboard/index.website.js +++ /dev/null @@ -1,80 +0,0 @@ -import CONST from '../../CONST'; -import * as Browser from '../Browser'; -import MiscClipboardFunctions from './miscClipboardFunctions'; - -const canSetHtml = MiscClipboardFunctions.canSetHtml; -const setString = MiscClipboardFunctions.setString; - -/** - * Deprecated method to write the content as HTML to clipboard. - * @param {String} html HTML representation - * @param {String} text Plain text representation - */ -const copyToClipboardDeprecated = (html, text) => { - const node = document.createElement('span'); - node.textContent = html; - node.style.all = 'unset'; - node.style.opacity = '0'; - node.style.position = 'absolute'; - node.style.whiteSpace = 'pre-wrap'; - node.style.userSelect = 'text'; - node.addEventListener('copy', (e) => { - e.stopPropagation(); - e.preventDefault(); - e.clipboardData.clearData(); - e.clipboardData.setData('text/html', html); - e.clipboardData.setData('text/plain', text); - }); - document.body.appendChild(node); - - const selection = window.getSelection(); - selection.removeAllRanges(); - const range = document.createRange(); - range.selectNodeContents(node); - selection.addRange(range); - - try { - document.execCommand('copy'); - // eslint-disable-next-line no-empty - } catch (e) {} - - selection.removeAllRanges(); - document.body.removeChild(node); -}; - -/** - * Writes the content as HTML if the web client supports it. - * @param {String} html HTML representation - * @param {String} text Plain text representation - */ -const setHtml = (html, text) => { - if (!html || !text) { - return; - } - - if (!canSetHtml()) { - throw new Error('clipboard.write is not supported on this platform, thus HTML cannot be copied.'); - } - - if (CONST.BROWSER.SAFARI === Browser.getBrowser()) { - // Safari sanitize "text/html" data before writing to the pasteboard when using Clipboard API, - // whitespaces in the start of line are stripped away. We use the deprecated method to copy - // contents as HTML and keep whitespaces in the start of line on Safari. - // See https://webkit.org/blog/10855/async-clipboard-api/ for more details. - copyToClipboardDeprecated(html, text); - } else { - navigator.clipboard.write([ - // eslint-disable-next-line no-undef - new ClipboardItem({ - 'text/html': new Blob([html], {type: 'text/html'}), - 'text/plain': new Blob([text], {type: 'text/plain'}), - }), - ]); - } -}; - -export default { - setString, - canSetHtml, - setHtml, -}; diff --git a/src/libs/Clipboard/miscClipboardFunctions.js b/src/libs/Clipboard/miscClipboardFunctions.js deleted file mode 100644 index 259e98a7f5d8..000000000000 --- a/src/libs/Clipboard/miscClipboardFunctions.js +++ /dev/null @@ -1,19 +0,0 @@ -// on Web/desktop this import will be replaced with `react-native-web` -import {Clipboard} from 'react-native-web'; -import lodashGet from 'lodash/get'; - -const canSetHtml = () => lodashGet(navigator, 'clipboard.write'); - -/** - * Sets a string on the Clipboard object via react-native-web - * - * @param {String} text - */ -const setString = (text) => { - Clipboard.setString(text); -}; - -export default { - setString, - canSetHtml, -}; From 7739a378ad3489e1a978311bcfc90d2495298e4c Mon Sep 17 00:00:00 2001 From: Alberto Date: Thu, 8 Dec 2022 11:37:24 +0100 Subject: [PATCH 111/133] add maxlength --- src/components/RoomNameInput/index.native.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/RoomNameInput/index.native.js b/src/components/RoomNameInput/index.native.js index 2eb22be46e18..239eb3156e43 100644 --- a/src/components/RoomNameInput/index.native.js +++ b/src/components/RoomNameInput/index.native.js @@ -34,6 +34,7 @@ class RoomNameInput extends Component { value={this.props.value.substring(1)} // Since the room name always starts with a prefix, we omit the first character to avoid displaying it twice. errorText={this.props.errorText} autoCapitalize="none" + maxLength={CONST.REPORT.MAX_ROOM_NAME_LENGTH} /> ); } From fe72acbf147b93192a152982a4d6ac576e03bc1b Mon Sep 17 00:00:00 2001 From: Puneet Date: Thu, 8 Dec 2022 22:15:14 +0530 Subject: [PATCH 112/133] remove / --- src/languages/en.js | 2 +- src/languages/es.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 9b19dac3406d..403bab7f3aa5 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -418,7 +418,7 @@ export default { nameOnCard: 'Name on card', debitCardNumber: 'Debit card number', expiration: 'Expiration date', - expirationDate: 'MM/YY', + expirationDate: 'MMYY', cvv: 'CVV', billingAddress: 'Billing address', expensifyTermsOfService: 'Expensify Terms of Service', diff --git a/src/languages/es.js b/src/languages/es.js index 0462f80af814..45274080d86a 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -418,7 +418,7 @@ export default { nameOnCard: 'Nombre en la tarjeta', debitCardNumber: 'Numero de la tarjeta de débito', expiration: 'Fecha de vencimiento', - expirationDate: 'MM/AA', + expirationDate: 'MMAA', cvv: 'CVV', billingAddress: 'Dirección de envio', expensifyTermsOfService: 'Expensify Términos de servicio', From f3c4c99d24f105d0eadbfa5d3c8269829a164a85 Mon Sep 17 00:00:00 2001 From: Puneet Date: Thu, 8 Dec 2022 22:15:45 +0530 Subject: [PATCH 113/133] add character limit --- src/pages/settings/Payments/AddDebitCardPage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/settings/Payments/AddDebitCardPage.js b/src/pages/settings/Payments/AddDebitCardPage.js index dd5f394163c3..5ab14f4c3b96 100644 --- a/src/pages/settings/Payments/AddDebitCardPage.js +++ b/src/pages/settings/Payments/AddDebitCardPage.js @@ -139,6 +139,7 @@ class DebitCardPage extends Component { label={this.props.translate('addDebitCardPage.expiration')} placeholder={this.props.translate('addDebitCardPage.expirationDate')} keyboardType={CONST.KEYBOARD_TYPE.NUMBER_PAD} + maxLength={4} /> From 3843798bab4b9cb52872679bef74aeb112d13299 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Thu, 8 Dec 2022 10:00:06 -0700 Subject: [PATCH 114/133] DRY up checking the report chatType and fix a console error --- src/components/OptionsList/BaseOptionsList.js | 5 ++--- .../OptionsList/optionsListPropTypes.js | 2 -- src/libs/ReportUtils.js | 16 ++++++++++------ src/pages/SearchPage.js | 1 + 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/components/OptionsList/BaseOptionsList.js b/src/components/OptionsList/BaseOptionsList.js index 3de630dde272..d1e16c6254be 100644 --- a/src/components/OptionsList/BaseOptionsList.js +++ b/src/components/OptionsList/BaseOptionsList.js @@ -2,7 +2,6 @@ import _ from 'underscore'; import React, {forwardRef, Component} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; -import CONST from '../../CONST'; import styles from '../../styles/styles'; import variables from '../../styles/variables'; import OptionRow from '../OptionRow'; @@ -204,13 +203,13 @@ class BaseOptionsList extends Component { render() { return ( - {this.props.headerMessage && ( + {this.props.headerMessage ? ( {this.props.headerMessage} - )} + ) : null} allReports = val, }); +function getChatType(report) { + return report ? report.chatType : ''; +} + /** * Returns the concatenated title for the PrimaryLogins of a report * @@ -150,7 +154,7 @@ function canDeleteReportAction(reportAction) { * @returns {Boolean} */ function isAdminRoom(report) { - return lodashGet(report, ['chatType'], '') === CONST.REPORT.CHAT_TYPE.POLICY_ADMINS; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_ADMINS; } /** @@ -160,7 +164,7 @@ function isAdminRoom(report) { * @returns {Boolean} */ function isAnnounceRoom(report) { - return lodashGet(report, ['chatType'], '') === CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE; } /** @@ -174,7 +178,7 @@ function isDefaultRoom(report) { CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, CONST.REPORT.CHAT_TYPE.DOMAIN_ALL, - ].indexOf(report ? report.chatType : '') > -1; + ].indexOf(getChatType(report)) > -1; } /** @@ -184,7 +188,7 @@ function isDefaultRoom(report) { * @returns {Boolean} */ function isDomainRoom(report) { - return (report ? report.chatType : '') === CONST.REPORT.CHAT_TYPE.DOMAIN_ALL; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.DOMAIN_ALL; } /** @@ -194,7 +198,7 @@ function isDomainRoom(report) { * @returns {Boolean} */ function isUserCreatedPolicyRoom(report) { - return lodashGet(report, ['chatType'], '') === CONST.REPORT.CHAT_TYPE.POLICY_ROOM; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_ROOM; } /** @@ -204,7 +208,7 @@ function isUserCreatedPolicyRoom(report) { * @returns {Boolean} */ function isPolicyExpenseChat(report) { - return lodashGet(report, ['chatType'], '') === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT; } /** diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js index 6c13340a3986..0ba284a4112f 100755 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -129,6 +129,7 @@ class SearchPage extends Component { this.state.searchValue.trim(), this.props.betas, ); + console.log(recentReports, personalDetails, userToInvite); this.setState({ userToInvite, recentReports, From c9d098163ad2be2a88fa905690dc69a3dd9979c7 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Thu, 8 Dec 2022 10:00:06 -0700 Subject: [PATCH 115/133] DRY up checking the report chatType and fix a console error --- src/components/OptionsList/BaseOptionsList.js | 5 ++--- .../OptionsList/optionsListPropTypes.js | 2 -- src/libs/ReportUtils.js | 18 +++++++++++------- src/pages/SearchPage.js | 1 + 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/components/OptionsList/BaseOptionsList.js b/src/components/OptionsList/BaseOptionsList.js index 3de630dde272..d1e16c6254be 100644 --- a/src/components/OptionsList/BaseOptionsList.js +++ b/src/components/OptionsList/BaseOptionsList.js @@ -2,7 +2,6 @@ import _ from 'underscore'; import React, {forwardRef, Component} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; -import CONST from '../../CONST'; import styles from '../../styles/styles'; import variables from '../../styles/variables'; import OptionRow from '../OptionRow'; @@ -204,13 +203,13 @@ class BaseOptionsList extends Component { render() { return ( - {this.props.headerMessage && ( + {this.props.headerMessage ? ( {this.props.headerMessage} - )} + ) : null} allReports = val, }); +function getChatType(report) { + return report ? report.chatType : ''; +} + /** * Returns the concatenated title for the PrimaryLogins of a report * @@ -150,7 +154,7 @@ function canDeleteReportAction(reportAction) { * @returns {Boolean} */ function isAdminRoom(report) { - return lodashGet(report, ['chatType'], '') === CONST.REPORT.CHAT_TYPE.POLICY_ADMINS; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_ADMINS; } /** @@ -160,7 +164,7 @@ function isAdminRoom(report) { * @returns {Boolean} */ function isAnnounceRoom(report) { - return lodashGet(report, ['chatType'], '') === CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE; } /** @@ -174,7 +178,7 @@ function isDefaultRoom(report) { CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, CONST.REPORT.CHAT_TYPE.DOMAIN_ALL, - ].indexOf(report ? report.chatType : '') > -1; + ].indexOf(getChatType(report)) > -1; } /** @@ -184,7 +188,7 @@ function isDefaultRoom(report) { * @returns {Boolean} */ function isDomainRoom(report) { - return (report ? report.chatType : '') === CONST.REPORT.CHAT_TYPE.DOMAIN_ALL; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.DOMAIN_ALL; } /** @@ -194,7 +198,7 @@ function isDomainRoom(report) { * @returns {Boolean} */ function isUserCreatedPolicyRoom(report) { - return lodashGet(report, ['chatType'], '') === CONST.REPORT.CHAT_TYPE.POLICY_ROOM; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_ROOM; } /** @@ -204,7 +208,7 @@ function isUserCreatedPolicyRoom(report) { * @returns {Boolean} */ function isPolicyExpenseChat(report) { - return lodashGet(report, ['chatType'], '') === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT; + return getChatType(report) === CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT; } /** @@ -301,7 +305,7 @@ function getChatRoomSubtitle(report, policiesMap) { if (!isDefaultRoom(report) && !isUserCreatedPolicyRoom(report) && !isPolicyExpenseChat(report)) { return ''; } - if (report.chatType === CONST.REPORT.CHAT_TYPE.DOMAIN_ALL) { + if (getChatType(report) === CONST.REPORT.CHAT_TYPE.DOMAIN_ALL) { // The domainAll rooms are just #domainName, so we ignore the prefix '#' to get the domainName return report.reportName.substring(1); } diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js index 6c13340a3986..0ba284a4112f 100755 --- a/src/pages/SearchPage.js +++ b/src/pages/SearchPage.js @@ -129,6 +129,7 @@ class SearchPage extends Component { this.state.searchValue.trim(), this.props.betas, ); + console.log(recentReports, personalDetails, userToInvite); this.setState({ userToInvite, recentReports, From 5c008b664baea71b464e18d789cab398f4555db9 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Thu, 8 Dec 2022 07:24:21 -1000 Subject: [PATCH 116/133] Use else if --- src/pages/ReimbursementAccount/CompanyStep.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js index 41cd4dc06b9d..10c2c6fdc021 100644 --- a/src/pages/ReimbursementAccount/CompanyStep.js +++ b/src/pages/ReimbursementAccount/CompanyStep.js @@ -101,9 +101,7 @@ class CompanyStep extends React.Component { if (!values.incorporationDate || !ValidationUtils.isValidDate(values.incorporationDate)) { errors.incorporationDate = this.props.translate('bankAccount.error.incorporationDate'); - } - - if (!values.incorporationDate || !ValidationUtils.isValidPastDate(values.incorporationDate)) { + } else if (!values.incorporationDate || !ValidationUtils.isValidPastDate(values.incorporationDate)) { errors.incorporationDate = this.props.translate('bankAccount.error.incorporationDateFuture'); } From eedccb16acd2540a1ca7e9772881905399a0b826 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Thu, 8 Dec 2022 18:51:28 +0100 Subject: [PATCH 117/133] Use SET in sendMoney to save the iouReport Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- src/libs/actions/IOU.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 0157dc590eff..dd8194584c9b 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -794,7 +794,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType }, }, { - onyxMethod: CONST.ONYX.METHOD.MERGE, + onyxMethod: CONST.ONYX.METHOD.SET, key: `${ONYXKEYS.COLLECTION.REPORT}${optimisticIOUReport.reportID}`, value: optimisticIOUReport, }, From 5634f96bb286d188e5d4f1c23194d9b5c3b146ab Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Thu, 8 Dec 2022 12:21:53 -0700 Subject: [PATCH 118/133] rm comment --- src/styles/colors.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/styles/colors.js b/src/styles/colors.js index df71ea96f426..39f9ab7e4acf 100644 --- a/src/styles/colors.js +++ b/src/styles/colors.js @@ -33,8 +33,6 @@ export default { greenDefaultButtonHover: '#2C6755', greenDefaultButtonPressed: '#467164', greenDefaultButtonDisabled: '#8BA69E', - - // Picker option text color, we set this to avoid white on white dropdowns in Windows midnight: '#002140', // DEPRECATED COLORS. Do not reference these colors. Will be deleted in color switch PR. From 46f8297c62f448180cfc79b8968f9383f1d9e12b Mon Sep 17 00:00:00 2001 From: Aldo Canepa Date: Thu, 8 Dec 2022 12:36:40 -0800 Subject: [PATCH 119/133] Uppercase PDF acronym following style guideline --- src/components/PDFView/index.js | 6 +++--- src/components/PDFView/index.native.js | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/PDFView/index.js b/src/components/PDFView/index.js index fcead57588d9..485b40c1e983 100644 --- a/src/components/PDFView/index.js +++ b/src/components/PDFView/index.js @@ -25,7 +25,7 @@ class PDFView extends Component { }; this.onDocumentLoadSuccess = this.onDocumentLoadSuccess.bind(this); this.initiatePasswordChallenge = this.initiatePasswordChallenge.bind(this); - this.attemptPdfLoad = this.attemptPdfLoad.bind(this); + this.attemptPDFLoad = this.attemptPDFLoad.bind(this); this.toggleKeyboardOnSmallScreens = this.toggleKeyboardOnSmallScreens.bind(this); } @@ -84,7 +84,7 @@ class PDFView extends Component { * * @param {String} password Password to send via callback to react-pdf */ - attemptPdfLoad(password) { + attemptPDFLoad(password) { this.onPasswordCallback(password); } @@ -150,7 +150,7 @@ class PDFView extends Component { {this.state.shouldRequestPassword && ( this.setState({isPasswordInvalid: false})} isPasswordInvalid={this.state.isPasswordInvalid} shouldAutofocusPasswordField={!this.props.isSmallScreenWidth} diff --git a/src/components/PDFView/index.native.js b/src/components/PDFView/index.native.js index bf2a632dc32e..46474eb73705 100644 --- a/src/components/PDFView/index.native.js +++ b/src/components/PDFView/index.native.js @@ -32,15 +32,15 @@ class PDFView extends Component { super(props); this.state = { shouldRequestPassword: false, - shouldAttemptPdfLoad: true, + shouldAttemptPDFLoad: true, shouldShowLoadingIndicator: true, isPasswordInvalid: false, failedToLoadPDF: false, password: '', }; this.initiatePasswordChallenge = this.initiatePasswordChallenge.bind(this); - this.attemptPdfLoadWithPassword = this.attemptPdfLoadWithPassword.bind(this); - this.finishPdfLoad = this.finishPdfLoad.bind(this); + this.attemptPDFLoadWithPassword = this.attemptPDFLoadWithPassword.bind(this); + this.finishPDFLoad = this.finishPDFLoad.bind(this); this.handleFailureToLoadPDF = this.handleFailureToLoadPDF.bind(this); } @@ -56,7 +56,7 @@ class PDFView extends Component { this.setState({ failedToLoadPDF: true, - shouldAttemptPdfLoad: false, + shouldAttemptPDFLoad: false, }); } @@ -74,7 +74,7 @@ class PDFView extends Component { // Render password form, and don't render PDF and loading indicator. this.setState({ shouldRequestPassword: true, - shouldAttemptPdfLoad: false, + shouldAttemptPDFLoad: false, }); // The message provided by react-native-pdf doesn't indicate whether this @@ -92,13 +92,13 @@ class PDFView extends Component { * * @param {String} password Password submitted via PDFPasswordForm */ - attemptPdfLoadWithPassword(password) { + attemptPDFLoadWithPassword(password) { // Render react-native-pdf/PDF so that it can validate the password. // Note that at this point in the password challenge, shouldRequestPassword is true. // Thus react-native-pdf/PDF will be rendered - but not visible. this.setState({ password, - shouldAttemptPdfLoad: true, + shouldAttemptPDFLoad: true, shouldShowLoadingIndicator: true, }); } @@ -107,7 +107,7 @@ class PDFView extends Component { * After the PDF is successfully loaded hide PDFPasswordForm and the loading * indicator. */ - finishPdfLoad() { + finishPDFLoad() { this.setState({ shouldRequestPassword: false, shouldShowLoadingIndicator: false, @@ -146,7 +146,7 @@ class PDFView extends Component { )} - {this.state.shouldAttemptPdfLoad && ( + {this.state.shouldAttemptPDFLoad && ( )} {this.state.shouldRequestPassword && ( this.setState({isPasswordInvalid: false})} isPasswordInvalid={this.state.isPasswordInvalid} shouldShowLoadingIndicator={this.state.shouldShowLoadingIndicator} From b059f0827f5e41db639d6212faa78e7845798e0c Mon Sep 17 00:00:00 2001 From: miroslav Date: Thu, 8 Dec 2022 23:08:37 +0100 Subject: [PATCH 120/133] fix "Upload photo" popup menu not hiding --- src/components/AttachmentPicker/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/AttachmentPicker/index.js b/src/components/AttachmentPicker/index.js index 25191883f709..384505a0cfbe 100644 --- a/src/components/AttachmentPicker/index.js +++ b/src/components/AttachmentPicker/index.js @@ -41,6 +41,9 @@ class AttachmentPicker extends React.Component { // Cleanup after selecting a file to start from a fresh state this.fileInput.value = null; }} + + // Prevent parent's onclick event from firing + onClick={e => e.stopPropagation()} accept={getAcceptableFileTypes(this.props.type)} /> {this.props.children({ From ada0df2415c46c74a1d57e4f9cc00ec6721861ac Mon Sep 17 00:00:00 2001 From: Hans Date: Tue, 6 Dec 2022 10:58:26 +0700 Subject: [PATCH 121/133] make image refreshable From fee05c8333bd9de07d5c5ce0f85f15bf851000c9 Mon Sep 17 00:00:00 2001 From: miroslav Date: Fri, 9 Dec 2022 05:54:46 +0100 Subject: [PATCH 122/133] update comment for stopPropagation in file input --- src/components/AttachmentPicker/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/AttachmentPicker/index.js b/src/components/AttachmentPicker/index.js index 384505a0cfbe..082853285bc4 100644 --- a/src/components/AttachmentPicker/index.js +++ b/src/components/AttachmentPicker/index.js @@ -42,7 +42,8 @@ class AttachmentPicker extends React.Component { this.fileInput.value = null; }} - // Prevent parent's onclick event from firing + // We are stopping the event propagation because triggering the `click()` on the hidden input + // causes the event to unexpectedly bubble up to anything wrapping this component e.g. Pressable onClick={e => e.stopPropagation()} accept={getAcceptableFileTypes(this.props.type)} /> From ec4bcb8043d3616a034ece8520863d17312daa64 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 9 Dec 2022 05:17:51 +0000 Subject: [PATCH 123/133] Update version to 1.2.37-1 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index e786e27a7136..1bae507f51d3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -156,8 +156,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001023700 - versionName "1.2.37-0" + versionCode 1001023701 + versionName "1.2.37-1" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 5b955cd7e739..a1b84fed17a1 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.37.0 + 1.2.37.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index a65379f25781..44cb1b6af9b7 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.2.37.0 + 1.2.37.1 diff --git a/package-lock.json b/package-lock.json index e7c7570c679c..9e22793766ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.2.37-0", + "version": "1.2.37-1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.2.37-0", + "version": "1.2.37-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 55f8b2b27283..400c52db75aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.2.37-0", + "version": "1.2.37-1", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From 3b32ee5619d25a7a68e594bf25187c086dbe3e30 Mon Sep 17 00:00:00 2001 From: b1tjoy <103875612+b1tjoy@users.noreply.github.com> Date: Fri, 9 Dec 2022 23:49:03 +0800 Subject: [PATCH 124/133] add comment for empty catch --- src/libs/Clipboard/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/Clipboard/index.js b/src/libs/Clipboard/index.js index fb3e6654e413..b45099e89e8f 100644 --- a/src/libs/Clipboard/index.js +++ b/src/libs/Clipboard/index.js @@ -36,6 +36,9 @@ function setHTMLSync(html, text) { try { document.execCommand('copy'); + + // The 'copy' command can throw a SecurityError exception. + // See https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#the-copy-command for more details. // eslint-disable-next-line no-empty } catch (e) {} From e3aa181051508bb12a1fd85371ac9931b5208d52 Mon Sep 17 00:00:00 2001 From: Alberto Date: Fri, 9 Dec 2022 17:18:31 +0100 Subject: [PATCH 125/133] Remove extra flex from style --- src/styles/styles.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/styles/styles.js b/src/styles/styles.js index 9a2b6eed5439..baac1d8f3386 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -2486,7 +2486,6 @@ const styles = { dotIndicatorMessage: { display: 'flex', - flex: 1, flexDirection: 'row', alignItems: 'center', }, From 941158ab81e65539ca24c8d53fa218de4ae6fc08 Mon Sep 17 00:00:00 2001 From: Daraksha Date: Fri, 9 Dec 2022 22:06:10 +0530 Subject: [PATCH 126/133] add spanish and english copy for currency --- src/languages/en.js | 1 + src/languages/es.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/languages/en.js b/src/languages/en.js index d8c2a0c4e208..3a5fe7046ae4 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -110,6 +110,7 @@ export default { thisFeatureRequiresInternet: 'This feature requires an active internet connection to be used.', areYouSure: 'Are you sure?', zipCodeExample: 'e.g. 12345, 12345-1234, 12345 1234', + currency: 'Currency', }, attachmentPicker: { cameraPermissionRequired: 'Camera permission required', diff --git a/src/languages/es.js b/src/languages/es.js index e794243eb431..13dc2964dd29 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -110,6 +110,7 @@ export default { thisFeatureRequiresInternet: 'Esta función requiere una conexión a Internet activa para ser utilizada.', areYouSure: '¿Estás seguro?', zipCodeExample: 'p. ej. 12345, 12345-1234, 12345 1234', + currency: 'Moneda', }, attachmentPicker: { cameraPermissionRequired: 'Se necesita permiso para usar la cámara', From 153a5908f73c7cae956a239e88a7b559ea22a349 Mon Sep 17 00:00:00 2001 From: Daraksha Date: Fri, 9 Dec 2022 22:09:18 +0530 Subject: [PATCH 127/133] add tooltip for currency picker --- src/components/CurrencySymbolButton.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/components/CurrencySymbolButton.js b/src/components/CurrencySymbolButton.js index 85a6ad8e4083..545c0721ceb5 100644 --- a/src/components/CurrencySymbolButton.js +++ b/src/components/CurrencySymbolButton.js @@ -3,6 +3,8 @@ import {TouchableOpacity} from 'react-native'; import PropTypes from 'prop-types'; import Text from './Text'; import styles from '../styles/styles'; +import Tooltip from './Tooltip'; +import withLocalize, {withLocalizePropTypes} from './withLocalize'; const propTypes = { /** Currency symbol of selected currency */ @@ -10,17 +12,21 @@ const propTypes = { /** Function to call when currency button is pressed */ onCurrencyButtonPress: PropTypes.func.isRequired, + + ...withLocalizePropTypes, }; function CurrencySymbolButton(props) { return ( - - {props.currencySymbol} - + + + {props.currencySymbol} + + ); } CurrencySymbolButton.propTypes = propTypes; CurrencySymbolButton.displayName = 'CurrencySymbolButton'; -export default CurrencySymbolButton; +export default withLocalize(CurrencySymbolButton); From 546d8de71596af1f9325e27c6227e7bd8268634a Mon Sep 17 00:00:00 2001 From: Daraksha Date: Fri, 9 Dec 2022 23:13:03 +0530 Subject: [PATCH 128/133] use existing copy --- src/components/CurrencySymbolButton.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CurrencySymbolButton.js b/src/components/CurrencySymbolButton.js index 545c0721ceb5..8b73cabc1b23 100644 --- a/src/components/CurrencySymbolButton.js +++ b/src/components/CurrencySymbolButton.js @@ -18,7 +18,7 @@ const propTypes = { function CurrencySymbolButton(props) { return ( - + {props.currencySymbol} From e1ea2d54278e8c083e7b9b2331a271e90e6fd34a Mon Sep 17 00:00:00 2001 From: Daraksha Date: Fri, 9 Dec 2022 23:14:09 +0530 Subject: [PATCH 129/133] remove unused copy --- src/languages/en.js | 1 - src/languages/es.js | 1 - 2 files changed, 2 deletions(-) diff --git a/src/languages/en.js b/src/languages/en.js index 3a5fe7046ae4..d8c2a0c4e208 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -110,7 +110,6 @@ export default { thisFeatureRequiresInternet: 'This feature requires an active internet connection to be used.', areYouSure: 'Are you sure?', zipCodeExample: 'e.g. 12345, 12345-1234, 12345 1234', - currency: 'Currency', }, attachmentPicker: { cameraPermissionRequired: 'Camera permission required', diff --git a/src/languages/es.js b/src/languages/es.js index 13dc2964dd29..e794243eb431 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -110,7 +110,6 @@ export default { thisFeatureRequiresInternet: 'Esta función requiere una conexión a Internet activa para ser utilizada.', areYouSure: '¿Estás seguro?', zipCodeExample: 'p. ej. 12345, 12345-1234, 12345 1234', - currency: 'Moneda', }, attachmentPicker: { cameraPermissionRequired: 'Se necesita permiso para usar la cámara', From ecb60196794be5acbe835f22f45e5c74c77461b6 Mon Sep 17 00:00:00 2001 From: Francois Laithier Date: Fri, 9 Dec 2022 12:43:43 -0800 Subject: [PATCH 130/133] Revert "fix composer hidden while loading messages" --- src/pages/home/ReportScreen.js | 20 ++++---------------- src/pages/home/report/ReportActionCompose.js | 17 +++++++---------- src/pages/home/report/ReportFooter.js | 16 ++++------------ 3 files changed, 15 insertions(+), 38 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 4707a71e396b..eb55a8996e08 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -236,13 +236,7 @@ class ReportScreen extends React.Component { placeholder={( <> - - - - + )} > @@ -318,15 +312,9 @@ class ReportScreen extends React.Component { {/* Note: The report should be allowed to mount even if the initial report actions are not loaded. If we prevent rendering the report while they are loading then we'll unnecessarily unmount the ReportActionsView which will clear the new marker lines initial state. */} {(!this.isReportReadyForDisplay() || isLoadingInitialReportActions) && ( - <> - - - + )} diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index e07b1880d514..7811d1c25ee1 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -88,10 +88,7 @@ const propTypes = { isFocused: PropTypes.bool.isRequired, /** Is the composer full size */ - isComposerFullSize: PropTypes.bool, - - /** Whether user interactions should be disabled */ - disabled: PropTypes.bool, + isComposerFullSize: PropTypes.bool.isRequired, // The NVP describing a user's block status blockedFromConcierge: PropTypes.shape({ @@ -575,7 +572,7 @@ class ReportActionCompose extends React.Component { onMouseDown={e => e.preventDefault()} style={styles.composerSizeButton} underlayColor={themeColors.componentBG} - disabled={isBlockedFromConcierge || this.props.disabled} + disabled={isBlockedFromConcierge} > @@ -594,7 +591,7 @@ class ReportActionCompose extends React.Component { onMouseDown={e => e.preventDefault()} style={styles.composerSizeButton} underlayColor={themeColors.componentBG} - disabled={isBlockedFromConcierge || this.props.disabled} + disabled={isBlockedFromConcierge} > @@ -612,7 +609,7 @@ class ReportActionCompose extends React.Component { }} style={styles.chatItemAttachButton} underlayColor={themeColors.componentBG} - disabled={isBlockedFromConcierge || this.props.disabled} + disabled={isBlockedFromConcierge} > @@ -675,7 +672,7 @@ class ReportActionCompose extends React.Component { onPasteFile={displayFileInModal} shouldClear={this.state.textInputShouldClear} onClear={() => this.setTextInputShouldClear(false)} - isDisabled={isComposeDisabled || isBlockedFromConcierge || this.props.disabled} + isDisabled={isComposeDisabled || isBlockedFromConcierge} selection={this.state.selection} onSelectionChange={this.onSelectionChange} isFullComposerAvailable={this.state.isFullComposerAvailable} @@ -690,7 +687,7 @@ class ReportActionCompose extends React.Component { {canUseTouchScreen() && this.props.isMediumScreenWidth ? null : ( this.focus(true)} onEmojiSelected={this.addEmojiToTextBox} /> @@ -707,7 +704,7 @@ class ReportActionCompose extends React.Component { // Keep focus on the composer when Send message is clicked. // eslint-disable-next-line react/jsx-props-no-multi-spaces onMouseDown={e => e.preventDefault()} - disabled={this.state.isCommentEmpty || isBlockedFromConcierge || this.props.disabled || hasExceededMaxCommentLength} + disabled={this.state.isCommentEmpty || isBlockedFromConcierge || hasExceededMaxCommentLength} hitSlop={{ top: 3, right: 3, bottom: 3, left: 3, }} diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index 3aa2feff5f80..7c3a4191b390 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -21,16 +21,16 @@ import reportPropTypes from '../../reportPropTypes'; const propTypes = { /** Report object for the current report */ - report: reportPropTypes, + report: reportPropTypes.isRequired, /** Report actions for the current report */ - reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)).isRequired, /** Offline status */ isOffline: PropTypes.bool.isRequired, /** Callback fired when the comment is submitted */ - onSubmitComment: PropTypes.func, + onSubmitComment: PropTypes.func.isRequired, /** Any errors associated with an attempt to create a chat */ // eslint-disable-next-line react/forbid-prop-types @@ -42,20 +42,13 @@ const propTypes = { /** Whether the composer input should be shown */ shouldShowComposeInput: PropTypes.bool, - /** Whether user interactions should be disabled */ - shouldDisableCompose: PropTypes.bool, - ...windowDimensionsPropTypes, }; const defaultProps = { - report: {reportID: '0'}, - reportActions: {}, - onSubmitComment: () => {}, + shouldShowComposeInput: true, errors: {}, pendingAction: null, - shouldShowComposeInput: true, - shouldDisableCompose: false, }; class ReportFooter extends React.Component { @@ -106,7 +99,6 @@ class ReportFooter extends React.Component { reportActions={this.props.reportActions} report={this.props.report} isComposerFullSize={this.props.isComposerFullSize} - disabled={this.props.shouldDisableCompose} /> From 57e2728dcf744e06ff69f4e4f6832bd92c09d501 Mon Sep 17 00:00:00 2001 From: b1tjoy <103875612+b1tjoy@users.noreply.github.com> Date: Sat, 10 Dec 2022 04:57:54 +0800 Subject: [PATCH 131/133] move comment inside catch block --- src/libs/Clipboard/index.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libs/Clipboard/index.js b/src/libs/Clipboard/index.js index b45099e89e8f..efffd9626e03 100644 --- a/src/libs/Clipboard/index.js +++ b/src/libs/Clipboard/index.js @@ -36,11 +36,10 @@ function setHTMLSync(html, text) { try { document.execCommand('copy'); - - // The 'copy' command can throw a SecurityError exception. + } catch (e) { + // The 'copy' command can throw a SecurityError exception, we ignore this exception on purpose. // See https://dvcs.w3.org/hg/editing/raw-file/tip/editing.html#the-copy-command for more details. - // eslint-disable-next-line no-empty - } catch (e) {} + } selection.removeAllRanges(); document.body.removeChild(node); From a9b7f265398a119b583111932e1d321283241b46 Mon Sep 17 00:00:00 2001 From: OSBotify Date: Fri, 9 Dec 2022 22:49:37 +0000 Subject: [PATCH 132/133] Update version to 1.2.37-2 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 2 +- ios/NewExpensifyTests/Info.plist | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 1bae507f51d3..9d2e43f4a3f2 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -156,8 +156,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001023701 - versionName "1.2.37-1" + versionCode 1001023702 + versionName "1.2.37-2" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index a1b84fed17a1..99a8e1deb4b0 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.37.1 + 1.2.37.2 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 44cb1b6af9b7..a048ac1f7d92 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.2.37.1 + 1.2.37.2 diff --git a/package-lock.json b/package-lock.json index 9e22793766ff..8a33809dadc7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.2.37-1", + "version": "1.2.37-2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.2.37-1", + "version": "1.2.37-2", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 400c52db75aa..4e3a3b6799c3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.2.37-1", + "version": "1.2.37-2", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", From c3300b747b3adea2b28d2ecf8d9cb1ab40381c5d Mon Sep 17 00:00:00 2001 From: OSBotify Date: Sat, 10 Dec 2022 00:19:30 +0000 Subject: [PATCH 133/133] Update version to 1.2.38-0 --- android/app/build.gradle | 4 ++-- ios/NewExpensify/Info.plist | 4 ++-- ios/NewExpensifyTests/Info.plist | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 9d2e43f4a3f2..f0b68a3e6348 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -156,8 +156,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001023702 - versionName "1.2.37-2" + versionCode 1001023800 + versionName "1.2.38-0" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 99a8e1deb4b0..3a5d89e05004 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.37 + 1.2.38 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.37.2 + 1.2.38.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index a048ac1f7d92..52e471af78b7 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.2.37 + 1.2.38 CFBundleSignature ???? CFBundleVersion - 1.2.37.2 + 1.2.38.0 diff --git a/package-lock.json b/package-lock.json index 8a33809dadc7..f0f878afd2f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.2.37-2", + "version": "1.2.38-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.2.37-2", + "version": "1.2.38-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 4e3a3b6799c3..d95af9e60f70 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.2.37-2", + "version": "1.2.38-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",