From 2dda81f0d0281b3912818891bc4d72ce7e0c2a07 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Wed, 29 Mar 2023 12:03:36 +0000 Subject: [PATCH 01/25] Migrate the new modal props / HOC --- src/pages/iou/MoneyRequestModal.js | 167 +++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 src/pages/iou/MoneyRequestModal.js diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js new file mode 100644 index 000000000000..ea072dbf54a7 --- /dev/null +++ b/src/pages/iou/MoneyRequestModal.js @@ -0,0 +1,167 @@ +import _ from 'underscore'; +import React, {useState, useEffect} from 'react'; +import {View, TouchableOpacity} from 'react-native'; +import PropTypes from 'prop-types'; +import lodashGet from 'lodash/get'; +import {withOnyx} from 'react-native-onyx'; +import Str from 'expensify-common/lib/str'; +import IOUAmountPage from './steps/IOUAmountPage'; +import IOUParticipantsPage from './steps/IOUParticipantsPage/IOUParticipantsPage'; +import IOUConfirmPage from './steps/IOUConfirmPage'; +import Header from '../../components/Header'; +import styles from '../../styles/styles'; +import Icon from '../../components/Icon'; +import * as IOU from '../../libs/actions/IOU'; +import * as Expensicons from '../../components/Icon/Expensicons'; +import Navigation from '../../libs/Navigation/Navigation'; +import ONYXKEYS from '../../ONYXKEYS'; +import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; +import compose from '../../libs/compose'; +import * as OptionsListUtils from '../../libs/OptionsListUtils'; +import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; +import AnimatedStep from '../../components/AnimatedStep'; +import ScreenWrapper from '../../components/ScreenWrapper'; +import Tooltip from '../../components/Tooltip'; +import CONST from '../../CONST'; +import * as PersonalDetails from '../../libs/actions/PersonalDetails'; +import withCurrentUserPersonalDetails from '../../components/withCurrentUserPersonalDetails'; +import networkPropTypes from '../../components/networkPropTypes'; +import {withNetwork} from '../../components/OnyxProvider'; +import reportPropTypes from '../reportPropTypes'; +import * as ReportUtils from '../../libs/ReportUtils'; +import * as ReportScrollManager from '../../libs/ReportScrollManager'; + +/** + * IOU modal for requesting money and splitting bills. + */ +const propTypes = { + /** Whether the IOU is for a single request or a group bill split */ + hasMultipleParticipants: PropTypes.bool, + + /** The type of IOU report, i.e. bill, request, send */ + iouType: PropTypes.string, + + /** The report passed via the route */ + // eslint-disable-next-line react/no-unused-prop-types + report: reportPropTypes, + + /** Information about the network */ + network: networkPropTypes.isRequired, + + // Holds data related to IOU view state, rather than the underlying IOU data. + iou: PropTypes.shape({ + /** Whether or not transaction creation has started */ + creatingIOUTransaction: PropTypes.bool, + + /** Whether or not transaction creation has resulted to error */ + error: PropTypes.bool, + + // Selected Currency Code of the current IOU + selectedCurrencyCode: PropTypes.string, + }), + + /** Personal details of all the users */ + personalDetails: PropTypes.shape({ + /** Primary login of participant */ + login: PropTypes.string, + + /** Display Name of participant */ + displayName: PropTypes.string, + + /** Avatar url of participant */ + avatar: PropTypes.string, + }), + + /** Personal details of the current user */ + currentUserPersonalDetails: PropTypes.shape({ + // Local Currency Code of the current user + localCurrencyCode: PropTypes.string, + }), + + ...withLocalizePropTypes, +}; + +const defaultProps = { + hasMultipleParticipants: false, + report: { + participants: [], + }, + iouType: CONST.IOU.IOU_TYPE.REQUEST, + currentUserPersonalDetails: { + localCurrencyCode: CONST.CURRENCY.USD, + }, + personalDetails: {}, + iou: { + creatingIOUTransaction: false, + error: false, + selectedCurrencyCode: null, + }, +}; + +// Determines type of step to display within Modal, value provides the title for that page. +const Steps = { + IOUAmount: 'iou.amount', + IOUParticipants: 'iou.participants', + IOUConfirm: 'iou.confirm', +}; + +const MoneyRequestModal = (props) => { + const [previousStepIndex, setPreviousStepIndex] = useState(0); + const [currentStepIndex, setCurrentStepIndex] = useState(0); + + const reportParticipants = lodashGet(props, 'report.participants', []); + const participantsWithDetails = _.map(OptionsListUtils.getPersonalDetailsForLogins(reportParticipants, props.personalDetails), personalDetails => ({ + login: personalDetails.login, + text: personalDetails.displayName, + firstName: lodashGet(personalDetails, 'firstName', ''), + lastName: lodashGet(personalDetails, 'lastName', ''), + alternateText: Str.isSMSLogin(personalDetails.login) ? Str.removeSMSDomain(personalDetails.login) : personalDetails.login, + icons: [{ + source: ReportUtils.getAvatar(personalDetails.avatar, personalDetails.login), + name: personalDetails.login, + type: CONST.ICON_TYPE_AVATAR, + }], + keyForList: personalDetails.login, + payPalMeAddress: lodashGet(personalDetails, 'payPalMeAddress', ''), + phoneNumber: lodashGet(personalDetails, 'phoneNumber', ''), + })); + const [participants, setParticipants] = useState(participantsWithDetails); + const [amount, setAmount] = useState(''); + const [comment, setComment] = useState(''); + + useEffect(() => { + PersonalDetails.openIOUModalPage(); + IOU.setIOUSelectedCurrency(props.currentUserPersonalDetails.localCurrencyCode); + }, []); + + useEffect(() => { + + }); + + return ( +
+

Money Request Modal

+
+ ); +} + +MoneyRequestModal.displayName = 'MoneyRequestModal'; +MoneyRequestModal.propTypes = propTypes; +MoneyRequestModal.defaultProps = defaultProps; + +export default compose( + withLocalize, + withNetwork(), + withCurrentUserPersonalDetails, + withOnyx({ + report: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID', '')}`, + }, + iou: { + key: ONYXKEYS.IOU, + }, + personalDetails: { + key: ONYXKEYS.PERSONAL_DETAILS, + }, + }), +)(MoneyRequestModal); From 6408554e10ed2fedccc01c1d34d42252eed1b039 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Wed, 29 Mar 2023 16:41:05 +0000 Subject: [PATCH 02/25] add the class functions --- src/pages/iou/MoneyRequestModal.js | 172 ++++++++++++++++++++++++++++- 1 file changed, 171 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index ea072dbf54a7..6399abe57a6f 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -138,12 +138,182 @@ const MoneyRequestModal = (props) => { }); + /** + * Decides our animation type based on whether we're increasing or decreasing + * our step index. + * @returns {String} + */ + function getDirection() { + if (previousStepIndex < currentStepIndex) { + return 'in'; + } + if (previousStepIndex > currentStepIndex) { + return 'out'; + } + + // Doesn't animate the step when first opening the modal + if (previousStepIndex === currentStepIndex) { + return null; + } + } + + /** + * Retrieve title for current step, based upon current step and type of IOU + * + * @returns {String} + */ + function getTitleForStep() { + const currentStepIndex = currentStepIndex; + const isSendingMoney = props.iouType === CONST.IOU.IOU_TYPE.SEND; + if (currentStepIndex === 1 || currentStepIndex === 2) { + const formattedAmount = props.numberFormat( + amount, { + style: 'currency', + currency: props.iou.selectedCurrencyCode, + }, + ); + if (isSendingMoney) { + return props.translate('iou.send', { + amount: formattedAmount, + }); + } + return props.translate( + props.hasMultipleParticipants ? 'iou.split' : 'iou.request', { + amount: formattedAmount, + }, + ); + } + if (currentStepIndex === 0) { + if (isSendingMoney) { + return props.translate('iou.sendMoney'); + } + return props.translate(props.hasMultipleParticipants ? 'iou.splitBill' : 'iou.requestMoney'); + } + + return props.translate(this.steps[currentStepIndex]) || ''; + } + + /** + * Navigate to the next IOU step if possible + */ + function navigateToPreviousStep() { + if (currentStepIndex <= 0) { + return; + } + + setPreviousStepIndex(currentStepIndex); + setCurrentStepIndex(currentStepIndex - 1); + } + + /** + * Navigate to the previous IOU step if possible + */ + function navigateToNextStep() { + if (currentStepIndex >= this.steps.length - 1) { + return; + } + + setPreviousStepIndex(currentStepIndex); + setCurrentStepIndex(currentStepIndex + 1); + } + + /** + * Checks if user has a GOLD wallet then creates a paid IOU report on the fly + * + * @param {String} paymentMethodType + */ + function sendMoney(paymentMethodType) { + const formattedAmount = Math.round(amount * 100); + const currency = props.iou.selectedCurrencyCode; + const trimmedComment = comment.trim(); + const participant = participants[0]; + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { + IOU.sendMoneyElsewhere( + props.report, + formattedAmount, + currency, + trimmedComment, + props.currentUserPersonalDetails.login, + participant, + ); + return; + } + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { + IOU.sendMoneyViaPaypal( + props.report, + formattedAmount, + currency, + trimmedComment, + props.currentUserPersonalDetails.login, + participant, + ); + return; + } + + if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { + IOU.sendMoneyWithWallet( + props.report, + formattedAmount, + currency, + trimmedComment, + props.currentUserPersonalDetails.login, + participant, + ); + } + } + + /** + * @param {Array} selectedParticipants + */ + function createTransaction(selectedParticipants) { + const reportID = lodashGet(props, 'route.params.reportID', ''); + const trimmedComment = comment.trim(); + + // IOUs created from a group report will have a reportID param in the route. + // Since the user is already viewing the report, we don't need to navigate them to the report + if (props.hasMultipleParticipants && CONST.REGEX.NUMBER.test(reportID)) { + IOU.splitBill( + selectedParticipants, + props.currentUserPersonalDetails.login, + amount, + trimmedComment, + props.iou.selectedCurrencyCode, + props.preferredLocale, + reportID, + ); + return; + } + + // If the IOU is created from the global create menu, we also navigate the user to the group report + if (props.hasMultipleParticipants) { + IOU.splitBillAndOpenReport( + selectedParticipants, + props.currentUserPersonalDetails.login, + amount, + trimmedComment, + props.iou.selectedCurrencyCode, + props.preferredLocale, + ); + return; + } + IOU.requestMoney( + props.report, + Math.round(amount * 100), + props.iou.selectedCurrencyCode, + props.currentUserPersonalDetails.login, + selectedParticipants[0], + trimmedComment, + ); + } + return (

Money Request Modal

); -} +}; MoneyRequestModal.displayName = 'MoneyRequestModal'; MoneyRequestModal.propTypes = propTypes; From 4cf8420ce0889e8359f410141d38d5955ac127dd Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Wed, 29 Mar 2023 16:53:50 +0000 Subject: [PATCH 03/25] migrate this.step --- src/pages/iou/MoneyRequestModal.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 6399abe57a6f..87fce50162e8 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -106,9 +106,6 @@ const Steps = { }; const MoneyRequestModal = (props) => { - const [previousStepIndex, setPreviousStepIndex] = useState(0); - const [currentStepIndex, setCurrentStepIndex] = useState(0); - const reportParticipants = lodashGet(props, 'report.participants', []); const participantsWithDetails = _.map(OptionsListUtils.getPersonalDetailsForLogins(reportParticipants, props.personalDetails), personalDetails => ({ login: personalDetails.login, @@ -125,6 +122,12 @@ const MoneyRequestModal = (props) => { payPalMeAddress: lodashGet(personalDetails, 'payPalMeAddress', ''), phoneNumber: lodashGet(personalDetails, 'phoneNumber', ''), })); + + // Skip IOUParticipants step if participants are passed in + const steps = reportParticipants.length ? [Steps.IOUAmount, Steps.IOUConfirm] : [Steps.IOUAmount, Steps.IOUParticipants, Steps.IOUConfirm]; + + const [previousStepIndex, setPreviousStepIndex] = useState(0); + const [currentStepIndex, setCurrentStepIndex] = useState(0); const [participants, setParticipants] = useState(participantsWithDetails); const [amount, setAmount] = useState(''); const [comment, setComment] = useState(''); @@ -190,7 +193,7 @@ const MoneyRequestModal = (props) => { return props.translate(props.hasMultipleParticipants ? 'iou.splitBill' : 'iou.requestMoney'); } - return props.translate(this.steps[currentStepIndex]) || ''; + return props.translate(steps[currentStepIndex]) || ''; } /** @@ -209,7 +212,7 @@ const MoneyRequestModal = (props) => { * Navigate to the previous IOU step if possible */ function navigateToNextStep() { - if (currentStepIndex >= this.steps.length - 1) { + if (currentStepIndex >= steps.length - 1) { return; } @@ -223,7 +226,7 @@ const MoneyRequestModal = (props) => { * @param {String} paymentMethodType */ function sendMoney(paymentMethodType) { - const formattedAmount = Math.round(amount * 100); + const amountInDollars = Math.round(amount * 100); const currency = props.iou.selectedCurrencyCode; const trimmedComment = comment.trim(); const participant = participants[0]; @@ -231,7 +234,7 @@ const MoneyRequestModal = (props) => { if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.ELSEWHERE) { IOU.sendMoneyElsewhere( props.report, - formattedAmount, + amountInDollars, currency, trimmedComment, props.currentUserPersonalDetails.login, @@ -243,7 +246,7 @@ const MoneyRequestModal = (props) => { if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { IOU.sendMoneyViaPaypal( props.report, - formattedAmount, + amountInDollars, currency, trimmedComment, props.currentUserPersonalDetails.login, @@ -255,7 +258,7 @@ const MoneyRequestModal = (props) => { if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { IOU.sendMoneyWithWallet( props.report, - formattedAmount, + amountInDollars, currency, trimmedComment, props.currentUserPersonalDetails.login, From 3b228b358bb954338ebfc5be3d9f800d1a1cdfc0 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Thu, 30 Mar 2023 10:32:21 +0000 Subject: [PATCH 04/25] add refs for previous values --- src/pages/iou/MoneyRequestModal.js | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 87fce50162e8..74796ada7f93 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -1,5 +1,5 @@ import _ from 'underscore'; -import React, {useState, useEffect} from 'react'; +import React, {useState, useEffect, useRef} from 'react'; import {View, TouchableOpacity} from 'react-native'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; @@ -126,6 +126,9 @@ const MoneyRequestModal = (props) => { // Skip IOUParticipants step if participants are passed in const steps = reportParticipants.length ? [Steps.IOUAmount, Steps.IOUConfirm] : [Steps.IOUAmount, Steps.IOUParticipants, Steps.IOUConfirm]; + const prevCreatingIOUTransactionStatusRef = useRef(); + const prevNetworkStatusRef = useRef(); + const [previousStepIndex, setPreviousStepIndex] = useState(0); const [currentStepIndex, setCurrentStepIndex] = useState(0); const [participants, setParticipants] = useState(participantsWithDetails); @@ -138,6 +141,31 @@ const MoneyRequestModal = (props) => { }, []); useEffect(() => { + prevCreatingIOUTransactionStatusRef.current = lodashGet(props, 'iou.creatingIOUTransaction'); + }, [props.iou]); + + useEffect(() => { + prevNetworkStatusRef.current = props.network.isOffline; + }, [props.network.isOffline]); + + + useEffect(() => { + const wasCreatingIOUTransaction = prevCreatingIOUTransactionStatusRef.current; + const isCurrentlyCreatingIOUTransaction = lodashGet(props, 'iou.creatingIOUTransaction'); + const iouError = lodashGet(props, 'iou.error'); + + // User came back online, so we can try to create the IOU transaction again + if (prevNetworkStatusRef.current && !props.network.isOffline) { + PersonalDetails.openIOUModalPage(); + } + + // We successfully created the IOU transaction, so we can dismiss the modal + if (wasCreatingIOUTransaction && !lodashGet(props, 'iou.creatingIOUTransaction') && !iouError) { + Navigation.dismissModal(); + } + + // We failed to create the IOU transaction, so we can show the error modal + if (wasCreatingIOUTransaction && !lodashGet(props, 'iou.creatingIOUTransaction') && iouError) { }); From 6f1af21295ea94379949e48eb2e67976ed0ebe1e Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Thu, 30 Mar 2023 11:41:40 +0000 Subject: [PATCH 05/25] refactor the useEffect --- src/pages/iou/MoneyRequestModal.js | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 74796ada7f93..aa06cace3af5 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -128,6 +128,7 @@ const MoneyRequestModal = (props) => { const prevCreatingIOUTransactionStatusRef = useRef(); const prevNetworkStatusRef = useRef(); + const prevSelectedCurrencyCodeRef = useRef(); const [previousStepIndex, setPreviousStepIndex] = useState(0); const [currentStepIndex, setCurrentStepIndex] = useState(0); @@ -148,26 +149,34 @@ const MoneyRequestModal = (props) => { prevNetworkStatusRef.current = props.network.isOffline; }, [props.network.isOffline]); + useEffect(() => { + prevSelectedCurrencyCodeRef.current = lodashGet(props, 'iou.selectedCurrencyCode'); + }, [props.iou.selectedCurrencyCode]); useEffect(() => { - const wasCreatingIOUTransaction = prevCreatingIOUTransactionStatusRef.current; - const isCurrentlyCreatingIOUTransaction = lodashGet(props, 'iou.creatingIOUTransaction'); - const iouError = lodashGet(props, 'iou.error'); + const isDoneCreatingIOUTransaction = prevCreatingIOUTransactionStatusRef.current && !lodashGet(props, 'iou.creatingIOUTransaction'); // User came back online, so we can try to create the IOU transaction again if (prevNetworkStatusRef.current && !props.network.isOffline) { PersonalDetails.openIOUModalPage(); } - // We successfully created the IOU transaction, so we can dismiss the modal - if (wasCreatingIOUTransaction && !lodashGet(props, 'iou.creatingIOUTransaction') && !iouError) { - Navigation.dismissModal(); + const selectedCurrencyCode = lodashGet(props, 'iou.selectedCurrencyCode'); + if (prevSelectedCurrencyCodeRef.current !== selectedCurrencyCode) { + IOU.setIOUSelectedCurrency(selectedCurrencyCode); } - // We failed to create the IOU transaction, so we can show the error modal - if (wasCreatingIOUTransaction && !lodashGet(props, 'iou.creatingIOUTransaction') && iouError) { + if (!isDoneCreatingIOUTransaction) { + return; + } - }); + // At this point, we're done creating the IOU transaction, but we need to check if it was successful + if (lodashGet(props, 'iou.error') === true) { + setCurrentStepIndex(0); + } else { + Navigation.dismissModal(); + } + }, [props.iou, props.network.isOffline]); /** * Decides our animation type based on whether we're increasing or decreasing From 1d5d5bcae2f1ad28d1d72ebdfe29c313eb6242fa Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Fri, 31 Mar 2023 17:15:17 +0000 Subject: [PATCH 06/25] add seperate component for header --- src/pages/iou/MoneyRequestHeader.js | 104 ++++++++++++++++++++++++++++ src/pages/iou/MoneyRequestModal.js | 99 ++++++++++++++++++++++++-- 2 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 src/pages/iou/MoneyRequestHeader.js diff --git a/src/pages/iou/MoneyRequestHeader.js b/src/pages/iou/MoneyRequestHeader.js new file mode 100644 index 000000000000..6ac1381ccfbd --- /dev/null +++ b/src/pages/iou/MoneyRequestHeader.js @@ -0,0 +1,104 @@ +import _ from 'underscore'; +import React from 'react'; +import {View, TouchableOpacity} from 'react-native'; +import PropTypes from 'prop-types'; +import Header from '../../components/Header'; +import styles from '../../styles/styles'; +import Icon from '../../components/Icon'; +import * as Expensicons from '../../components/Icon/Expensicons'; +import Navigation from '../../libs/Navigation/Navigation'; +import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; +import Tooltip from '../../components/Tooltip'; +import CONST from '../../CONST'; + +const propTypes = { + currentStepIndex: PropTypes.number.isRequired, + iouType: PropTypes.oneOf([CONST.IOU.IOU_TYPE.SEND, CONST.IOU.IOU_TYPE.REQUEST]).isRequired, + hasMultipleParticipants: PropTypes.bool.isRequired, + amount: PropTypes.string.isRequired, + navigateToPreviousStep: PropTypes.func.isRequired, + steps: PropTypes.array.isRequired, + ...withLocalizePropTypes, +} + +const MoneyRequestHeader = (props) => { + /** + * Retrieve title for current step, based upon current step and type of IOU + * + * @returns {String} + */ + function getTitleForStep() { + const isSendingMoney = props.iouType === CONST.IOU.IOU_TYPE.SEND; + if (props.currentStepIndex === 1 || props.currentStepIndex === 2) { + const formattedAmount = props.numberFormat( + props.amount, { + style: 'currency', + currency: props.iou.selectedCurrencyCode, + }, + ); + if (isSendingMoney) { + return props.translate('iou.send', { + amount: formattedAmount, + }); + } + return props.translate( + props.hasMultipleParticipants ? 'iou.split' : 'iou.request', { + amount: formattedAmount, + }, + ); + } + if (props.currentStepIndex === 0) { + if (isSendingMoney) { + return props.translate('iou.sendMoney'); + } + return props.translate(props.hasMultipleParticipants ? 'iou.splitBill' : 'iou.requestMoney'); + } + + return props.translate(props.steps[props.currentStepIndex]) || ''; + } + + return ( + + + {props.currentStepIndex > 0 + && ( + + + + + + + + )} +
+ + + Navigation.dismissModal()} + style={[styles.touchableButtonImage]} + accessibilityRole="button" + accessibilityLabel={props.translate('common.close')} + > + + + + + + + ); +} + +MoneyRequestHeader.displayName = 'MoneyRequestHeader'; +MoneyRequestHeader.propTypes = propTypes; +export default withLocalize(MoneyRequestHeader); diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index aa06cace3af5..b41849a02c6f 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -30,6 +30,7 @@ import {withNetwork} from '../../components/OnyxProvider'; import reportPropTypes from '../reportPropTypes'; import * as ReportUtils from '../../libs/ReportUtils'; import * as ReportScrollManager from '../../libs/ReportScrollManager'; +import MoneyRequestHeader from './MoneyRequestHeader'; /** * IOU modal for requesting money and splitting bills. @@ -203,7 +204,6 @@ const MoneyRequestModal = (props) => { * @returns {String} */ function getTitleForStep() { - const currentStepIndex = currentStepIndex; const isSendingMoney = props.iouType === CONST.IOU.IOU_TYPE.SEND; if (currentStepIndex === 1 || currentStepIndex === 2) { const formattedAmount = props.numberFormat( @@ -348,11 +348,98 @@ const MoneyRequestModal = (props) => { ); } - return ( -
-

Money Request Modal

-
- ); + const currentStep = this.steps[this.state.currentStepIndex]; + const reportID = lodashGet(this.props, 'route.params.reportID', ''); + return ( + + {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( + <> + + {!didScreenTransitionEnd && } + {didScreenTransitionEnd && ( + <> + {currentStep === Steps.IOUAmount && ( + + {this.renderHeader()} + { + this.setState({amount}); + this.navigateToNextStep(); + }} + reportID={reportID} + hasMultipleParticipants={this.props.hasMultipleParticipants} + selectedAmount={this.state.amount} + navigation={this.props.navigation} + iouType={this.props.iouType} + /> + + )} + {currentStep === Steps.IOUParticipants && ( + + {this.renderHeader()} + + + )} + {currentStep === Steps.IOUConfirm && ( + + {this.renderHeader()} + { + // Prevent creating multiple transactions if the button is pressed repeatedly + if (this.creatingIOUTransaction) { + return; + } + this.creatingIOUTransaction = true; + this.createTransaction(selectedParticipants); + ReportScrollManager.scrollToBottom(); + }} + onSendMoney={(paymentMethodType) => { + if (this.creatingIOUTransaction) { + return; + } + this.creatingIOUTransaction = true; + this.sendMoney(paymentMethodType); + ReportScrollManager.scrollToBottom(); + }} + hasMultipleParticipants={this.props.hasMultipleParticipants} + participants={_.filter(this.state.participants, email => this.props.currentUserPersonalDetails.login !== email.login)} + iouAmount={this.state.amount} + comment={this.state.comment} + onUpdateComment={this.updateComment} + iouType={this.props.iouType} + + // The participants can only be modified when the action is initiated from directly within a group chat and not the floating-action-button. + // This is because when there is a group of people, say they are on a trip, and you have some shared expenses with some of the people, + // but not all of them (maybe someone skipped out on dinner). Then it's nice to be able to select/deselect people from the group chat bill + // split rather than forcing the user to create a new group, just for that expense. The reportID is empty, when the action was initiated from + // the floating-action-button (since it is something that exists outside the context of a report). + canModifyParticipants={!_.isEmpty(reportID)} + /> + + )} + + )} + + + )} + + ); + } }; MoneyRequestModal.displayName = 'MoneyRequestModal'; From a447ee38c8aa0ee10b7ab0c01c3151b749c4050f Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Fri, 31 Mar 2023 17:25:51 +0000 Subject: [PATCH 07/25] update all instances of this --- src/pages/iou/MoneyRequestModal.js | 111 +++++++++++++++++++---------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index b41849a02c6f..4cf1372e8b73 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -162,6 +162,7 @@ const MoneyRequestModal = (props) => { PersonalDetails.openIOUModalPage(); } + // If the curency code is updated, also update the IOU selected currency const selectedCurrencyCode = lodashGet(props, 'iou.selectedCurrencyCode'); if (prevSelectedCurrencyCodeRef.current !== selectedCurrencyCode) { IOU.setIOUSelectedCurrency(selectedCurrencyCode); @@ -348,11 +349,54 @@ const MoneyRequestModal = (props) => { ); } - const currentStep = this.steps[this.state.currentStepIndex]; - const reportID = lodashGet(this.props, 'route.params.reportID', ''); + function renderHeader() { return ( - - {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( + + + {currentStepIndex > 0 + && ( + + + + + + + + )} +
+ + + Navigation.dismissModal()} + style={[styles.touchableButtonImage]} + accessibilityRole="button" + accessibilityLabel={props.translate('common.close')} + > + + + + + + + ); + } + + const currentStep = steps[currentStepIndex]; + const reportID = lodashGet(props, 'route.params.reportID', ''); + return ( + + {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( <> {!didScreenTransitionEnd && } @@ -360,34 +404,34 @@ const MoneyRequestModal = (props) => { <> {currentStep === Steps.IOUAmount && ( - {this.renderHeader()} + {renderHeader()} { - this.setState({amount}); - this.navigateToNextStep(); + setAmount(amount); + navigateToNextStep(); }} reportID={reportID} - hasMultipleParticipants={this.props.hasMultipleParticipants} - selectedAmount={this.state.amount} - navigation={this.props.navigation} - iouType={this.props.iouType} + hasMultipleParticipants={props.hasMultipleParticipants} + selectedAmount={amount} + navigation={props.navigation} + iouType={props.iouType} /> )} {currentStep === Steps.IOUParticipants && ( - {this.renderHeader()} + {renderHeader()} @@ -395,33 +439,26 @@ const MoneyRequestModal = (props) => { {currentStep === Steps.IOUConfirm && ( - {this.renderHeader()} + {renderHeader()} { - // Prevent creating multiple transactions if the button is pressed repeatedly - if (this.creatingIOUTransaction) { - return; - } - this.creatingIOUTransaction = true; - this.createTransaction(selectedParticipants); + // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT + createTransaction(selectedParticipants); ReportScrollManager.scrollToBottom(); }} onSendMoney={(paymentMethodType) => { - if (this.creatingIOUTransaction) { - return; - } - this.creatingIOUTransaction = true; - this.sendMoney(paymentMethodType); + // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT + sendMoney(paymentMethodType); ReportScrollManager.scrollToBottom(); }} - hasMultipleParticipants={this.props.hasMultipleParticipants} - participants={_.filter(this.state.participants, email => this.props.currentUserPersonalDetails.login !== email.login)} - iouAmount={this.state.amount} - comment={this.state.comment} - onUpdateComment={this.updateComment} - iouType={this.props.iouType} + hasMultipleParticipants={props.hasMultipleParticipants} + participants={_.filter(participants, email => props.currentUserPersonalDetails.login !== email.login)} + iouAmount={amount} + comment={comment} + onUpdateComment={comment => setComment(comment)} + iouType={props.iouType} // The participants can only be modified when the action is initiated from directly within a group chat and not the floating-action-button. // This is because when there is a group of people, say they are on a trip, and you have some shared expenses with some of the people, From c2aa299b4a956b35828110e64fc71675244a4856 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Fri, 31 Mar 2023 17:26:09 +0000 Subject: [PATCH 08/25] remove seperate header for now --- src/pages/iou/MoneyRequestHeader.js | 104 ---------------------------- 1 file changed, 104 deletions(-) delete mode 100644 src/pages/iou/MoneyRequestHeader.js diff --git a/src/pages/iou/MoneyRequestHeader.js b/src/pages/iou/MoneyRequestHeader.js deleted file mode 100644 index 6ac1381ccfbd..000000000000 --- a/src/pages/iou/MoneyRequestHeader.js +++ /dev/null @@ -1,104 +0,0 @@ -import _ from 'underscore'; -import React from 'react'; -import {View, TouchableOpacity} from 'react-native'; -import PropTypes from 'prop-types'; -import Header from '../../components/Header'; -import styles from '../../styles/styles'; -import Icon from '../../components/Icon'; -import * as Expensicons from '../../components/Icon/Expensicons'; -import Navigation from '../../libs/Navigation/Navigation'; -import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; -import Tooltip from '../../components/Tooltip'; -import CONST from '../../CONST'; - -const propTypes = { - currentStepIndex: PropTypes.number.isRequired, - iouType: PropTypes.oneOf([CONST.IOU.IOU_TYPE.SEND, CONST.IOU.IOU_TYPE.REQUEST]).isRequired, - hasMultipleParticipants: PropTypes.bool.isRequired, - amount: PropTypes.string.isRequired, - navigateToPreviousStep: PropTypes.func.isRequired, - steps: PropTypes.array.isRequired, - ...withLocalizePropTypes, -} - -const MoneyRequestHeader = (props) => { - /** - * Retrieve title for current step, based upon current step and type of IOU - * - * @returns {String} - */ - function getTitleForStep() { - const isSendingMoney = props.iouType === CONST.IOU.IOU_TYPE.SEND; - if (props.currentStepIndex === 1 || props.currentStepIndex === 2) { - const formattedAmount = props.numberFormat( - props.amount, { - style: 'currency', - currency: props.iou.selectedCurrencyCode, - }, - ); - if (isSendingMoney) { - return props.translate('iou.send', { - amount: formattedAmount, - }); - } - return props.translate( - props.hasMultipleParticipants ? 'iou.split' : 'iou.request', { - amount: formattedAmount, - }, - ); - } - if (props.currentStepIndex === 0) { - if (isSendingMoney) { - return props.translate('iou.sendMoney'); - } - return props.translate(props.hasMultipleParticipants ? 'iou.splitBill' : 'iou.requestMoney'); - } - - return props.translate(props.steps[props.currentStepIndex]) || ''; - } - - return ( - - - {props.currentStepIndex > 0 - && ( - - - - - - - - )} -
- - - Navigation.dismissModal()} - style={[styles.touchableButtonImage]} - accessibilityRole="button" - accessibilityLabel={props.translate('common.close')} - > - - - - - - - ); -} - -MoneyRequestHeader.displayName = 'MoneyRequestHeader'; -MoneyRequestHeader.propTypes = propTypes; -export default withLocalize(MoneyRequestHeader); From d8dd2d8c4d30a911e474e8ba84753fd53bf75474 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Sat, 1 Apr 2023 20:20:08 +0000 Subject: [PATCH 09/25] fix function declarations --- src/pages/iou/MoneyRequestModal.js | 152 ++++++++++++++--------------- 1 file changed, 75 insertions(+), 77 deletions(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 4cf1372e8b73..56bb61ef2778 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -30,7 +30,6 @@ import {withNetwork} from '../../components/OnyxProvider'; import reportPropTypes from '../reportPropTypes'; import * as ReportUtils from '../../libs/ReportUtils'; import * as ReportScrollManager from '../../libs/ReportScrollManager'; -import MoneyRequestHeader from './MoneyRequestHeader'; /** * IOU modal for requesting money and splitting bills. @@ -366,7 +365,7 @@ const MoneyRequestModal = (props) => { navigateToPreviousStep} style={[styles.touchableButtonImage]} > @@ -396,87 +395,86 @@ const MoneyRequestModal = (props) => { const reportID = lodashGet(props, 'route.params.reportID', ''); return ( - {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( - <> - - {!didScreenTransitionEnd && } - {didScreenTransitionEnd && ( - <> - {currentStep === Steps.IOUAmount && ( - - {renderHeader()} - { - setAmount(amount); - navigateToNextStep(); - }} - reportID={reportID} - hasMultipleParticipants={props.hasMultipleParticipants} - selectedAmount={amount} - navigation={props.navigation} - iouType={props.iouType} - /> - - )} - {currentStep === Steps.IOUParticipants && ( - - {renderHeader()} - - - )} - {currentStep === Steps.IOUConfirm && ( - - {renderHeader()} - { - // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT - createTransaction(selectedParticipants); - ReportScrollManager.scrollToBottom(); - }} - onSendMoney={(paymentMethodType) => { - // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT - sendMoney(paymentMethodType); - ReportScrollManager.scrollToBottom(); - }} - hasMultipleParticipants={props.hasMultipleParticipants} - participants={_.filter(participants, email => props.currentUserPersonalDetails.login !== email.login)} - iouAmount={amount} - comment={comment} - onUpdateComment={comment => setComment(comment)} - iouType={props.iouType} + {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( + <> + + {!didScreenTransitionEnd && } + {didScreenTransitionEnd && ( + <> + {currentStep === Steps.IOUAmount && ( + + {renderHeader()} + { + setAmount(value); + navigateToNextStep(); + }} + reportID={reportID} + hasMultipleParticipants={props.hasMultipleParticipants} + selectedAmount={amount} + navigation={props.navigation} + iouType={props.iouType} + /> + + )} + {currentStep === Steps.IOUParticipants && ( + + {renderHeader()} + setParticipants(selectedParticipants)} + onStepComplete={() => navigateToNextStep} + safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle} + /> + + )} + {currentStep === Steps.IOUConfirm && ( + + {renderHeader()} + { + // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT + createTransaction(selectedParticipants); + ReportScrollManager.scrollToBottom(); + }} + onSendMoney={(paymentMethodType) => { + // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT + sendMoney(paymentMethodType); + ReportScrollManager.scrollToBottom(); + }} + hasMultipleParticipants={props.hasMultipleParticipants} + participants={_.filter(participants, email => props.currentUserPersonalDetails.login !== email.login)} + iouAmount={amount} + comment={comment} + onUpdateComment={value => setComment(value)} + iouType={props.iouType} // The participants can only be modified when the action is initiated from directly within a group chat and not the floating-action-button. // This is because when there is a group of people, say they are on a trip, and you have some shared expenses with some of the people, // but not all of them (maybe someone skipped out on dinner). Then it's nice to be able to select/deselect people from the group chat bill // split rather than forcing the user to create a new group, just for that expense. The reportID is empty, when the action was initiated from // the floating-action-button (since it is something that exists outside the context of a report). - canModifyParticipants={!_.isEmpty(reportID)} - /> - - )} - - )} - - - )} - - ); - } + canModifyParticipants={!_.isEmpty(reportID)} + /> + + )} + + )} + + + )} + + ); }; MoneyRequestModal.displayName = 'MoneyRequestModal'; From 60cf4f89ea4585c4f067f10b601888ac80bad267 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Sat, 1 Apr 2023 20:27:36 +0000 Subject: [PATCH 10/25] Comment updates --- src/ONYXKEYS.js | 2 +- src/components/IOUConfirmationList.js | 6 +++--- src/pages/iou/steps/IOUConfirmPage.js | 6 +++--- .../iou/steps/IOUParticipantsPage/IOUParticipantsPage.js | 4 ++-- .../iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js | 2 +- .../iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ONYXKEYS.js b/src/ONYXKEYS.js index 9db87bcba6db..2a453daadce8 100755 --- a/src/ONYXKEYS.js +++ b/src/ONYXKEYS.js @@ -30,7 +30,7 @@ export default { // Credentials to authenticate the user CREDENTIALS: 'credentials', - // Contains loading data for the IOU feature (IOUModal, IOUDetail, & IOUPreview Components) + // Contains loading data for the IOU feature (MoneyRequestModal, IOUDetail, & IOUPreview Components) IOU: 'iou', // Keeps track if there is modal currently visible or not diff --git a/src/components/IOUConfirmationList.js b/src/components/IOUConfirmationList.js index eae3f48d84ca..40439bfd39f6 100755 --- a/src/components/IOUConfirmationList.js +++ b/src/components/IOUConfirmationList.js @@ -25,10 +25,10 @@ const propTypes = { /** Callback to parent modal to send money */ onSendMoney: PropTypes.func.isRequired, - /** Callback to update comment from IOUModal */ + /** Callback to update comment from MoneyRequestModal */ onUpdateComment: PropTypes.func, - /** Comment value from IOUModal */ + /** Comment value from MoneyRequestModal */ comment: PropTypes.string, /** Should we request a single or multiple participant selection from user */ @@ -40,7 +40,7 @@ const propTypes = { /** IOU type */ iouType: PropTypes.string, - /** Selected participants from IOUModal with login */ + /** Selected participants from MoneyRequestModal with login */ participants: PropTypes.arrayOf(PropTypes.shape({ login: PropTypes.string.isRequired, alternateText: PropTypes.string, diff --git a/src/pages/iou/steps/IOUConfirmPage.js b/src/pages/iou/steps/IOUConfirmPage.js index ea321b0e0a9b..f176f73f93fb 100644 --- a/src/pages/iou/steps/IOUConfirmPage.js +++ b/src/pages/iou/steps/IOUConfirmPage.js @@ -11,10 +11,10 @@ const propTypes = { /** Callback to to parent modal to send money */ onSendMoney: PropTypes.func.isRequired, - /** Callback to update comment from IOUModal */ + /** Callback to update comment from MoneyRequestModal */ onUpdateComment: PropTypes.func, - /** Comment value from IOUModal */ + /** Comment value from MoneyRequestModal */ comment: PropTypes.string, /** Should we request a single or multiple participant selection from user */ @@ -23,7 +23,7 @@ const propTypes = { /** IOU amount */ iouAmount: PropTypes.string.isRequired, - /** Selected participants from IOUMOdal with login */ + /** Selected participants from MoneyRequestModal with login */ participants: PropTypes.arrayOf(PropTypes.shape({ login: PropTypes.string.isRequired, alternateText: PropTypes.string, diff --git a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsPage.js b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsPage.js index 2d948552611e..93a27f88946f 100644 --- a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsPage.js +++ b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsPage.js @@ -16,10 +16,10 @@ const propTypes = { /** Should we request a single or multiple participant selection from user */ hasMultipleParticipants: PropTypes.bool.isRequired, - /** Callback to add participants in IOUModal */ + /** Callback to add participants in MoneyRequestModal */ onAddParticipants: PropTypes.func.isRequired, - /** Selected participants from IOUModal with login */ + /** Selected participants from MoneyRequestModal with login */ participants: PropTypes.arrayOf(PropTypes.shape({ login: PropTypes.string.isRequired, alternateText: PropTypes.string, diff --git a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js index 8d094f3cf466..8929889884e7 100755 --- a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js +++ b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsRequest.js @@ -18,7 +18,7 @@ const propTypes = { /** Callback to inform parent modal of success */ onStepComplete: PropTypes.func.isRequired, - /** Callback to add participants in IOUModal */ + /** Callback to add participants in MoneyRequestModal */ onAddParticipants: PropTypes.func.isRequired, /** All of the personal details for everyone */ diff --git a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js index fed5ed23c072..4d7c05c461e1 100755 --- a/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js +++ b/src/pages/iou/steps/IOUParticipantsPage/IOUParticipantsSplit.js @@ -22,10 +22,10 @@ const propTypes = { /** Callback to inform parent modal of success */ onStepComplete: PropTypes.func.isRequired, - /** Callback to add participants in IOUModal */ + /** Callback to add participants in MoneyRequestModal */ onAddParticipants: PropTypes.func.isRequired, - /** Selected participants from IOUModal with login */ + /** Selected participants from MoneyRequestModal with login */ participants: PropTypes.arrayOf(PropTypes.shape({ login: PropTypes.string.isRequired, alternateText: PropTypes.string, From 9f1a746bff5d942b2bafe9b584328c1f8ed386eb Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Sat, 1 Apr 2023 20:28:05 +0000 Subject: [PATCH 11/25] Update method for openMoneyRequestModalPage --- src/libs/actions/PersonalDetails.js | 6 +++--- src/pages/iou/MoneyRequestModal.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index ce3151da9c66..323d40f0004d 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -258,8 +258,8 @@ function updateSelectedTimezone(selectedTimezone) { /** * Fetches the local currency based on location and sets currency code/symbol to Onyx */ -function openIOUModalPage() { - API.read('OpenIOUModalPage'); +function openMoneyRequestModalPage() { + API.read('OpenMoneyRequestModalPage'); } /** @@ -368,7 +368,7 @@ export { getDisplayName, updateAvatar, deleteAvatar, - openIOUModalPage, + openMoneyRequestModalPage, openPersonalDetailsPage, extractFirstAndLastNameFromAvailableDetails, updateDisplayName, diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 56bb61ef2778..a396e931a512 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -137,7 +137,7 @@ const MoneyRequestModal = (props) => { const [comment, setComment] = useState(''); useEffect(() => { - PersonalDetails.openIOUModalPage(); + PersonalDetails.openMoneyRequestModalPage(); IOU.setIOUSelectedCurrency(props.currentUserPersonalDetails.localCurrencyCode); }, []); @@ -158,7 +158,7 @@ const MoneyRequestModal = (props) => { // User came back online, so we can try to create the IOU transaction again if (prevNetworkStatusRef.current && !props.network.isOffline) { - PersonalDetails.openIOUModalPage(); + PersonalDetails.openMoneyRequestModalPage(); } // If the curency code is updated, also update the IOU selected currency From e0aaee704d2a30b7e8f0a8cdee8054b27d4ba965 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Sat, 1 Apr 2023 20:28:27 +0000 Subject: [PATCH 12/25] Update usages of IOUModal Component --- src/pages/iou/IOUBillPage.js | 4 ++-- src/pages/iou/IOURequestPage.js | 4 ++-- src/pages/iou/IOUSendPage.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pages/iou/IOUBillPage.js b/src/pages/iou/IOUBillPage.js index d1938ec41a15..6ca3bc6ec916 100644 --- a/src/pages/iou/IOUBillPage.js +++ b/src/pages/iou/IOUBillPage.js @@ -1,7 +1,7 @@ import React from 'react'; -import IOUModal from './IOUModal'; +import MoneyRequestModal from './MoneyRequestModal'; // eslint-disable-next-line react/jsx-props-no-spreading -const IOUBillPage = props => ; +const IOUBillPage = props => ; IOUBillPage.displayName = 'IOUBillPage'; export default IOUBillPage; diff --git a/src/pages/iou/IOURequestPage.js b/src/pages/iou/IOURequestPage.js index 7b6e32ac9ab3..0d45ba531878 100644 --- a/src/pages/iou/IOURequestPage.js +++ b/src/pages/iou/IOURequestPage.js @@ -1,7 +1,7 @@ import React from 'react'; -import IOUModal from './IOUModal'; +import MoneyRequestModal from './MoneyRequestModal'; // eslint-disable-next-line react/jsx-props-no-spreading -const IOURequestPage = props => ; +const IOURequestPage = props => ; IOURequestPage.displayName = 'IOURequestPage'; export default IOURequestPage; diff --git a/src/pages/iou/IOUSendPage.js b/src/pages/iou/IOUSendPage.js index 79a83acaf8ea..c9aec6022293 100644 --- a/src/pages/iou/IOUSendPage.js +++ b/src/pages/iou/IOUSendPage.js @@ -1,8 +1,8 @@ import React from 'react'; import CONST from '../../CONST'; -import IOUModal from './IOUModal'; +import MoneyRequestModal from './MoneyRequestModal'; // eslint-disable-next-line react/jsx-props-no-spreading -const IOUSendPage = props => ; +const IOUSendPage = props => ; IOUSendPage.displayName = 'IOUSendPage'; export default IOUSendPage; From 3cce255c126c58fd08ce6b8b4a0741688f99ab1c Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Sat, 1 Apr 2023 20:29:49 -0700 Subject: [PATCH 13/25] update the api command that is called --- src/libs/actions/PersonalDetails.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js index 323d40f0004d..c6e1be4f6f41 100644 --- a/src/libs/actions/PersonalDetails.js +++ b/src/libs/actions/PersonalDetails.js @@ -259,7 +259,7 @@ function updateSelectedTimezone(selectedTimezone) { * Fetches the local currency based on location and sets currency code/symbol to Onyx */ function openMoneyRequestModalPage() { - API.read('OpenMoneyRequestModalPage'); + API.read('OpenIOUModalPage'); } /** From 81380ccbf82f79d6c5adfebdc2625681f792c929 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Mon, 3 Apr 2023 14:58:36 -0700 Subject: [PATCH 14/25] review comments / kill currency update --- src/pages/iou/MoneyRequestModal.js | 54 +++++++++++------------------- 1 file changed, 20 insertions(+), 34 deletions(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index a396e931a512..89b9f8ff6c41 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -126,9 +126,8 @@ const MoneyRequestModal = (props) => { // Skip IOUParticipants step if participants are passed in const steps = reportParticipants.length ? [Steps.IOUAmount, Steps.IOUConfirm] : [Steps.IOUAmount, Steps.IOUParticipants, Steps.IOUConfirm]; - const prevCreatingIOUTransactionStatusRef = useRef(); - const prevNetworkStatusRef = useRef(); - const prevSelectedCurrencyCodeRef = useRef(); + const prevCreatingIOUTransactionStatusRef = useRef(lodashGet(props.iou, 'creatingIOUTransaction')); + const prevNetworkStatusRef = useRef(props.network.isOffline); const [previousStepIndex, setPreviousStepIndex] = useState(0); const [currentStepIndex, setCurrentStepIndex] = useState(0); @@ -137,47 +136,34 @@ const MoneyRequestModal = (props) => { const [comment, setComment] = useState(''); useEffect(() => { - PersonalDetails.openMoneyRequestModalPage(); - IOU.setIOUSelectedCurrency(props.currentUserPersonalDetails.localCurrencyCode); - }, []); - - useEffect(() => { - prevCreatingIOUTransactionStatusRef.current = lodashGet(props, 'iou.creatingIOUTransaction'); - }, [props.iou]); - - useEffect(() => { - prevNetworkStatusRef.current = props.network.isOffline; - }, [props.network.isOffline]); - - useEffect(() => { - prevSelectedCurrencyCodeRef.current = lodashGet(props, 'iou.selectedCurrencyCode'); - }, [props.iou.selectedCurrencyCode]); - - useEffect(() => { - const isDoneCreatingIOUTransaction = prevCreatingIOUTransactionStatusRef.current && !lodashGet(props, 'iou.creatingIOUTransaction'); - - // User came back online, so we can try to create the IOU transaction again - if (prevNetworkStatusRef.current && !props.network.isOffline) { - PersonalDetails.openMoneyRequestModalPage(); - } - - // If the curency code is updated, also update the IOU selected currency - const selectedCurrencyCode = lodashGet(props, 'iou.selectedCurrencyCode'); - if (prevSelectedCurrencyCodeRef.current !== selectedCurrencyCode) { - IOU.setIOUSelectedCurrency(selectedCurrencyCode); - } + const isDoneCreatingIOUTransaction = prevCreatingIOUTransactionStatusRef.current && !lodashGet(props.iou, 'creatingIOUTransaction'); if (!isDoneCreatingIOUTransaction) { return; } // At this point, we're done creating the IOU transaction, but we need to check if it was successful - if (lodashGet(props, 'iou.error') === true) { + if (lodashGet(props.iou, 'error') === true) { setCurrentStepIndex(0); } else { Navigation.dismissModal(); } - }, [props.iou, props.network.isOffline]); + // eslint-disable-next-line react-hooks/exhaustive-deps -- props.iou will always exist + }, [props.iou]); + + useEffect(() => { + if (props.network.isOffline || !prevNetworkStatusRef.current) { + return; + } + + // User came back online, so let's refetch the currency details based on location + PersonalDetails.openMoneyRequestModalPage(); + }, [props.network.isOffline]); + + useEffect(() => { + prevNetworkStatusRef.current = props.network.isOffline; + prevCreatingIOUTransactionStatusRef.current = lodashGet(props.iou, 'creatingIOUTransaction'); + }); /** * Decides our animation type based on whether we're increasing or decreasing From 6424dd246f13fea403d21b90170c529abe82f209 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Mon, 3 Apr 2023 15:25:42 -0700 Subject: [PATCH 15/25] update routes / useEffect cleanup --- src/ROUTES.js | 6 +++--- src/pages/iou/MoneyRequestModal.js | 13 +++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index 2412e7e42550..d5ba2406e322 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -6,9 +6,9 @@ import * as Url from './libs/Url'; */ const REPORT = 'r'; -const IOU_REQUEST = 'iou/request'; -const IOU_BILL = 'iou/split'; -const IOU_SEND = 'iou/send'; +const IOU_REQUEST = 'request/new'; +const IOU_BILL = 'split/new'; +const IOU_SEND = 'send/new'; const IOU_DETAILS = 'iou/details'; const IOU_REQUEST_CURRENCY = `${IOU_REQUEST}/currency`; const IOU_BILL_CURRENCY = `${IOU_BILL}/currency`; diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 89b9f8ff6c41..af555f974fd0 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -136,9 +136,8 @@ const MoneyRequestModal = (props) => { const [comment, setComment] = useState(''); useEffect(() => { - const isDoneCreatingIOUTransaction = prevCreatingIOUTransactionStatusRef.current && !lodashGet(props.iou, 'creatingIOUTransaction'); - - if (!isDoneCreatingIOUTransaction) { + // If we're currently creating an IOU transaction, then we don't want to do anything + if (!prevCreatingIOUTransactionStatusRef.current || lodashGet(props.iou, 'creatingIOUTransaction')) { return; } @@ -161,6 +160,7 @@ const MoneyRequestModal = (props) => { }, [props.network.isOffline]); useEffect(() => { + // Used to store previous prop values to compare on next render prevNetworkStatusRef.current = props.network.isOffline; prevCreatingIOUTransactionStatusRef.current = lodashGet(props.iou, 'creatingIOUTransaction'); }); @@ -220,7 +220,7 @@ const MoneyRequestModal = (props) => { } /** - * Navigate to the next IOU step if possible + * Navigate to the previous IOU step if possible */ function navigateToPreviousStep() { if (currentStepIndex <= 0) { @@ -231,8 +231,9 @@ const MoneyRequestModal = (props) => { setCurrentStepIndex(currentStepIndex - 1); } + /** - * Navigate to the previous IOU step if possible + * Navigate to the next IOU step if possible */ function navigateToNextStep() { if (currentStepIndex >= steps.length - 1) { @@ -416,7 +417,7 @@ const MoneyRequestModal = (props) => { participants={participants} hasMultipleParticipants={props.hasMultipleParticipants} onAddParticipants={selectedParticipants => setParticipants(selectedParticipants)} - onStepComplete={() => navigateToNextStep} + onStepComplete={() => navigateToNextStep()} safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle} /> From 07b1fd8d935d2c5e34abedfcc0b028058fbd61d8 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Mon, 3 Apr 2023 15:29:39 -0700 Subject: [PATCH 16/25] clean up comments --- src/pages/iou/MoneyRequestModal.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index af555f974fd0..4c1dd1831f49 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -136,18 +136,18 @@ const MoneyRequestModal = (props) => { const [comment, setComment] = useState(''); useEffect(() => { - // If we're currently creating an IOU transaction, then we don't want to do anything + // We only want to check if we just finished creating an IOU transaction + // We check it within this effect because we're sending the request optimistically but if an error occurs from the API, we will update the iou state with the error later if (!prevCreatingIOUTransactionStatusRef.current || lodashGet(props.iou, 'creatingIOUTransaction')) { return; } - // At this point, we're done creating the IOU transaction, but we need to check if it was successful if (lodashGet(props.iou, 'error') === true) { setCurrentStepIndex(0); } else { Navigation.dismissModal(); } - // eslint-disable-next-line react-hooks/exhaustive-deps -- props.iou will always exist + // eslint-disable-next-line react-hooks/exhaustive-deps -- props.iou will always exist from Onyx }, [props.iou]); useEffect(() => { From 592f083f03257273a2e7730fd001a1a76aa21f42 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Mon, 3 Apr 2023 15:52:13 -0700 Subject: [PATCH 17/25] add new header component --- src/pages/iou/ModalHeader.js | 74 ++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 src/pages/iou/ModalHeader.js diff --git a/src/pages/iou/ModalHeader.js b/src/pages/iou/ModalHeader.js new file mode 100644 index 000000000000..7fdd6f2dc782 --- /dev/null +++ b/src/pages/iou/ModalHeader.js @@ -0,0 +1,74 @@ +import React from 'react'; +import {View, TouchableOpacity} from 'react-native'; +import PropTypes from 'prop-types'; +import styles from '../../styles/styles'; +import Icon from '../../components/Icon'; +import Header from '../../components/Header'; +import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; +import * as Expensicons from '../../components/Icon/Expensicons'; +import Tooltip from '../../components/Tooltip'; +import Navigation from '../../libs/Navigation/Navigation'; + +const propTypes = { + /** Title of the Header */ + title: PropTypes.string.isRequired, + + /** Should we show the back button? */ + shouldShowBackButton: PropTypes.bool, + + /** Callback to fire on back button press */ + onBackButtonPress: PropTypes.func, + + ...withLocalizePropTypes, +}; + +const defaultProps = { + shouldShowBackButton: true, + onBackButtonPress: () => Navigation.goBack(), +}; + +const ModalHeader = (props) => ( + + + {props.shouldShowBackButton + && ( + + + + + + + + )} +
+ + + Navigation.dismissModal()} + style={[styles.touchableButtonImage]} + accessibilityRole="button" + accessibilityLabel={props.translate('common.close')} + > + + + + + + +); + +ModalHeader.displayName = 'ModalHeader'; +ModalHeader.propTypes = propTypes; +ModalHeader.defaultProps = defaultProps; +export default withLocalize(ModalHeader); From 1d916df1ff1bba493cc225e5f256efc3db55dfbb Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Mon, 3 Apr 2023 15:53:38 -0700 Subject: [PATCH 18/25] clean up method to use new component --- src/pages/iou/ModalHeader.js | 2 +- src/pages/iou/MoneyRequestModal.js | 58 ++++-------------------------- 2 files changed, 8 insertions(+), 52 deletions(-) diff --git a/src/pages/iou/ModalHeader.js b/src/pages/iou/ModalHeader.js index 7fdd6f2dc782..c5bdedc8d486 100644 --- a/src/pages/iou/ModalHeader.js +++ b/src/pages/iou/ModalHeader.js @@ -27,7 +27,7 @@ const defaultProps = { onBackButtonPress: () => Navigation.goBack(), }; -const ModalHeader = (props) => ( +const ModalHeader = props => ( { ); } - function renderHeader() { - return ( - - - {currentStepIndex > 0 - && ( - - - navigateToPreviousStep} - style={[styles.touchableButtonImage]} - > - - - - - )} -
- - - Navigation.dismissModal()} - style={[styles.touchableButtonImage]} - accessibilityRole="button" - accessibilityLabel={props.translate('common.close')} - > - - - - - - - ); - } - const currentStep = steps[currentStepIndex]; const reportID = lodashGet(props, 'route.params.reportID', ''); + const shouldShowBackButton = currentStepIndex > 0; + const modalHeader = navigateToPreviousStep()} />; return ( {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( @@ -393,7 +349,7 @@ const MoneyRequestModal = (props) => { direction={getDirection()} style={[styles.flex1, safeAreaPaddingBottomStyle]} > - {renderHeader()} + {modalHeader} { setAmount(value); @@ -412,7 +368,7 @@ const MoneyRequestModal = (props) => { style={[styles.flex1]} direction={getDirection()} > - {renderHeader()} + {modalHeader} { style={[styles.flex1, safeAreaPaddingBottomStyle]} direction={getDirection()} > - {renderHeader()} + {modalHeader} { // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT From d4dd9d86fd81117aca0485f6e2a1c145c7c97ad1 Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Mon, 3 Apr 2023 15:56:39 -0700 Subject: [PATCH 19/25] remove IOU Modal --- src/pages/iou/IOUModal.js | 536 ----------------------------- src/pages/iou/MoneyRequestModal.js | 1 - 2 files changed, 537 deletions(-) delete mode 100755 src/pages/iou/IOUModal.js diff --git a/src/pages/iou/IOUModal.js b/src/pages/iou/IOUModal.js deleted file mode 100755 index 069ff51c7e57..000000000000 --- a/src/pages/iou/IOUModal.js +++ /dev/null @@ -1,536 +0,0 @@ -import _ from 'underscore'; -import React, {Component} from 'react'; -import {View, TouchableOpacity} from 'react-native'; -import PropTypes from 'prop-types'; -import lodashGet from 'lodash/get'; -import {withOnyx} from 'react-native-onyx'; -import Str from 'expensify-common/lib/str'; -import IOUAmountPage from './steps/IOUAmountPage'; -import IOUParticipantsPage from './steps/IOUParticipantsPage/IOUParticipantsPage'; -import IOUConfirmPage from './steps/IOUConfirmPage'; -import Header from '../../components/Header'; -import styles from '../../styles/styles'; -import Icon from '../../components/Icon'; -import * as IOU from '../../libs/actions/IOU'; -import * as Expensicons from '../../components/Icon/Expensicons'; -import Navigation from '../../libs/Navigation/Navigation'; -import ONYXKEYS from '../../ONYXKEYS'; -import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; -import compose from '../../libs/compose'; -import * as OptionsListUtils from '../../libs/OptionsListUtils'; -import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; -import AnimatedStep from '../../components/AnimatedStep'; -import ScreenWrapper from '../../components/ScreenWrapper'; -import Tooltip from '../../components/Tooltip'; -import CONST from '../../CONST'; -import * as PersonalDetails from '../../libs/actions/PersonalDetails'; -import withCurrentUserPersonalDetails from '../../components/withCurrentUserPersonalDetails'; -import networkPropTypes from '../../components/networkPropTypes'; -import {withNetwork} from '../../components/OnyxProvider'; -import reportPropTypes from '../reportPropTypes'; -import * as ReportUtils from '../../libs/ReportUtils'; -import * as ReportScrollManager from '../../libs/ReportScrollManager'; - -/** - * IOU modal for requesting money and splitting bills. - */ -const propTypes = { - /** Whether the IOU is for a single request or a group bill split */ - hasMultipleParticipants: PropTypes.bool, - - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.string, - - /** The report passed via the route */ - // eslint-disable-next-line react/no-unused-prop-types - report: reportPropTypes, - - /** Information about the network */ - network: networkPropTypes.isRequired, - - // Holds data related to IOU view state, rather than the underlying IOU data. - iou: PropTypes.shape({ - /** Whether or not transaction creation has started */ - creatingIOUTransaction: PropTypes.bool, - - /** Whether or not transaction creation has resulted to error */ - error: PropTypes.bool, - - // Selected Currency Code of the current IOU - selectedCurrencyCode: PropTypes.string, - }), - - /** Personal details of all the users */ - personalDetails: PropTypes.shape({ - /** Primary login of participant */ - login: PropTypes.string, - - /** Display Name of participant */ - displayName: PropTypes.string, - - /** Avatar url of participant */ - avatar: PropTypes.string, - }), - - /** Personal details of the current user */ - currentUserPersonalDetails: PropTypes.shape({ - // Local Currency Code of the current user - localCurrencyCode: PropTypes.string, - }), - - ...withLocalizePropTypes, -}; - -const defaultProps = { - hasMultipleParticipants: false, - report: { - participants: [], - }, - iouType: CONST.IOU.IOU_TYPE.REQUEST, - currentUserPersonalDetails: { - localCurrencyCode: CONST.CURRENCY.USD, - }, - personalDetails: {}, - iou: { - creatingIOUTransaction: false, - error: false, - selectedCurrencyCode: null, - }, -}; - -// Determines type of step to display within Modal, value provides the title for that page. -const Steps = { - IOUAmount: 'iou.amount', - IOUParticipants: 'iou.participants', - IOUConfirm: 'iou.confirm', -}; - -class IOUModal extends Component { - constructor(props) { - super(props); - this.navigateToPreviousStep = this.navigateToPreviousStep.bind(this); - this.navigateToNextStep = this.navigateToNextStep.bind(this); - this.addParticipants = this.addParticipants.bind(this); - this.createTransaction = this.createTransaction.bind(this); - this.updateComment = this.updateComment.bind(this); - this.sendMoney = this.sendMoney.bind(this); - - const participants = lodashGet(props, 'report.participants', []); - const participantsWithDetails = _.map(OptionsListUtils.getPersonalDetailsForLogins(participants, props.personalDetails), personalDetails => ({ - login: personalDetails.login, - text: personalDetails.displayName, - firstName: lodashGet(personalDetails, 'firstName', ''), - lastName: lodashGet(personalDetails, 'lastName', ''), - alternateText: Str.isSMSLogin(personalDetails.login) ? Str.removeSMSDomain(personalDetails.login) : personalDetails.login, - icons: [{ - source: ReportUtils.getAvatar(personalDetails.avatar, personalDetails.login), - name: personalDetails.login, - type: CONST.ICON_TYPE_AVATAR, - }], - keyForList: personalDetails.login, - payPalMeAddress: lodashGet(personalDetails, 'payPalMeAddress', ''), - phoneNumber: lodashGet(personalDetails, 'phoneNumber', ''), - })); - - this.state = { - previousStepIndex: 0, - currentStepIndex: 0, - participants: participantsWithDetails, - - // amount is currency in decimal format - amount: '', - comment: '', - }; - - // Skip IOUParticipants step if participants are passed in - if (participants.length) { - // The steps to be shown within the create IOU flow. - this.steps = [Steps.IOUAmount, Steps.IOUConfirm]; - } else { - this.steps = [Steps.IOUAmount, Steps.IOUParticipants, Steps.IOUConfirm]; - } - } - - componentDidMount() { - PersonalDetails.openIOUModalPage(); - IOU.setIOUSelectedCurrency(this.props.currentUserPersonalDetails.localCurrencyCode); - } - - componentDidUpdate(prevProps) { - const wasCreatingIOUTransaction = lodashGet(prevProps, 'iou.creatingIOUTransaction'); - const iouError = lodashGet(this.props, 'iou.error'); - if (prevProps.network.isOffline && !this.props.network.isOffline) { - PersonalDetails.openIOUModalPage(); - } - - // Successfully close the modal if transaction creation has ended and there is no error - if (wasCreatingIOUTransaction && !lodashGet(this.props, 'iou.creatingIOUTransaction') && !iouError) { - Navigation.dismissModal(); - } - - // If transaction fails, handling it here - if (wasCreatingIOUTransaction && iouError === true) { - // Navigating to Enter Amount Page - // eslint-disable-next-line react/no-did-update-set-state - this.setState({currentStepIndex: 0}); - this.creatingIOUTransaction = false; - } - - const currentSelectedCurrencyCode = lodashGet(this.props, 'iou.selectedCurrencyCode'); - if (lodashGet(prevProps, 'iou.selectedCurrencyCode') !== currentSelectedCurrencyCode) { - IOU.setIOUSelectedCurrency(currentSelectedCurrencyCode); - } - } - - /** - * Decides our animation type based on whether we're increasing or decreasing - * our step index. - * @returns {String} - */ - getDirection() { - if (this.state.previousStepIndex < this.state.currentStepIndex) { - return 'in'; - } - if (this.state.previousStepIndex > this.state.currentStepIndex) { - return 'out'; - } - - // Doesn't animate the step when first opening the modal - if (this.state.previousStepIndex === this.state.currentStepIndex) { - return null; - } - } - - /** - * Retrieve title for current step, based upon current step and type of IOU - * - * @returns {String} - */ - getTitleForStep() { - const currentStepIndex = this.state.currentStepIndex; - const isSendingMoney = this.props.iouType === CONST.IOU.IOU_TYPE.SEND; - if (currentStepIndex === 1 || currentStepIndex === 2) { - const formattedAmount = this.props.numberFormat( - this.state.amount, { - style: 'currency', - currency: this.props.iou.selectedCurrencyCode, - }, - ); - if (isSendingMoney) { - return this.props.translate('iou.send', { - amount: formattedAmount, - }); - } - return this.props.translate( - this.props.hasMultipleParticipants ? 'iou.split' : 'iou.request', { - amount: formattedAmount, - }, - ); - } - if (currentStepIndex === 0) { - if (isSendingMoney) { - return this.props.translate('iou.sendMoney'); - } - return this.props.translate(this.props.hasMultipleParticipants ? 'iou.splitBill' : 'iou.requestMoney'); - } - - return this.props.translate(this.steps[currentStepIndex]) || ''; - } - - /** - * Update comment whenever user enters any new text - * - * @param {String} comment - */ - updateComment(comment) { - this.setState({ - comment, - }); - } - - /** - * Update participants whenever user selects the payment recipient - * - * @param {Array} participants - */ - addParticipants(participants) { - this.setState({ - participants, - }); - } - - /** - * Navigate to the next IOU step if possible - */ - navigateToPreviousStep() { - if (this.state.currentStepIndex <= 0) { - return; - } - this.setState(prevState => ({ - previousStepIndex: prevState.currentStepIndex, - currentStepIndex: prevState.currentStepIndex - 1, - })); - } - - /** - * Navigate to the previous IOU step if possible - */ - navigateToNextStep() { - if (this.state.currentStepIndex >= this.steps.length - 1) { - return; - } - - this.setState(prevState => ({ - previousStepIndex: prevState.currentStepIndex, - currentStepIndex: prevState.currentStepIndex + 1, - })); - } - - /** - * Checks if user has a GOLD wallet then creates a paid IOU report on the fly - * - * @param {String} paymentMethodType - */ - sendMoney(paymentMethodType) { - const amount = Math.round(this.state.amount * 100); - const currency = this.props.iou.selectedCurrencyCode; - const comment = this.state.comment.trim(); - 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, - ); - return; - } - - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) { - IOU.sendMoneyViaPaypal( - this.props.report, - amount, - currency, - comment, - this.props.currentUserPersonalDetails.login, - participant, - ); - return; - } - - if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) { - IOU.sendMoneyWithWallet( - this.props.report, - amount, - currency, - comment, - this.props.currentUserPersonalDetails.login, - participant, - ); - } - } - - /** - * @param {Array} selectedParticipants - */ - createTransaction(selectedParticipants) { - const reportID = lodashGet(this.props, 'route.params.reportID', ''); - const comment = this.state.comment.trim(); - - // IOUs created from a group report will have a reportID param in the route. - // Since the user is already viewing the report, we don't need to navigate them to the report - if (this.props.hasMultipleParticipants && CONST.REGEX.NUMBER.test(reportID)) { - IOU.splitBill( - selectedParticipants, - this.props.currentUserPersonalDetails.login, - this.state.amount, - comment, - this.props.iou.selectedCurrencyCode, - this.props.preferredLocale, - reportID, - ); - return; - } - - // If the IOU is created from the global create menu, we also navigate the user to the group report - if (this.props.hasMultipleParticipants) { - IOU.splitBillAndOpenReport( - selectedParticipants, - this.props.currentUserPersonalDetails.login, - this.state.amount, - comment, - this.props.iou.selectedCurrencyCode, - this.props.preferredLocale, - ); - return; - } - IOU.requestMoney( - this.props.report, - Math.round(this.state.amount * 100), - this.props.iou.selectedCurrencyCode, - this.props.currentUserPersonalDetails.login, - selectedParticipants[0], - comment, - ); - } - - renderHeader() { - return ( - - - {this.state.currentStepIndex > 0 - && ( - - - - - - - - )} -
- - - Navigation.dismissModal()} - style={[styles.touchableButtonImage]} - accessibilityRole="button" - accessibilityLabel={this.props.translate('common.close')} - > - - - - - - - ); - } - - render() { - const currentStep = this.steps[this.state.currentStepIndex]; - const reportID = lodashGet(this.props, 'route.params.reportID', ''); - return ( - - {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( - <> - - {!didScreenTransitionEnd && } - {didScreenTransitionEnd && ( - <> - {currentStep === Steps.IOUAmount && ( - - {this.renderHeader()} - { - this.setState({amount}); - this.navigateToNextStep(); - }} - reportID={reportID} - hasMultipleParticipants={this.props.hasMultipleParticipants} - selectedAmount={this.state.amount} - navigation={this.props.navigation} - iouType={this.props.iouType} - /> - - )} - {currentStep === Steps.IOUParticipants && ( - - {this.renderHeader()} - - - )} - {currentStep === Steps.IOUConfirm && ( - - {this.renderHeader()} - { - // Prevent creating multiple transactions if the button is pressed repeatedly - if (this.creatingIOUTransaction) { - return; - } - this.creatingIOUTransaction = true; - this.createTransaction(selectedParticipants); - ReportScrollManager.scrollToBottom(); - }} - onSendMoney={(paymentMethodType) => { - if (this.creatingIOUTransaction) { - return; - } - this.creatingIOUTransaction = true; - this.sendMoney(paymentMethodType); - ReportScrollManager.scrollToBottom(); - }} - hasMultipleParticipants={this.props.hasMultipleParticipants} - participants={_.filter(this.state.participants, email => this.props.currentUserPersonalDetails.login !== email.login)} - iouAmount={this.state.amount} - comment={this.state.comment} - onUpdateComment={this.updateComment} - iouType={this.props.iouType} - - // The participants can only be modified when the action is initiated from directly within a group chat and not the floating-action-button. - // This is because when there is a group of people, say they are on a trip, and you have some shared expenses with some of the people, - // but not all of them (maybe someone skipped out on dinner). Then it's nice to be able to select/deselect people from the group chat bill - // split rather than forcing the user to create a new group, just for that expense. The reportID is empty, when the action was initiated from - // the floating-action-button (since it is something that exists outside the context of a report). - canModifyParticipants={!_.isEmpty(reportID)} - /> - - )} - - )} - - - )} - - ); - } -} - -IOUModal.propTypes = propTypes; -IOUModal.defaultProps = defaultProps; - -export default compose( - withLocalize, - withNetwork(), - withCurrentUserPersonalDetails, - withOnyx({ - report: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID', '')}`, - }, - iou: { - key: ONYXKEYS.IOU, - }, - personalDetails: { - key: ONYXKEYS.PERSONAL_DETAILS, - }, - }), -)(IOUModal); diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index d93ab13e109a..c7bc2e86e6de 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -228,7 +228,6 @@ const MoneyRequestModal = (props) => { setCurrentStepIndex(currentStepIndex - 1); } - /** * Navigate to the next IOU step if possible */ From 78c23add42a75b1cf9f3b252f8bb446cfb1cc50d Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Mon, 3 Apr 2023 17:00:13 -0700 Subject: [PATCH 20/25] comment update --- src/pages/iou/MoneyRequestModal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index c7bc2e86e6de..a1c7863e57a6 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -29,7 +29,7 @@ import * as ReportUtils from '../../libs/ReportUtils'; import * as ReportScrollManager from '../../libs/ReportScrollManager'; /** - * IOU modal for requesting money and splitting bills. + * Money request modal for requesting money and splitting bills. */ const propTypes = { /** Whether the IOU is for a single request or a group bill split */ From edd210c03fb81e7a97f43ce79f069cac2c91979c Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Mon, 3 Apr 2023 18:04:16 -0700 Subject: [PATCH 21/25] Add initial mount details --- src/pages/iou/MoneyRequestModal.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index a1c7863e57a6..3cf4506d9d3c 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -132,6 +132,12 @@ const MoneyRequestModal = (props) => { const [amount, setAmount] = useState(''); const [comment, setComment] = useState(''); + useEffect(() => { + PersonalDetails.openMoneyRequestModalPage(); + IOU.setIOUSelectedCurrency(props.currentUserPersonalDetails.localCurrencyCode); + // eslint-disable-next-line react-hooks/exhaustive-deps -- props.currentUserPersonalDetails will always exist from Onyx + }, []); + useEffect(() => { // We only want to check if we just finished creating an IOU transaction // We check it within this effect because we're sending the request optimistically but if an error occurs from the API, we will update the iou state with the error later From faf4cb0348666914c8a66a5ab73e494221d78a2d Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Tue, 4 Apr 2023 10:15:08 -0700 Subject: [PATCH 22/25] review comments --- src/pages/iou/ModalHeader.js | 2 +- src/pages/iou/MoneyRequestModal.js | 126 ++++++++++++++--------------- 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/src/pages/iou/ModalHeader.js b/src/pages/iou/ModalHeader.js index c5bdedc8d486..a89b184fb897 100644 --- a/src/pages/iou/ModalHeader.js +++ b/src/pages/iou/ModalHeader.js @@ -10,7 +10,7 @@ import Tooltip from '../../components/Tooltip'; import Navigation from '../../libs/Navigation/Navigation'; const propTypes = { - /** Title of the Header */ + /** Title of the header */ title: PropTypes.string.isRequired, /** Should we show the back button? */ diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 3cf4506d9d3c..9ec0bf94e634 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -29,7 +29,7 @@ import * as ReportUtils from '../../libs/ReportUtils'; import * as ReportScrollManager from '../../libs/ReportScrollManager'; /** - * Money request modal for requesting money and splitting bills. + * A modal used for requesting money, splitting bills or sending money. */ const propTypes = { /** Whether the IOU is for a single request or a group bill split */ @@ -171,7 +171,7 @@ const MoneyRequestModal = (props) => { /** * Decides our animation type based on whether we're increasing or decreasing * our step index. - * @returns {String} + * @returns {String|null} */ function getDirection() { if (previousStepIndex < currentStepIndex) { @@ -350,71 +350,71 @@ const MoneyRequestModal = (props) => { {didScreenTransitionEnd && ( <> {currentStep === Steps.IOUAmount && ( - - {modalHeader} - { - setAmount(value); - navigateToNextStep(); - }} - reportID={reportID} - hasMultipleParticipants={props.hasMultipleParticipants} - selectedAmount={amount} - navigation={props.navigation} - iouType={props.iouType} - /> - + + {modalHeader} + { + setAmount(value); + navigateToNextStep(); + }} + reportID={reportID} + hasMultipleParticipants={props.hasMultipleParticipants} + selectedAmount={amount} + navigation={props.navigation} + iouType={props.iouType} + /> + )} {currentStep === Steps.IOUParticipants && ( - - {modalHeader} - setParticipants(selectedParticipants)} - onStepComplete={() => navigateToNextStep()} - safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle} - /> - + + {modalHeader} + setParticipants(selectedParticipants)} + onStepComplete={() => navigateToNextStep()} + safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle} + /> + )} {currentStep === Steps.IOUConfirm && ( - - {modalHeader} - { - // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT - createTransaction(selectedParticipants); - ReportScrollManager.scrollToBottom(); - }} - onSendMoney={(paymentMethodType) => { - // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT - sendMoney(paymentMethodType); - ReportScrollManager.scrollToBottom(); - }} - hasMultipleParticipants={props.hasMultipleParticipants} - participants={_.filter(participants, email => props.currentUserPersonalDetails.login !== email.login)} - iouAmount={amount} - comment={comment} - onUpdateComment={value => setComment(value)} - iouType={props.iouType} - - // The participants can only be modified when the action is initiated from directly within a group chat and not the floating-action-button. - // This is because when there is a group of people, say they are on a trip, and you have some shared expenses with some of the people, - // but not all of them (maybe someone skipped out on dinner). Then it's nice to be able to select/deselect people from the group chat bill - // split rather than forcing the user to create a new group, just for that expense. The reportID is empty, when the action was initiated from - // the floating-action-button (since it is something that exists outside the context of a report). - canModifyParticipants={!_.isEmpty(reportID)} - /> - + + {modalHeader} + { + // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT + createTransaction(selectedParticipants); + ReportScrollManager.scrollToBottom(); + }} + onSendMoney={(paymentMethodType) => { + // TODO: ADD HANDLING TO DISABLE BUTTON FUNCTIONALITY WHILE REQUEST IS IN FLIGHT + sendMoney(paymentMethodType); + ReportScrollManager.scrollToBottom(); + }} + hasMultipleParticipants={props.hasMultipleParticipants} + participants={_.filter(participants, email => props.currentUserPersonalDetails.login !== email.login)} + iouAmount={amount} + comment={comment} + onUpdateComment={value => setComment(value)} + iouType={props.iouType} + + // The participants can only be modified when the action is initiated from directly within a group chat and not the floating-action-button. + // This is because when there is a group of people, say they are on a trip, and you have some shared expenses with some of the people, + // but not all of them (maybe someone skipped out on dinner). Then it's nice to be able to select/deselect people from the group chat bill + // split rather than forcing the user to create a new group, just for that expense. The reportID is empty, when the action was initiated from + // the floating-action-button (since it is something that exists outside the context of a report). + canModifyParticipants={!_.isEmpty(reportID)} + /> + )} )} From c9af57d16de48516d2a33e9b827c8e8e7c77e51a Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Tue, 4 Apr 2023 13:15:39 -0700 Subject: [PATCH 23/25] remove lint --- src/pages/iou/MoneyRequestModal.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 9ec0bf94e634..17fa97fcc54a 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -150,7 +150,6 @@ const MoneyRequestModal = (props) => { } else { Navigation.dismissModal(); } - // eslint-disable-next-line react-hooks/exhaustive-deps -- props.iou will always exist from Onyx }, [props.iou]); useEffect(() => { From 1a8df6f253d7b860d62002caa547b44e166fa0df Mon Sep 17 00:00:00 2001 From: Jack Nam Date: Tue, 4 Apr 2023 15:14:21 -0700 Subject: [PATCH 24/25] review. comments / update functions to useCallback --- src/pages/iou/MoneyRequestModal.js | 59 ++++++++++++++++-------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index 17fa97fcc54a..c28702544d7c 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -1,5 +1,7 @@ import _ from 'underscore'; -import React, {useState, useEffect, useRef} from 'react'; +import React, { + useState, useEffect, useRef, useCallback, +} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; @@ -32,7 +34,7 @@ import * as ReportScrollManager from '../../libs/ReportScrollManager'; * A modal used for requesting money, splitting bills or sending money. */ const propTypes = { - /** Whether the IOU is for a single request or a group bill split */ + /** Whether the request is for a single request or a group bill split */ hasMultipleParticipants: PropTypes.bool, /** The type of IOU report, i.e. bill, request, send */ @@ -45,7 +47,7 @@ const propTypes = { /** Information about the network */ network: networkPropTypes.isRequired, - // Holds data related to IOU view state, rather than the underlying IOU data. + // Holds data related to request view state, rather than the underlying request data. iou: PropTypes.shape({ /** Whether or not transaction creation has started */ creatingIOUTransaction: PropTypes.bool, @@ -53,7 +55,7 @@ const propTypes = { /** Whether or not transaction creation has resulted to error */ error: PropTypes.bool, - // Selected Currency Code of the current IOU + // Selected Currency Code of the current request selectedCurrencyCode: PropTypes.string, }), @@ -135,7 +137,7 @@ const MoneyRequestModal = (props) => { useEffect(() => { PersonalDetails.openMoneyRequestModalPage(); IOU.setIOUSelectedCurrency(props.currentUserPersonalDetails.localCurrencyCode); - // eslint-disable-next-line react-hooks/exhaustive-deps -- props.currentUserPersonalDetails will always exist from Onyx + // eslint-disable-next-line react-hooks/exhaustive-deps -- props.currentUserPersonalDetails will always exist from Onyx and we don't want this effect to run again }, []); useEffect(() => { @@ -172,7 +174,7 @@ const MoneyRequestModal = (props) => { * our step index. * @returns {String|null} */ - function getDirection() { + const getDirection = useCallback(() => { if (previousStepIndex < currentStepIndex) { return 'in'; } @@ -184,14 +186,14 @@ const MoneyRequestModal = (props) => { if (previousStepIndex === currentStepIndex) { return null; } - } + }, [previousStepIndex, currentStepIndex]); /** - * Retrieve title for current step, based upon current step and type of IOU + * Retrieve title for current step, based upon current step and type of request * * @returns {String} */ - function getTitleForStep() { + const getTitleForStep = useCallback(() => { const isSendingMoney = props.iouType === CONST.IOU.IOU_TYPE.SEND; if (currentStepIndex === 1 || currentStepIndex === 2) { const formattedAmount = props.numberFormat( @@ -219,38 +221,41 @@ const MoneyRequestModal = (props) => { } return props.translate(steps[currentStepIndex]) || ''; - } + // eslint-disable-next-line react-hooks/exhaustive-deps -- props does not need to be a dependency as it will always exist + }, [amount, currentStepIndex, props.hasMultipleParticipants, props.iou.selectedCurrencyCode, props.iouType, props.numberFormat, steps]); + + /** - * Navigate to the previous IOU step if possible + * Navigate to the previous request step if possible */ - function navigateToPreviousStep() { + const navigateToPreviousStep = useCallback(() => { if (currentStepIndex <= 0) { return; } setPreviousStepIndex(currentStepIndex); setCurrentStepIndex(currentStepIndex - 1); - } + }, [currentStepIndex]); /** - * Navigate to the next IOU step if possible + * Navigate to the next request step if possible */ - function navigateToNextStep() { + const navigateToNextStep = useCallback(() => { if (currentStepIndex >= steps.length - 1) { return; } setPreviousStepIndex(currentStepIndex); setCurrentStepIndex(currentStepIndex + 1); - } + }, [currentStepIndex, steps.length]); /** * Checks if user has a GOLD wallet then creates a paid IOU report on the fly * * @param {String} paymentMethodType */ - function sendMoney(paymentMethodType) { + const sendMoney = useCallback((paymentMethodType) => { const amountInDollars = Math.round(amount * 100); const currency = props.iou.selectedCurrencyCode; const trimmedComment = comment.trim(); @@ -290,13 +295,13 @@ const MoneyRequestModal = (props) => { participant, ); } - } + }, [amount, comment, participants, props.currentUserPersonalDetails.login, props.iou.selectedCurrencyCode, props.report]); /** * @param {Array} selectedParticipants */ - function createTransaction(selectedParticipants) { - const reportID = lodashGet(props, 'route.params.reportID', ''); + const createTransaction = useCallback((selectedParticipants) => { + const reportID = lodashGet(props.route, 'params.reportID', ''); const trimmedComment = comment.trim(); // IOUs created from a group report will have a reportID param in the route. @@ -314,7 +319,7 @@ const MoneyRequestModal = (props) => { return; } - // If the IOU is created from the global create menu, we also navigate the user to the group report + // If the request is created from the global create menu, we also navigate the user to the group report if (props.hasMultipleParticipants) { IOU.splitBillAndOpenReport( selectedParticipants, @@ -334,12 +339,12 @@ const MoneyRequestModal = (props) => { selectedParticipants[0], trimmedComment, ); - } + }, [amount, comment, props.currentUserPersonalDetails.login, props.hasMultipleParticipants, props.iou.selectedCurrencyCode, props.preferredLocale, props.report, props.route]); const currentStep = steps[currentStepIndex]; const reportID = lodashGet(props, 'route.params.reportID', ''); const shouldShowBackButton = currentStepIndex > 0; - const modalHeader = navigateToPreviousStep()} />; + const modalHeader = ; return ( {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( @@ -350,7 +355,7 @@ const MoneyRequestModal = (props) => { <> {currentStep === Steps.IOUAmount && ( {modalHeader} @@ -370,14 +375,14 @@ const MoneyRequestModal = (props) => { {currentStep === Steps.IOUParticipants && ( {modalHeader} setParticipants(selectedParticipants)} - onStepComplete={() => navigateToNextStep()} + onStepComplete={navigateToNextStep} safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle} /> @@ -385,7 +390,7 @@ const MoneyRequestModal = (props) => { {currentStep === Steps.IOUConfirm && ( {modalHeader} Date: Tue, 4 Apr 2023 15:50:55 -0700 Subject: [PATCH 25/25] update some functions to memo --- src/pages/iou/MoneyRequestModal.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/pages/iou/MoneyRequestModal.js b/src/pages/iou/MoneyRequestModal.js index c28702544d7c..00e92b26cecc 100644 --- a/src/pages/iou/MoneyRequestModal.js +++ b/src/pages/iou/MoneyRequestModal.js @@ -1,6 +1,6 @@ import _ from 'underscore'; import React, { - useState, useEffect, useRef, useCallback, + useState, useEffect, useRef, useCallback, useMemo, } from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; @@ -174,7 +174,7 @@ const MoneyRequestModal = (props) => { * our step index. * @returns {String|null} */ - const getDirection = useCallback(() => { + const direction = useMemo(() => { if (previousStepIndex < currentStepIndex) { return 'in'; } @@ -193,7 +193,7 @@ const MoneyRequestModal = (props) => { * * @returns {String} */ - const getTitleForStep = useCallback(() => { + const titleForStep = useMemo(() => { const isSendingMoney = props.iouType === CONST.IOU.IOU_TYPE.SEND; if (currentStepIndex === 1 || currentStepIndex === 2) { const formattedAmount = props.numberFormat( @@ -224,8 +224,6 @@ const MoneyRequestModal = (props) => { // eslint-disable-next-line react-hooks/exhaustive-deps -- props does not need to be a dependency as it will always exist }, [amount, currentStepIndex, props.hasMultipleParticipants, props.iou.selectedCurrencyCode, props.iouType, props.numberFormat, steps]); - - /** * Navigate to the previous request step if possible */ @@ -344,7 +342,7 @@ const MoneyRequestModal = (props) => { const currentStep = steps[currentStepIndex]; const reportID = lodashGet(props, 'route.params.reportID', ''); const shouldShowBackButton = currentStepIndex > 0; - const modalHeader = ; + const modalHeader = ; return ( {({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => ( @@ -355,7 +353,7 @@ const MoneyRequestModal = (props) => { <> {currentStep === Steps.IOUAmount && ( {modalHeader} @@ -375,7 +373,7 @@ const MoneyRequestModal = (props) => { {currentStep === Steps.IOUParticipants && ( {modalHeader} { {currentStep === Steps.IOUConfirm && ( {modalHeader}