From 8c8d3ff0cd340f70ba1fa68169fb7936b1de1149 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Sun, 8 Oct 2023 20:29:41 +0800 Subject: [PATCH 01/59] Make SplitBillDetailsPage editable when receipt is scanning or SS failed --- src/pages/iou/SplitBillDetailsPage.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 3de27a0086bd..9e7419abd5ad 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -72,6 +72,7 @@ function SplitBillDetailsPage(props) { const participantsExcludingPayee = _.filter(participants, (participant) => participant.accountID !== reportAction.actorAccountID); const {amount: splitAmount, currency: splitCurrency, comment: splitComment, merchant: splitMerchant, created: splitCreated} = ReportUtils.getTransactionDetails(transaction); const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); + const isEditable = isScanning || (TransactionUtils.hasReceipt && transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED); return ( @@ -93,11 +94,11 @@ function SplitBillDetailsPage(props) { iouCreated={splitCreated} iouMerchant={splitMerchant} iouType={CONST.IOU.MONEY_REQUEST_TYPE.SPLIT} - isReadOnly + isReadOnly={!isEditable} receiptPath={transaction.receipt && transaction.receipt.source} receiptFilename={transaction.filename} - shouldShowFooter={false} isScanning={isScanning} + shouldShowFooter={false} /> )} From 12b90431f1383cb6b7d9a7f2d8bef5964b61186e Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Sun, 8 Oct 2023 21:20:16 +0800 Subject: [PATCH 02/59] Only show SmartScan fields splitting manually or editting a split --- src/components/MoneyRequestConfirmationList.js | 10 +++------- src/pages/iou/SplitBillDetailsPage.js | 15 +++++++++++++-- src/pages/iou/steps/MoneyRequestConfirmPage.js | 1 + 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 6fcfc3bb4f08..480284a1c296 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -203,10 +203,6 @@ function MoneyRequestConfirmationList(props) { // A flag for showing the categories field const shouldShowCategories = isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && OptionsListUtils.hasEnabledOptions(_.values(props.policyCategories)); - // A flag for showing SS fields: date, merchant, and amount, only when we don't have a receiptPath (e.g. manual request) - // or in the split details page when it's ReadOnly - const shouldShowSmartScanFields = (!props.receiptPath || props.isReadOnly) && !props.isScanning; - // Fetches the first tag list of the policy const policyTag = PolicyUtils.getTag(props.policyTags); const policyTagList = lodashGet(policyTag, 'tags', {}); @@ -506,7 +502,7 @@ function MoneyRequestConfirmationList(props) { isAuthTokenRequired={!_.isEmpty(receiptThumbnail)} /> )} - {shouldShowSmartScanFields && ( + {props.shouldShowSmartScanFields && ( - {shouldShowSmartScanFields && ( + {props.shouldShowSmartScanFields && ( )} - {shouldShowSmartScanFields && ( + {props.shouldShowSmartScanFields && ( participant.accountID !== reportAction.actorAccountID); const {amount: splitAmount, currency: splitCurrency, comment: splitComment, merchant: splitMerchant, created: splitCreated} = ReportUtils.getTransactionDetails(transaction); const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); - const isEditable = isScanning || (TransactionUtils.hasReceipt && transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED); + const canEditSplit = + props.session.accountID === reportAction.actorAccountID && (isScanning || (TransactionUtils.hasReceipt && transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED)); return ( @@ -94,7 +101,8 @@ function SplitBillDetailsPage(props) { iouCreated={splitCreated} iouMerchant={splitMerchant} iouType={CONST.IOU.MONEY_REQUEST_TYPE.SPLIT} - isReadOnly={!isEditable} + isReadOnly={!canEditSplit} + shouldShowSmartScanFields receiptPath={transaction.receipt && transaction.receipt.source} receiptFilename={transaction.filename} isScanning={isScanning} @@ -118,5 +126,8 @@ export default compose( personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, + session: { + key: ONYXKEYS.SESSION, + }, }), )(SplitBillDetailsPage); diff --git a/src/pages/iou/steps/MoneyRequestConfirmPage.js b/src/pages/iou/steps/MoneyRequestConfirmPage.js index 2c8f1adb1b11..b82e3c9575dc 100644 --- a/src/pages/iou/steps/MoneyRequestConfirmPage.js +++ b/src/pages/iou/steps/MoneyRequestConfirmPage.js @@ -366,6 +366,7 @@ function MoneyRequestConfirmPage(props) { iouCreated={props.iou.created} isDistanceRequest={isDistanceRequest} listStyles={[StyleUtils.getMaximumHeight(windowHeight / 3)]} + shouldShowSmartScanFields={_.isEmpty(props.iou.receiptPath)} /> From 7fba50a4d00674eaceb8d78a5a681c0ee276006f Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Sun, 8 Oct 2023 21:59:34 +0800 Subject: [PATCH 03/59] Create EditSplitBillPage --- src/libs/actions/IOU.js | 18 ++++ src/pages/EditSplitBillPage.js | 178 +++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 src/pages/EditSplitBillPage.js diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 6c5f2cbc1e33..75008aca02f3 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1471,6 +1471,23 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co Report.notifyNewAction(splitChatReport.chatReportID, currentUserAccountID); } +/** + * @param {Number} reportID + * @param {Number} reportActionID + * @param {String} transactionID + * @param {Object} transactionChanges + */ +function setSpliBillTransaction(reportID, reportActionID, transactionID, transactionChanges) { + const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; + const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction, transactionChanges); + Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, updatedTransaction); + Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { + [reportActionID]: { + lastModified: DateUtils.getDBTime(), + }, + }); +} + /** * @param {String} transactionID * @param {Number} transactionThreadReportID @@ -2535,6 +2552,7 @@ export { splitBill, splitBillAndOpenReport, startSplitBill, + setSpliBillTransaction, requestMoney, sendMoneyElsewhere, approveMoneyRequest, diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js new file mode 100644 index 000000000000..cfd83b36c94d --- /dev/null +++ b/src/pages/EditSplitBillPage.js @@ -0,0 +1,178 @@ +import React, {useEffect} from 'react'; +import PropTypes from 'prop-types'; +import lodashGet from 'lodash/get'; +import {withOnyx} from 'react-native-onyx'; +import compose from '../libs/compose'; +import CONST from '../CONST'; +import ROUTES from '../ROUTES'; +import Navigation from '../libs/Navigation/Navigation'; +import ONYXKEYS from '../ONYXKEYS'; +import * as ReportActionsUtils from '../libs/ReportActionsUtils'; +import * as ReportUtils from '../libs/ReportUtils'; +import * as TransactionUtils from '../libs/TransactionUtils'; +import * as Policy from '../libs/actions/Policy'; +import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../components/withCurrentUserPersonalDetails'; +import EditRequestDescriptionPage from './EditRequestDescriptionPage'; +import EditRequestMerchantPage from './EditRequestMerchantPage'; +import EditRequestCreatedPage from './EditRequestCreatedPage'; +import EditRequestAmountPage from './EditRequestAmountPage'; +import reportPropTypes from './reportPropTypes'; +import * as IOU from '../libs/actions/IOU'; +import * as CurrencyUtils from '../libs/CurrencyUtils'; +import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView'; + +const propTypes = { + /** Route from navigation */ + route: PropTypes.shape({ + /** Params from the route */ + params: PropTypes.shape({ + /** Which field we are editing */ + field: PropTypes.string, + + /** reportID for the "transaction thread" */ + threadReportID: PropTypes.string, + }), + }).isRequired, + + /** The report object for the thread report */ + report: reportPropTypes, + + /** The parent report object for the thread report */ + parentReport: reportPropTypes, + + /** The policy object for the current route */ + policy: PropTypes.shape({ + /** The name of the policy */ + name: PropTypes.string, + + /** The URL for the policy avatar */ + avatar: PropTypes.string, + }), + + /** Session info for the currently logged in user. */ + session: PropTypes.shape({ + /** Currently logged in user email */ + email: PropTypes.string, + }), + + ...withCurrentUserPersonalDetailsPropTypes, +}; + +const defaultProps = { + report: {}, + parentReport: {}, + policy: null, + session: { + email: null, + }, +}; + +function EditSplitBillRequestPage({report, reportActions, route}) { + const fieldToEdit = lodashGet(route, ['params', 'field'], ''); + const reportAction = reportActions[route.params.reportActionID]; + const transaction = TransactionUtils.getLinkedTransaction(reportAction); + + const {amount: transactionAmount, currency: transactionCurrency, comment: transactionDescription, merchant: transactionMerchant} = ReportUtils.getTransactionDetails(transaction); + + const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; + + function updateSplitBillTransaction(transactionChanges) { + IOU.updateSplitBillTransaction(report.reportID, reportAction.reportActionID, transaction.transactionID, transactionChanges); + Navigation.goBack(ROUTES.SPLIT_BILL_DETAILS.getRoute(report.reportID, reportAction.reportActionID)); + } + + if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.DESCRIPTION) { + return ( + { + if (transactionChanges.comment === transactionDescription) { + Navigation.dismissModal(); + return; + } + updateSplitBillTransaction({ + comment: transactionChanges.comment, + }); + }} + /> + ); + } + + if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.DATE) { + return ( + { + if (transactionChanges.created === transactionCreated) { + Navigation.dismissModal(); + return; + } + updateSplitBillTransaction({ + created: transactionChanges.created, + }); + }} + /> + ); + } + + if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.AMOUNT) { + return ( + { + const amount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(transactionChanges)); + + if (amount === transactionAmount && transactionCurrency === defaultCurrency) { + Navigation.goBack(); + return; + } + + updateSplitBillTransaction({ + amount, + currency: defaultCurrency, + }); + }} + /> + ); + } + + if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.MERCHANT) { + return ( + { + if (transactionMerchant === transactionChanges.merchant) { + Navigation.goBack(); + return; + } + updateSplitBillTransaction({merchant: transactionChanges.merchant}); + }} + /> + ); + } + + return ; +} + +EditSplitBillRequestPage.displayName = 'EditSplitBillRequestPage'; +EditSplitBillRequestPage.propTypes = propTypes; +EditSplitBillRequestPage.defaultProps = defaultProps; +export default compose( + withCurrentUserPersonalDetails, + withOnyx({ + report: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, + }, + reportActions: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${route.params.reportID}`, + canEvict: false, + }, + policy: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, + }, + }), +)(EditSplitBillRequestPage); From bd7c4b2d2bbd9f09fd103265bc64de0933845b5a Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Sun, 8 Oct 2023 21:59:52 +0800 Subject: [PATCH 04/59] Create routes for EditSplitBillPage --- src/ROUTES.ts | 8 ++++++++ src/libs/Navigation/AppNavigator/ModalStackNavigators.js | 2 ++ src/libs/Navigation/linkingConfig.js | 2 ++ 3 files changed, 12 insertions(+) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 2b64dd9c5465..d8f1dc06898b 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -161,6 +161,14 @@ export default { route: 'r/:reportID/split/:reportActionID', getRoute: (reportID: string, reportActionID: string) => `r/${reportID}/split/${reportActionID}`, }, + EDIT_SPLIT_BILL: { + route: `r/:reportID/split/:reportActionID/edit/:field`, + getRoute: (reportID: number, reportActionID: number, field: ValueOf) => `r/${reportID}/split/${reportActionID}/edit/${field}`, + }, + EDIT_SPLIT_BILL_CURRENCY: { + route: 'r/:reportID/split/:reportActionID/edit/currency', + getRoute: (reportID: number, reportActionID: number, currency: string, backTo: string) => `r/${reportID}/split/${reportActionID}/edit/currency?currency=${currency}&backTo=${backTo}`, + }, TASK_TITLE: { route: 'r/:reportID/title', getRoute: (reportID: string) => `r/${reportID}/title`, diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js index 6636702592c0..d3d5c1b89dbd 100644 --- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js +++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js @@ -53,6 +53,8 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator({ const SplitDetailsModalStackNavigator = createModalStackNavigator({ SplitDetails_Root: () => require('../../../pages/iou/SplitBillDetailsPage').default, + SplitDetails_Edit_Request: () => require('../../../pages/EditSplitBillPage').default, + SplitDetails_Edit_Currency: () => require('../../../pages/iou/IOUCurrencySelection').default, }); const DetailsModalStackNavigator = createModalStackNavigator({ diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index bf069aba314e..707e4d55a666 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -344,6 +344,8 @@ export default { SplitDetails: { screens: { SplitDetails_Root: ROUTES.SPLIT_BILL_DETAILS.route, + SplitDetails_Edit_Request: ROUTES.EDIT_SPLIT_BILL.route, + SplitDetails_Edit_Currency: ROUTES.EDIT_SPLIT_BILL_CURRENCY.route, }, }, Task_Details: { From 4b95154f3d792d56bfc1f777147077066e5b5a51 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 9 Oct 2023 00:47:42 +0800 Subject: [PATCH 05/59] Configure inputs on split details page and link them with routes --- .../MoneyRequestConfirmationList.js | 34 +++++++++++++++--- src/libs/TransactionUtils.ts | 10 ++++-- src/libs/actions/IOU.js | 6 ++-- src/pages/EditRequestAmountPage.js | 3 +- src/pages/EditSplitBillPage.js | 35 ++++++++----------- src/pages/iou/SplitBillDetailsPage.js | 7 ++-- 6 files changed, 61 insertions(+), 34 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 480284a1c296..0c5c217bb04d 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -507,7 +507,15 @@ function MoneyRequestConfirmationList(props) { shouldShowRightIcon={!props.isReadOnly && !props.isDistanceRequest} title={formattedAmount} description={translate('iou.amount')} - onPress={() => !props.isDistanceRequest && Navigation.navigate(ROUTES.MONEY_REQUEST_AMOUNT.getRoute(props.iouType, props.reportID))} + onPress={() => { + if (props.isDistanceRequest) { + return; + } + if (props.canEditSplit) { + Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.AMOUNT)); + return; + } + }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} disabled={didConfirm || props.isReadOnly} @@ -518,7 +526,13 @@ function MoneyRequestConfirmationList(props) { shouldParseTitle title={props.iouComment} description={translate('common.description')} - onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_DESCRIPTION.getRoute(props.iouType, props.reportID))} + onPress={() => { + if (props.canEditSplit) { + Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.DESCRIPTION)); + return; + } + Navigation.navigate(ROUTES.MONEY_REQUEST_DESCRIPTION.getRoute(props.iouType, props.reportID)); + }} style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} disabled={didConfirm || props.isReadOnly} @@ -548,7 +562,13 @@ function MoneyRequestConfirmationList(props) { description={translate('common.date')} style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} - onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_DATE.getRoute(props.iouType, props.reportID))} + onPress={() => { + if (props.canEditSplit) { + Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.DATE)); + return; + } + Navigation.navigate(ROUTES.MONEY_REQUEST_DATE.getRoute(props.iouType, props.reportID)); + }} disabled={didConfirm || props.isReadOnly} /> )} @@ -570,7 +590,13 @@ function MoneyRequestConfirmationList(props) { description={translate('common.merchant')} style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} - onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_MERCHANT.getRoute(props.iouType, props.reportID))} + onPress={() => { + if (props.canEditSplit) { + Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.MERCHANT)); + return; + } + Navigation.navigate(ROUTES.MONEY_REQUEST_MERCHANT.getRoute(props.iouType, props.reportID)); + }} disabled={didConfirm || props.isReadOnly} /> )} diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 31bf90a6051f..eaac5ad90c25 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -96,7 +96,7 @@ function areRequiredFieldsEmpty(transaction: Transaction): boolean { /** * Given the edit made to the money request, return an updated transaction object. */ -function getUpdatedTransaction(transaction: Transaction, transactionChanges: TransactionChanges, isFromExpenseReport: boolean): Transaction { +function getUpdatedTransaction(transaction: Transaction, transactionChanges: TransactionChanges, isFromExpenseReport: boolean, shouldUpdateReceiptState: boolean = true): Transaction { // Only changing the first level fields so no need for deep clone now const updatedTransaction = {...transaction}; let shouldStopSmartscan = false; @@ -143,7 +143,13 @@ function getUpdatedTransaction(transaction: Transaction, transactionChanges: Tra updatedTransaction.tag = transactionChanges.tag; } - if (shouldStopSmartscan && transaction?.receipt && Object.keys(transaction.receipt).length > 0 && transaction?.receipt?.state !== CONST.IOU.RECEIPT_STATE.OPEN) { + if ( + shouldUpdateReceiptState && + shouldStopSmartscan && + transaction?.receipt && + Object.keys(transaction.receipt).length > 0 && + transaction?.receipt?.state !== CONST.IOU.RECEIPT_STATE.OPEN + ) { updatedTransaction.receipt.state = CONST.IOU.RECEIPT_STATE.OPEN; } diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 75008aca02f3..b99fd4743a48 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1477,9 +1477,9 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co * @param {String} transactionID * @param {Object} transactionChanges */ -function setSpliBillTransaction(reportID, reportActionID, transactionID, transactionChanges) { +function setSplitBillTransaction(reportID, reportActionID, transactionID, transactionChanges) { const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; - const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction, transactionChanges); + const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, false, false); Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, updatedTransaction); Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { [reportActionID]: { @@ -2552,7 +2552,7 @@ export { splitBill, splitBillAndOpenReport, startSplitBill, - setSpliBillTransaction, + setSplitBillTransaction, requestMoney, sendMoneyElsewhere, approveMoneyRequest, diff --git a/src/pages/EditRequestAmountPage.js b/src/pages/EditRequestAmountPage.js index 9f72c9afbc23..8d3fb05e8e90 100644 --- a/src/pages/EditRequestAmountPage.js +++ b/src/pages/EditRequestAmountPage.js @@ -23,7 +23,7 @@ const propTypes = { reportID: PropTypes.string.isRequired, }; -function EditRequestAmountPage({defaultAmount, defaultCurrency, onSubmit, reportID}) { +function EditRequestAmountPage({defaultAmount, defaultCurrency, reportID, reportActionID, onSubmit}) { const {translate} = useLocalize(); const textInput = useRef(null); @@ -35,7 +35,6 @@ function EditRequestAmountPage({defaultAmount, defaultCurrency, onSubmit, report if (!textInput.current) { return; } - textInput.current.focus(); }); }; diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index cfd83b36c94d..f129640225a1 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -67,18 +67,19 @@ const defaultProps = { }, }; -function EditSplitBillRequestPage({report, reportActions, route}) { +function EditSplitBillRequestPage({report, route}) { const fieldToEdit = lodashGet(route, ['params', 'field'], ''); - const reportAction = reportActions[route.params.reportActionID]; + const reportAction = ReportActionsUtils.getReportAction(report.reportID, lodashGet(route, ['params', 'reportActionID'], '')); const transaction = TransactionUtils.getLinkedTransaction(reportAction); const {amount: transactionAmount, currency: transactionCurrency, comment: transactionDescription, merchant: transactionMerchant} = ReportUtils.getTransactionDetails(transaction); const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; - function updateSplitBillTransaction(transactionChanges) { - IOU.updateSplitBillTransaction(report.reportID, reportAction.reportActionID, transaction.transactionID, transactionChanges); - Navigation.goBack(ROUTES.SPLIT_BILL_DETAILS.getRoute(report.reportID, reportAction.reportActionID)); + function setSplitBillTransaction(transactionChanges) { + console.log(reportAction.reportActionID); + IOU.setSplitBillTransaction(report.reportID, reportAction.reportActionID, transaction.transactionID, transactionChanges); + Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(report.reportID, reportAction.reportActionID)); } if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.DESCRIPTION) { @@ -90,7 +91,7 @@ function EditSplitBillRequestPage({report, reportActions, route}) { Navigation.dismissModal(); return; } - updateSplitBillTransaction({ + setSplitBillTransaction({ comment: transactionChanges.comment, }); }} @@ -102,12 +103,14 @@ function EditSplitBillRequestPage({report, reportActions, route}) { return ( { if (transactionChanges.created === transactionCreated) { Navigation.dismissModal(); return; } - updateSplitBillTransaction({ + setSplitBillTransaction({ created: transactionChanges.created, }); }} @@ -119,10 +122,8 @@ function EditSplitBillRequestPage({report, reportActions, route}) { return ( { const amount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(transactionChanges)); @@ -131,7 +132,7 @@ function EditSplitBillRequestPage({report, reportActions, route}) { return; } - updateSplitBillTransaction({ + setSplitBillTransaction({ amount, currency: defaultCurrency, }); @@ -149,7 +150,7 @@ function EditSplitBillRequestPage({report, reportActions, route}) { Navigation.goBack(); return; } - updateSplitBillTransaction({merchant: transactionChanges.merchant}); + setSplitBillTransaction({merchant: transactionChanges.merchant}); }} /> ); @@ -162,17 +163,9 @@ EditSplitBillRequestPage.displayName = 'EditSplitBillRequestPage'; EditSplitBillRequestPage.propTypes = propTypes; EditSplitBillRequestPage.defaultProps = defaultProps; export default compose( - withCurrentUserPersonalDetails, withOnyx({ report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, }, - reportActions: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${route.params.reportID}`, - canEvict: false, - }, - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, - }, }), )(EditSplitBillRequestPage); diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 28d4771cd863..8252f4ea0856 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -79,7 +79,7 @@ function SplitBillDetailsPage(props) { const {amount: splitAmount, currency: splitCurrency, comment: splitComment, merchant: splitMerchant, created: splitCreated} = ReportUtils.getTransactionDetails(transaction); const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); const canEditSplit = - props.session.accountID === reportAction.actorAccountID && (isScanning || (TransactionUtils.hasReceipt && transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED)); + props.session.accountID === reportAction.actorAccountID && (isScanning || (TransactionUtils.hasReceipt(transaction) && transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED)); return ( @@ -105,8 +105,11 @@ function SplitBillDetailsPage(props) { shouldShowSmartScanFields receiptPath={transaction.receipt && transaction.receipt.source} receiptFilename={transaction.filename} - isScanning={isScanning} shouldShowFooter={false} + isScanning={isScanning} + canEditSplit={canEditSplit} + reportActionID={reportAction.reportActionID} + reportID={props.report.reportID} /> )} From 8f3f42622c69b77829288dd956360e887ebf3060 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 9 Oct 2023 12:23:35 +0800 Subject: [PATCH 06/59] Save split transaction edits to a draft transaction --- src/ONYXKEYS.ts | 1 + .../MoneyRequestConfirmationList.js | 12 +++--- src/libs/actions/IOU.js | 38 ++++++++++++++----- src/pages/EditSplitBillPage.js | 31 ++++++++++----- src/pages/iou/SplitBillDetailsPage.js | 32 +++++++++++++--- 5 files changed, 83 insertions(+), 31 deletions(-) diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 0a17d3a1d2f7..96a6ce46f32e 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -252,6 +252,7 @@ const ONYXKEYS = { REPORT_USER_IS_LEAVING_ROOM: 'reportUserIsLeavingRoom_', SECURITY_GROUP: 'securityGroup_', TRANSACTION: 'transactions_', + DRAFT_SPLIT_TRANSACTION: 'draftSplitTransaction_', // Manual request tab selector SELECTED_TAB: 'selectedTab_', diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 0c5c217bb04d..8e8a5d9e820d 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -260,9 +260,9 @@ function MoneyRequestConfirmationList(props) { const splitOrRequestOptions = useMemo(() => { let text; - if (props.receiptPath && props.hasMultipleParticipants && props.iouAmount === 0) { + if (props.receiptPath && props.hasMultipleParticipants && props.isScanning && props.iouAmount === 0) { text = translate('iou.split'); - } else if (props.receiptPath || isDistanceRequestWithoutRoute) { + } else if ((props.receiptPath && props.iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST) || isDistanceRequestWithoutRoute) { text = translate('iou.request'); } else { const translationKey = props.hasMultipleParticipants ? 'iou.splitAmount' : 'iou.requestAmount'; @@ -511,7 +511,7 @@ function MoneyRequestConfirmationList(props) { if (props.isDistanceRequest) { return; } - if (props.canEditSplit) { + if (props.isEdittingSplitBill) { Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.AMOUNT)); return; } @@ -527,7 +527,7 @@ function MoneyRequestConfirmationList(props) { title={props.iouComment} description={translate('common.description')} onPress={() => { - if (props.canEditSplit) { + if (props.isEdittingSplitBill) { Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.DESCRIPTION)); return; } @@ -563,7 +563,7 @@ function MoneyRequestConfirmationList(props) { style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} onPress={() => { - if (props.canEditSplit) { + if (props.isEdittingSplitBill) { Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.DATE)); return; } @@ -591,7 +591,7 @@ function MoneyRequestConfirmationList(props) { style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} onPress={() => { - if (props.canEditSplit) { + if (props.isEdittingSplitBill) { Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.MERCHANT)); return; } diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index b99fd4743a48..99199f2a1df5 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -52,6 +52,20 @@ Onyx.connect({ }, }); +let allDraftSplitTransactions; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, + waitForCollectionCallback: true, + callback: (val) => { + if (!val) { + allDraftSplitTransactions = {}; + return; + } + + allDraftSplitTransactions = val; + }, +}); + let allRecentlyUsedCategories = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES, @@ -1471,21 +1485,24 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co Report.notifyNewAction(splitChatReport.chatReportID, currentUserAccountID); } +function completeSplitBill(updatedTransaction) {} + /** * @param {Number} reportID * @param {Number} reportActionID * @param {String} transactionID * @param {Object} transactionChanges */ -function setSplitBillTransaction(reportID, reportActionID, transactionID, transactionChanges) { - const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; - const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, false, false); - Onyx.merge(`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, updatedTransaction); - Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { - [reportActionID]: { - lastModified: DateUtils.getDBTime(), - }, - }); +function setDraftSplitTransaction(transactionID, transactionChanges = {}) { + let draftSplitTransaction = allDraftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`]; + + if (!draftSplitTransaction) { + draftSplitTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; + } + + const updatedTransaction = TransactionUtils.getUpdatedTransaction(draftSplitTransaction, transactionChanges, false, false); + + Onyx.merge(`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`, updatedTransaction); } /** @@ -2551,8 +2568,9 @@ export { deleteMoneyRequest, splitBill, splitBillAndOpenReport, + setDraftSplitTransaction, startSplitBill, - setSplitBillTransaction, + completeSplitBill, requestMoney, sendMoneyElsewhere, approveMoneyRequest, diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index f129640225a1..7ab6075e13b5 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -67,18 +67,24 @@ const defaultProps = { }, }; -function EditSplitBillRequestPage({report, route}) { +function EditSplitBillRequestPage({report, route, draftSplitTransactions}) { const fieldToEdit = lodashGet(route, ['params', 'field'], ''); const reportAction = ReportActionsUtils.getReportAction(report.reportID, lodashGet(route, ['params', 'reportActionID'], '')); - const transaction = TransactionUtils.getLinkedTransaction(reportAction); + const transactionID = TransactionUtils.getLinkedTransaction(reportAction).transactionID; + const draftSplitTransaction = draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`]; - const {amount: transactionAmount, currency: transactionCurrency, comment: transactionDescription, merchant: transactionMerchant} = ReportUtils.getTransactionDetails(transaction); + const { + amount: transactionAmount, + currency: transactionCurrency, + comment: transactionDescription, + merchant: transactionMerchant, + created: transactionCreated, + } = ReportUtils.getTransactionDetails(draftSplitTransaction); const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; - function setSplitBillTransaction(transactionChanges) { - console.log(reportAction.reportActionID); - IOU.setSplitBillTransaction(report.reportID, reportAction.reportActionID, transaction.transactionID, transactionChanges); + function setDraftSplitTransaction(transactionChanges) { + IOU.setDraftSplitTransaction(transactionID, transactionChanges); Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(report.reportID, reportAction.reportActionID)); } @@ -91,7 +97,7 @@ function EditSplitBillRequestPage({report, route}) { Navigation.dismissModal(); return; } - setSplitBillTransaction({ + setDraftSplitTransaction({ comment: transactionChanges.comment, }); }} @@ -110,7 +116,7 @@ function EditSplitBillRequestPage({report, route}) { Navigation.dismissModal(); return; } - setSplitBillTransaction({ + setDraftSplitTransaction({ created: transactionChanges.created, }); }} @@ -123,16 +129,18 @@ function EditSplitBillRequestPage({report, route}) { { const amount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(transactionChanges)); + console.log('new amount', amount); if (amount === transactionAmount && transactionCurrency === defaultCurrency) { Navigation.goBack(); return; } - setSplitBillTransaction({ + setDraftSplitTransaction({ amount, currency: defaultCurrency, }); @@ -150,7 +158,7 @@ function EditSplitBillRequestPage({report, route}) { Navigation.goBack(); return; } - setSplitBillTransaction({merchant: transactionChanges.merchant}); + setDraftSplitTransaction({merchant: transactionChanges.merchant}); }} /> ); @@ -167,5 +175,8 @@ export default compose( report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, }, + draftSplitTransactions: { + key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, + }, }), )(EditSplitBillRequestPage); diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 8252f4ea0856..811537774784 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -1,8 +1,9 @@ -import React from 'react'; +import React, {useCallback} from 'react'; import _ from 'underscore'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; +import lodashGet from 'lodash/get'; import styles from '../../styles/styles'; import ONYXKEYS from '../../ONYXKEYS'; import * as OptionsListUtils from '../../libs/OptionsListUtils'; @@ -20,6 +21,7 @@ import HeaderWithBackButton from '../../components/HeaderWithBackButton'; import * as TransactionUtils from '../../libs/TransactionUtils'; import * as ReportUtils from '../../libs/ReportUtils'; import MoneyRequestHeaderStatusBar from '../../components/MoneyRequestHeaderStatusBar'; +import * as IOU from '../../libs/actions/IOU'; const propTypes = { /* Onyx Props */ @@ -76,11 +78,27 @@ function SplitBillDetailsPage(props) { } const payeePersonalDetails = props.personalDetails[reportAction.actorAccountID]; const participantsExcludingPayee = _.filter(participants, (participant) => participant.accountID !== reportAction.actorAccountID); - const {amount: splitAmount, currency: splitCurrency, comment: splitComment, merchant: splitMerchant, created: splitCreated} = ReportUtils.getTransactionDetails(transaction); + const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); - const canEditSplit = + const isEdittingSplitBill = props.session.accountID === reportAction.actorAccountID && (isScanning || (TransactionUtils.hasReceipt(transaction) && transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED)); + const draftSplitTransaction = props.draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transaction.transactionID}`]; + + if (isEdittingSplitBill && !draftSplitTransaction) { + IOU.setDraftSplitTransaction(transaction.transactionID); + } + + const { + amount: splitAmount, + currency: splitCurrency, + comment: splitComment, + merchant: splitMerchant, + created: splitCreated, + } = isEdittingSplitBill && draftSplitTransaction ? ReportUtils.getTransactionDetails(draftSplitTransaction) : ReportUtils.getTransactionDetails(transaction); + + const onConfirm = useCallback(() => IOU.completeSplitBill(draftSplitTransaction)); + return ( @@ -101,15 +119,16 @@ function SplitBillDetailsPage(props) { iouCreated={splitCreated} iouMerchant={splitMerchant} iouType={CONST.IOU.MONEY_REQUEST_TYPE.SPLIT} - isReadOnly={!canEditSplit} + isReadOnly={!isEdittingSplitBill} shouldShowSmartScanFields receiptPath={transaction.receipt && transaction.receipt.source} receiptFilename={transaction.filename} shouldShowFooter={false} isScanning={isScanning} - canEditSplit={canEditSplit} + isEdittingSplitBill={isEdittingSplitBill} reportActionID={reportAction.reportActionID} reportID={props.report.reportID} + onConfirm={onConfirm} /> )} @@ -126,6 +145,9 @@ export default compose( withLocalize, withReportAndReportActionOrNotFound, withOnyx({ + draftSplitTransactions: { + key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, + }, personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS_LIST, }, From 60bca0ec107843ad5bb5d120e40988e3c90811b8 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 9 Oct 2023 15:27:09 +0800 Subject: [PATCH 07/59] Cleanup --- src/pages/EditSplitBillPage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index 7ab6075e13b5..a7eb61f4102c 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -133,7 +133,6 @@ function EditSplitBillRequestPage({report, route, draftSplitTransactions}) { isEdittingSplitBill onSubmit={(transactionChanges) => { const amount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(transactionChanges)); - console.log('new amount', amount); if (amount === transactionAmount && transactionCurrency === defaultCurrency) { Navigation.goBack(); From 914985f46a59dede41cd57f5e7208f3ce766874a Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 9 Oct 2023 17:56:41 +0800 Subject: [PATCH 08/59] Add useCallback dep --- src/pages/iou/SplitBillDetailsPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 811537774784..709fab0d83f0 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -83,7 +83,7 @@ function SplitBillDetailsPage(props) { const isEdittingSplitBill = props.session.accountID === reportAction.actorAccountID && (isScanning || (TransactionUtils.hasReceipt(transaction) && transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED)); - const draftSplitTransaction = props.draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transaction.transactionID}`]; + const draftSplitTransaction = props.draftSplitTransactions && props.draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transaction.transactionID}`]; if (isEdittingSplitBill && !draftSplitTransaction) { IOU.setDraftSplitTransaction(transaction.transactionID); @@ -97,7 +97,7 @@ function SplitBillDetailsPage(props) { created: splitCreated, } = isEdittingSplitBill && draftSplitTransaction ? ReportUtils.getTransactionDetails(draftSplitTransaction) : ReportUtils.getTransactionDetails(transaction); - const onConfirm = useCallback(() => IOU.completeSplitBill(draftSplitTransaction)); + const onConfirm = useCallback(() => IOU.completeSplitBill(draftSplitTransaction), [draftSplitTransaction]); return ( From b3c4a3e0a2558601d00eed01f2c31d98410b2a64 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 9 Oct 2023 17:58:48 +0800 Subject: [PATCH 09/59] Add proptype --- src/components/MoneyRequestConfirmationList.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 8e8a5d9e820d..4d1f0ec426fc 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -144,6 +144,9 @@ const propTypes = { /** Whether the receipt associated with this report is being scanned */ isScanning: PropTypes.bool, + /** Whether we should show the amount, date, and merchant fields. */ + shouldShowSmartScanFields: PropTypes.bool, + /* Onyx Props */ /** Collection of categories attached to a policy */ policyCategories: PropTypes.objectOf(categoryPropTypes), @@ -180,6 +183,7 @@ const defaultProps = { mileageRate: {unit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, rate: 0, currency: 'USD'}, isDistanceRequest: false, isScanning: false, + shouldShowSmartScanFields: true, }; function MoneyRequestConfirmationList(props) { From d62883cd577ad602e2011349bb27e1694a8b4a36 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 9 Oct 2023 21:05:55 +0800 Subject: [PATCH 10/59] Fix code removed by mistake --- src/components/MoneyRequestConfirmationList.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 4d1f0ec426fc..e55fd7428988 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -278,7 +278,7 @@ function MoneyRequestConfirmationList(props) { value: props.hasMultipleParticipants ? CONST.IOU.MONEY_REQUEST_TYPE.SPLIT : CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, }, ]; - }, [props.hasMultipleParticipants, props.iouAmount, props.receiptPath, translate, formattedAmount, isDistanceRequestWithoutRoute]); + }, [props.hasMultipleParticipants, props.iouType, props.iouAmount, props.receiptPath, props.isScanning, translate, formattedAmount, isDistanceRequestWithoutRoute]); const selectedParticipants = useMemo(() => _.filter(props.selectedParticipants, (participant) => participant.selected), [props.selectedParticipants]); const payeePersonalDetails = useMemo(() => props.payeePersonalDetails || props.currentUserPersonalDetails, [props.payeePersonalDetails, props.currentUserPersonalDetails]); @@ -519,6 +519,7 @@ function MoneyRequestConfirmationList(props) { Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.AMOUNT)); return; } + Navigation.navigate(ROUTES.MONEY_REQUEST_AMOUNT.getRoute(props.iouType, props.reportID)); }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} From 08d7577968ab4c130b077f7ce1ce7e1e8e66d657 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Mon, 9 Oct 2023 21:06:20 +0800 Subject: [PATCH 11/59] Bug fix and lint --- src/libs/actions/IOU.js | 6 +-- src/pages/EditSplitBillPage.js | 69 +++++++++++---------------- src/pages/iou/SplitBillDetailsPage.js | 5 ++ 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 99199f2a1df5..a5d872d703fd 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1485,11 +1485,11 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co Report.notifyNewAction(splitChatReport.chatReportID, currentUserAccountID); } -function completeSplitBill(updatedTransaction) {} +function completeSplitBill(updatedTransaction) { + console.log(updatedTransaction); +} /** - * @param {Number} reportID - * @param {Number} reportActionID * @param {String} transactionID * @param {Object} transactionChanges */ diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index a7eb61f4102c..5d5741da0116 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -1,4 +1,4 @@ -import React, {useEffect} from 'react'; +import React from 'react'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; @@ -7,19 +7,18 @@ import CONST from '../CONST'; import ROUTES from '../ROUTES'; import Navigation from '../libs/Navigation/Navigation'; import ONYXKEYS from '../ONYXKEYS'; +import reportPropTypes from './reportPropTypes'; +import transactionPropTypes from '../components/transactionPropTypes'; import * as ReportActionsUtils from '../libs/ReportActionsUtils'; import * as ReportUtils from '../libs/ReportUtils'; import * as TransactionUtils from '../libs/TransactionUtils'; -import * as Policy from '../libs/actions/Policy'; -import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../components/withCurrentUserPersonalDetails'; +import * as IOU from '../libs/actions/IOU'; +import * as CurrencyUtils from '../libs/CurrencyUtils'; +import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView'; import EditRequestDescriptionPage from './EditRequestDescriptionPage'; import EditRequestMerchantPage from './EditRequestMerchantPage'; import EditRequestCreatedPage from './EditRequestCreatedPage'; import EditRequestAmountPage from './EditRequestAmountPage'; -import reportPropTypes from './reportPropTypes'; -import * as IOU from '../libs/actions/IOU'; -import * as CurrencyUtils from '../libs/CurrencyUtils'; -import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView'; const propTypes = { /** Route from navigation */ @@ -37,41 +36,33 @@ const propTypes = { /** The report object for the thread report */ report: reportPropTypes, - /** The parent report object for the thread report */ - parentReport: reportPropTypes, - - /** The policy object for the current route */ - policy: PropTypes.shape({ - /** The name of the policy */ - name: PropTypes.string, - - /** The URL for the policy avatar */ - avatar: PropTypes.string, - }), + /** Used for retrieving the draft transaction of the split bill being edited */ + draftSplitTransactions: PropTypes.shape(transactionPropTypes), /** Session info for the currently logged in user. */ session: PropTypes.shape({ /** Currently logged in user email */ email: PropTypes.string, }), - - ...withCurrentUserPersonalDetailsPropTypes, }; const defaultProps = { report: {}, - parentReport: {}, - policy: null, session: { email: null, }, + draftSplitTransactions: {}, }; -function EditSplitBillRequestPage({report, route, draftSplitTransactions}) { +function EditSplitBillPage({report, route, draftSplitTransactions}) { const fieldToEdit = lodashGet(route, ['params', 'field'], ''); const reportAction = ReportActionsUtils.getReportAction(report.reportID, lodashGet(route, ['params', 'reportActionID'], '')); - const transactionID = TransactionUtils.getLinkedTransaction(reportAction).transactionID; - const draftSplitTransaction = draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`]; + const transaction = TransactionUtils.getLinkedTransaction(reportAction); + + let draftSplitTransaction = draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transaction.transactionID}`]; + if (!draftSplitTransaction) { + IOU.setDraftSplitTransaction(transaction.transactionID); + } const { amount: transactionAmount, @@ -79,12 +70,12 @@ function EditSplitBillRequestPage({report, route, draftSplitTransactions}) { comment: transactionDescription, merchant: transactionMerchant, created: transactionCreated, - } = ReportUtils.getTransactionDetails(draftSplitTransaction); + } = draftSplitTransaction ? ReportUtils.getTransactionDetails(draftSplitTransaction) : ReportUtils.getTransactionDetails(transaction); const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; function setDraftSplitTransaction(transactionChanges) { - IOU.setDraftSplitTransaction(transactionID, transactionChanges); + IOU.setDraftSplitTransaction(transaction.transactionID, transactionChanges); Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(report.reportID, reportAction.reportActionID)); } @@ -166,16 +157,14 @@ function EditSplitBillRequestPage({report, route, draftSplitTransactions}) { return ; } -EditSplitBillRequestPage.displayName = 'EditSplitBillRequestPage'; -EditSplitBillRequestPage.propTypes = propTypes; -EditSplitBillRequestPage.defaultProps = defaultProps; -export default compose( - withOnyx({ - report: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, - }, - draftSplitTransactions: { - key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, - }, - }), -)(EditSplitBillRequestPage); +EditSplitBillPage.displayName = 'EditSplitBillPage'; +EditSplitBillPage.propTypes = propTypes; +EditSplitBillPage.defaultProps = defaultProps; +export default withOnyx({ + report: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, + }, + draftSplitTransactions: { + key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, + }, +})(EditSplitBillPage); diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 709fab0d83f0..23a9d8abb725 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -14,6 +14,7 @@ import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize import compose from '../../libs/compose'; import reportActionPropTypes from '../home/report/reportActionPropTypes'; import reportPropTypes from '../reportPropTypes'; +import transactionPropTypes from '../../components/transactionPropTypes'; import withReportAndReportActionOrNotFound from '../home/report/withReportAndReportActionOrNotFound'; import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView'; import CONST from '../../CONST'; @@ -35,6 +36,9 @@ const propTypes = { /** Array of report actions for this report */ reportActions: PropTypes.shape(reportActionPropTypes), + /** Used for retrieving the draft transaction of the split bill being edited */ + draftSplitTransactions: PropTypes.shape(transactionPropTypes), + /** Route params */ route: PropTypes.shape({ params: PropTypes.shape({ @@ -58,6 +62,7 @@ const propTypes = { const defaultProps = { personalDetails: {}, reportActions: {}, + draftSplitTransactions: {}, }; function SplitBillDetailsPage(props) { From f516e3b3d64cbe27d3cb01752071713271199994 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 10 Oct 2023 00:11:02 +0800 Subject: [PATCH 12/59] wip --- src/libs/actions/IOU.js | 81 ++++++++++++++++++++++++++- src/pages/iou/SplitBillDetailsPage.js | 2 +- 2 files changed, 80 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index a5d872d703fd..dc5e28820a53 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1485,8 +1485,85 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co Report.notifyNewAction(splitChatReport.chatReportID, currentUserAccountID); } -function completeSplitBill(updatedTransaction) { - console.log(updatedTransaction); +function completeSplitBill(chatReportID, reportAction, updatedTransaction, currentUserAccountID, currentUserEmail) { + // Save optimistic updated transaction and action + const optimisticData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${updatedTransaction.transactionID}`, + value: updatedTransaction, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, + value: { + [reportActionID]: { + ...reportAction, + lastModified: DateUtils.getDBTime(), + whisperedToAccountIDs: [], + }, + }, + }, + ]; + + const splitParticipants = transaction.comment.splits; + const {modifiedAmount: amount, modifiedCurrency: currency} = splitTransaction; + const splitAmount = IOUUtils.calculateAmount(splitParticipants.length, amount, currency, false); + const splits = []; + _.eacch(splitParticipants, (participant) => { + // Skip creating the transaction for the current user + if (participant.email && participant.email === currentUserEmail) { + return; + } + const isPolicyExpenseChat = !_.isEmpty(participant.policyID); + let oneOnOneChatReport; + if (isPolicyExpenseChat) { + // The workspace chat reportID is saved in the splits array when starting a split bill with a workspace + oneOnOneChatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]; + } else { + oneOnOneChatReport = ReportUtils.getChatByParticipants([participant.accountID] || ReportUtils.buildOptimisticChatReport([participant.accountID])); + } + + let oneOnOneIOUReport = lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`, undefined); + const shouldCreateNewOneOnOneIOUReport = + _.isUndefined(oneOnOneIOUReport) || (isPolicyExpenseChat && ReportUtils.isControlPolicyExpenseReport(oneOnOneIOUReport) && ReportUtils.isReportApproved(oneOnOneIOUReport)); + + if (shouldCreateNewOneOnOneIOUReport) { + oneOnOneIOUReport = isPolicyExpenseChat + ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, participant.policyID, currentUserAccountID, splitAmount, currency) + : ReportUtils.buildOptimisticIOUReport(currentUserAccountID, participant.accountID, splitAmount, oneOnOneChatReport.reportID, currency); + } else if (isOwnPolicyExpenseChat) { + // Because of the Expense reports are stored as negative values, we subtract the total from the amount + oneOnOneIOUReport.total -= splitAmount; + } else { + oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, currentUserAccountID, splitAmount, currency); + } + + const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( + isPolicyExpenseChat ? -splitAmount : splitAmount, + currency, + oneOnOneIOUReport.reportID, + updatedTransaction.comment, + '', + CONST.IOU.MONEY_REQUEST_TYPE.SPLIT, + updatedTransaction.transactionID, + ); + + const oneOnOneCreatedActionForChat = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit); + const oneOnOneCreatedActionForIOU = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit); + const oneOnOneIOUAction = ReportUtils.buildOptimisticIOUReportAction( + CONST.IOU.REPORT_ACTION_TYPE.CREATE, + splitAmount, + currency, + comment, + [participant], + oneOnOneTransaction.transactionID, + '', + oneOnOneIOUReport.reportID, + ); + }); + + // Loop over participants and generate optimistic 1on1 chats and IOU reports, if workspace chat, generate optimistic expense report } /** diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 23a9d8abb725..6fa9c225d91e 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -102,7 +102,7 @@ function SplitBillDetailsPage(props) { created: splitCreated, } = isEdittingSplitBill && draftSplitTransaction ? ReportUtils.getTransactionDetails(draftSplitTransaction) : ReportUtils.getTransactionDetails(transaction); - const onConfirm = useCallback(() => IOU.completeSplitBill(draftSplitTransaction), [draftSplitTransaction]); + const onConfirm = useCallback(() => IOU.completeSplitBill(props.report.reportID, reportAction, draftSplitTransaction), [props.report.reportID, reportAction, draftSplitTransaction]); return ( From 4096fe2df2acaafbeba0b7339ed737f95385c9f8 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 10 Oct 2023 18:08:37 +0800 Subject: [PATCH 13/59] Remove deprecated method and use withOnyx --- src/pages/iou/SplitBillDetailsPage.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index e77345e0f2d3..cecc2f4154c0 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -67,7 +67,8 @@ const defaultProps = { function SplitBillDetailsPage(props) { const reportAction = props.reportActions[`${props.route.params.reportActionID.toString()}`]; - const transaction = TransactionUtils.getLinkedTransaction(reportAction); + const transactionID = reportAction.originalMessage.IOUTransactionID; + const transaction = props.allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const participantAccountIDs = reportAction.originalMessage.participantAccountIDs; // In case this is workspace split bill, we manually add the workspace as the second participant of the split bill @@ -88,7 +89,7 @@ function SplitBillDetailsPage(props) { const isEdittingSplitBill = props.session.accountID === reportAction.actorAccountID && (isScanning || (TransactionUtils.hasReceipt(transaction) && transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED)); - const draftSplitTransaction = props.draftSplitTransactions && props.draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transaction.transactionID}`]; + const draftSplitTransaction = props.draftSplitTransactions && props.draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`]; if (isEdittingSplitBill && !draftSplitTransaction) { IOU.setDraftSplitTransaction(transaction.transactionID); @@ -152,6 +153,9 @@ export default compose( withLocalize, withReportAndReportActionOrNotFound, withOnyx({ + allTransactions: { + key: ONYXKEYS.COLLECTION.TRANSACTION, + }, draftSplitTransactions: { key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, }, From dd6910514b099a9da06bd50fbf21d8b8f0c027e1 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 10 Oct 2023 22:51:50 +0800 Subject: [PATCH 14/59] Add completeSplitBill action --- src/libs/actions/IOU.js | 112 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 102 insertions(+), 10 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 346692a4a858..c560d985048a 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1476,6 +1476,16 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co }); }); + optimisticData.push({ + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`, + value: { + comment: { + splits, + }, + }, + }); + API.write( 'StartSplitBill', { @@ -1497,19 +1507,25 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co } function completeSplitBill(chatReportID, reportAction, updatedTransaction, currentUserAccountID, currentUserEmail) { + const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserEmail); + // Save optimistic updated transaction and action const optimisticData = [ { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${updatedTransaction.transactionID}`, - value: updatedTransaction, + value: { + receipt: { + ...updatedTransaction.receipt, + state: CONST.IOU.RECEIPT_STATE.OPEN, + }, + }, }, { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, value: { - [reportActionID]: { - ...reportAction, + [reportAction.reportActionID]: { lastModified: DateUtils.getDBTime(), whisperedToAccountIDs: [], }, @@ -1517,22 +1533,44 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre }, ]; - const splitParticipants = transaction.comment.splits; - const {modifiedAmount: amount, modifiedCurrency: currency} = splitTransaction; + const successData = []; + + const failureData = []; + + const splitParticipants = updatedTransaction.comment.splits; + const {modifiedAmount: amount, modifiedCurrency: currency} = updatedTransaction; const splitAmount = IOUUtils.calculateAmount(splitParticipants.length, amount, currency, false); const splits = []; - _.eacch(splitParticipants, (participant) => { + _.each(splitParticipants, (participant) => { // Skip creating the transaction for the current user if (participant.email && participant.email === currentUserEmail) { return; } const isPolicyExpenseChat = !_.isEmpty(participant.policyID); + + if (!isPolicyExpenseChat) { + // In case this is still the optimistic accountID saved in the splits array, return early as we cannot know + // if there is an existing chat between the split creator and this participant + // Instead, we will rely on Auth generating the report IDs and the user won't see any optimistic chats or reports created + const participantPersonalDetails = allPersonalDetails[participant.accountID] || {}; + if (!participantPersonalDetails || participantPersonalDetails.isOptimisticPersonalDetail) { + splits.push({ + email: participant.email, + }); + console.log('returning cause no personal details of this participant'); + return; + } + } + let oneOnOneChatReport; + let isNewOneOnOneChatReport = false; if (isPolicyExpenseChat) { // The workspace chat reportID is saved in the splits array when starting a split bill with a workspace oneOnOneChatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]; } else { - oneOnOneChatReport = ReportUtils.getChatByParticipants([participant.accountID] || ReportUtils.buildOptimisticChatReport([participant.accountID])); + let existingChatReport = ReportUtils.getChatByParticipants([participant.accountID]); + isNewOneOnOneChatReport = !existingChatReport; + oneOnOneChatReport = existingChatReport || ReportUtils.buildOptimisticChatReport([participant.accountID]); } let oneOnOneIOUReport = lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${oneOnOneChatReport.iouReportID}`, undefined); @@ -1555,9 +1593,12 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre currency, oneOnOneIOUReport.reportID, updatedTransaction.comment, - '', + updatedTransaction.created, CONST.IOU.MONEY_REQUEST_TYPE.SPLIT, updatedTransaction.transactionID, + updatedTransaction.merchant, + updatedTransaction.receipt, + updatedTransaction.filename, ); const oneOnOneCreatedActionForChat = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit); @@ -1566,15 +1607,66 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre CONST.IOU.REPORT_ACTION_TYPE.CREATE, splitAmount, currency, - comment, + updatedTransaction.modifiedComment, [participant], oneOnOneTransaction.transactionID, '', oneOnOneIOUReport.reportID, ); + + let oneOnOneReportPreviewAction = ReportActionsUtils.getReportPreviewAction(oneOnOneChatReport.reportID, oneOnOneIOUReport.reportID); + if (oneOnOneReportPreviewAction) { + oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); + } else { + oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport); + } + + const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( + oneOnOneChatReport, + oneOnOneIOUReport, + oneOnOneTransaction, + oneOnOneCreatedActionForChat, + oneOnOneCreatedActionForIOU, + oneOnOneIOUAction, + {}, + oneOnOneReportPreviewAction, + {}, + {}, + isNewOneOnOneChatReport, + shouldCreateNewOneOnOneIOUReport, + ); + + splits.push({ + email: participant.email, + accountID: participant.accountID, + policyID: participant.policyID, + iouReportID: oneOnOneIOUReport.reportID, + chatReportID: oneOnOneChatReport.reportID, + transactionID: oneOnOneTransaction.transactionID, + reportActionID: oneOnOneIOUAction.reportActionID, + createdChatReportActionID: oneOnOneCreatedActionForChat.reportActionID, + createdIOUReportActionID: oneOnOneCreatedActionForIOU.reportActionID, + reportPreviewReportActionID: oneOnOneReportPreviewAction.reportActionID, + }); + + optimisticData.push(...oneOnOneOptimisticData); + successData.push(...oneOnOneSuccessData); + failureData.push(...oneOnOneFailureData); }); - // Loop over participants and generate optimistic 1on1 chats and IOU reports, if workspace chat, generate optimistic expense report + console.log(updatedTransaction); + API.write( + 'CompleteSplitBill', + { + transactionID: updatedTransaction.transactionID, + amount: updatedTransaction.modifiedAmount, + currency: updatedTransaction.modifiedCurrency, + created: updatedTransaction.modifiedCreated, + merchant: updatedTransaction.modifiedMerchant, + comment: updatedTransaction.comment.comment, + }, + {optimisticData, successData, failureData}, + ); } /** From 46b6398fde0e537b56bddfe904b0a5092b8f8f70 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 10 Oct 2023 23:12:12 +0800 Subject: [PATCH 15/59] Send necessary params to completeSplitBill --- src/pages/iou/SplitBillDetailsPage.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index cecc2f4154c0..434effd61313 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -104,7 +104,10 @@ function SplitBillDetailsPage(props) { category: splitCategory, } = isEdittingSplitBill && draftSplitTransaction ? ReportUtils.getTransactionDetails(draftSplitTransaction) : ReportUtils.getTransactionDetails(transaction); - const onConfirm = useCallback(() => IOU.completeSplitBill(props.report.reportID, reportAction, draftSplitTransaction), [props.report.reportID, reportAction, draftSplitTransaction]); + const onConfirm = useCallback( + () => IOU.completeSplitBill(props.report.reportID, reportAction, draftSplitTransaction, props.session.accountID, props.session.email), + [props.report.reportID, reportAction, draftSplitTransaction, props.session.accountID, props.session.email], + ); return ( From f134e3f605a8b86f21fc37393fc70d8d40e80d2d Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Tue, 10 Oct 2023 23:15:57 +0800 Subject: [PATCH 16/59] Show right icon next to all fields in split details --- src/components/MoneyRequestConfirmationList.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 6d563a4eb993..b1f6ef33bddc 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -563,7 +563,7 @@ function MoneyRequestConfirmationList(props) { <> {props.shouldShowSmartScanFields && ( Navigation.navigate(ROUTES.MONEY_REQUEST_CATEGORY.getRoute(props.iouType, props.reportID))} style={[styles.moneyRequestMenuItem]} - disabled={didConfirm || props.isReadOnly} + disabled={didConfirm} /> )} {shouldShowTags && ( From 01d37b71c87e60baf67ea4ee8f4f8702a8dd2805 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 00:13:28 +0800 Subject: [PATCH 17/59] Fix a few bugs --- src/libs/ReportUtils.js | 2 ++ src/libs/actions/IOU.js | 18 ++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 591656b5c06a..30a074bcbfba 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2412,7 +2412,9 @@ function buildOptimisticSubmittedReportAction(amount, currency, expenseReportID) */ function buildOptimisticReportPreview(chatReport, iouReport, comment = '', transaction = undefined) { const hasReceipt = TransactionUtils.hasReceipt(transaction); + console.log('building optimistic report preview, has receipt', hasReceipt); const isReceiptBeingScanned = hasReceipt && TransactionUtils.isReceiptBeingScanned(transaction); + console.log('is receipt being scanned', isReceiptBeingScanned); const message = getReportPreviewMessage(iouReport); return { reportActionID: NumberUtils.rand64(), diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index c560d985048a..c6a35b5677e5 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1515,8 +1515,8 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.TRANSACTION}${updatedTransaction.transactionID}`, value: { + ...updatedTransaction, receipt: { - ...updatedTransaction.receipt, state: CONST.IOU.RECEIPT_STATE.OPEN, }, }, @@ -1539,7 +1539,10 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre const splitParticipants = updatedTransaction.comment.splits; const {modifiedAmount: amount, modifiedCurrency: currency} = updatedTransaction; - const splitAmount = IOUUtils.calculateAmount(splitParticipants.length, amount, currency, false); + + // Exclude the current user when calculating the split amount, `calculateAmount` takes it into account + const splitAmount = IOUUtils.calculateAmount(splitParticipants.length - 1, amount, currency, false); + const splits = []; _.each(splitParticipants, (participant) => { // Skip creating the transaction for the current user @@ -1557,7 +1560,6 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre splits.push({ email: participant.email, }); - console.log('returning cause no personal details of this participant'); return; } } @@ -1593,11 +1595,11 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre currency, oneOnOneIOUReport.reportID, updatedTransaction.comment, - updatedTransaction.created, + updatedTransaction.modifiedCreated, CONST.IOU.MONEY_REQUEST_TYPE.SPLIT, updatedTransaction.transactionID, - updatedTransaction.merchant, - updatedTransaction.receipt, + updatedTransaction.modifiedMerchant, + {...updatedTransaction.receipt, state: CONST.IOU.RECEIPT_STATE.OPEN}, updatedTransaction.filename, ); @@ -1618,7 +1620,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre if (oneOnOneReportPreviewAction) { oneOnOneReportPreviewAction = ReportUtils.updateReportPreview(oneOnOneIOUReport, oneOnOneReportPreviewAction); } else { - oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport); + oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport, '', oneOnOneTransaction); } const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest( @@ -1654,7 +1656,6 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre failureData.push(...oneOnOneFailureData); }); - console.log(updatedTransaction); API.write( 'CompleteSplitBill', { @@ -1664,6 +1665,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre created: updatedTransaction.modifiedCreated, merchant: updatedTransaction.modifiedMerchant, comment: updatedTransaction.comment.comment, + splits: JSON.stringify(splits), }, {optimisticData, successData, failureData}, ); From 5ad7a0affc77f6127894fcb0f2c820a7431ee28c Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 02:02:22 +0800 Subject: [PATCH 18/59] Cleanup --- src/libs/ReportUtils.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 054b051a352b..b5fc0bff6ec7 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2408,9 +2408,7 @@ function buildOptimisticSubmittedReportAction(amount, currency, expenseReportID) */ function buildOptimisticReportPreview(chatReport, iouReport, comment = '', transaction = undefined) { const hasReceipt = TransactionUtils.hasReceipt(transaction); - console.log('building optimistic report preview, has receipt', hasReceipt); const isReceiptBeingScanned = hasReceipt && TransactionUtils.isReceiptBeingScanned(transaction); - console.log('is receipt being scanned', isReceiptBeingScanned); const message = getReportPreviewMessage(iouReport); return { reportActionID: NumberUtils.rand64(), From 322e20f6687f53cb42cd766613761ff2c26b6b99 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 02:02:54 +0800 Subject: [PATCH 19/59] Update src/libs/TransactionUtils.ts Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- src/libs/TransactionUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index e0402140ef5e..ac9c9623a74c 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -96,7 +96,7 @@ function areRequiredFieldsEmpty(transaction: Transaction): boolean { /** * Given the edit made to the money request, return an updated transaction object. */ -function getUpdatedTransaction(transaction: Transaction, transactionChanges: TransactionChanges, isFromExpenseReport: boolean, shouldUpdateReceiptState: boolean = true): Transaction { +function getUpdatedTransaction(transaction: Transaction, transactionChanges: TransactionChanges, isFromExpenseReport: boolean, shouldUpdateReceiptState = true): Transaction { // Only changing the first level fields so no need for deep clone now const updatedTransaction = {...transaction}; let shouldStopSmartscan = false; From 11883ed562e054ef5bd797c07b1aac5153a21dff Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 02:24:34 +0800 Subject: [PATCH 20/59] Add nagivation to editting currency route --- src/pages/EditRequestAmountPage.js | 13 +++++-------- src/pages/EditRequestPage.js | 5 +++++ src/pages/EditSplitBillPage.js | 15 +++++++++++++-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/pages/EditRequestAmountPage.js b/src/pages/EditRequestAmountPage.js index 8d3fb05e8e90..82c288d62db9 100644 --- a/src/pages/EditRequestAmountPage.js +++ b/src/pages/EditRequestAmountPage.js @@ -19,11 +19,14 @@ const propTypes = { /** Callback to fire when the Save button is pressed */ onSubmit: PropTypes.func.isRequired, + /** Callback to fire when we press on the currency */ + onNavigateToCurrency: PropTypes.func.isRequired, + /** reportID for the transaction thread */ reportID: PropTypes.string.isRequired, }; -function EditRequestAmountPage({defaultAmount, defaultCurrency, reportID, reportActionID, onSubmit}) { +function EditRequestAmountPage({defaultAmount, defaultCurrency, onNavigateToCurrency, onSubmit}) { const {translate} = useLocalize(); const textInput = useRef(null); @@ -39,12 +42,6 @@ function EditRequestAmountPage({defaultAmount, defaultCurrency, reportID, report }); }; - const navigateToCurrencySelectionPage = () => { - // Remove query from the route and encode it. - const activeRoute = encodeURIComponent(Navigation.getActiveRoute().replace(/\?.*/, '')); - Navigation.navigate(ROUTES.EDIT_CURRENCY_REQUEST.getRoute(reportID, defaultCurrency, activeRoute)); - }; - useFocusEffect( useCallback(() => { focusTextInput(); @@ -63,7 +60,7 @@ function EditRequestAmountPage({defaultAmount, defaultCurrency, reportID, report currency={defaultCurrency} amount={defaultAmount} ref={(e) => (textInput.current = e)} - onCurrencyButtonPress={navigateToCurrencySelectionPage} + onCurrencyButtonPress={onNavigateToCurrency} onSubmitButtonPress={onSubmit} /> diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index 28e70dc1a47e..7980404f58a2 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -5,6 +5,7 @@ import lodashValues from 'lodash/values'; import {withOnyx} from 'react-native-onyx'; import CONST from '../CONST'; import ONYXKEYS from '../ONYXKEYS'; +import ROUTES from '../ROUTES'; import compose from '../libs/compose'; import Navigation from '../libs/Navigation/Navigation'; import * as ReportActionsUtils from '../libs/ReportActionsUtils'; @@ -199,6 +200,10 @@ function EditRequestPage({betas, report, route, parentReport, policy, session, p currency: defaultCurrency, }); }} + onNavigateToCurrency={() => { + const activeRoute = encodeURIComponent(Navigation.getActiveRoute().replace(/\?.*/, '')); + Navigation.navigate(ROUTES.EDIT_CURRENCY_REQUEST.getRoute(report.reportID, defaultCurrency, activeRoute)); + }} /> ); } diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index 5d5741da0116..8f529c0918ec 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -36,6 +36,9 @@ const propTypes = { /** The report object for the thread report */ report: reportPropTypes, + /** All the transactions */ + transactions: PropTypes.shape(transactionPropTypes), + /** Used for retrieving the draft transaction of the split bill being edited */ draftSplitTransactions: PropTypes.shape(transactionPropTypes), @@ -52,12 +55,13 @@ const defaultProps = { email: null, }, draftSplitTransactions: {}, + transactions: {}, }; -function EditSplitBillPage({report, route, draftSplitTransactions}) { +function EditSplitBillPage({report, route, transactions, draftSplitTransactions}) { const fieldToEdit = lodashGet(route, ['params', 'field'], ''); const reportAction = ReportActionsUtils.getReportAction(report.reportID, lodashGet(route, ['params', 'reportActionID'], '')); - const transaction = TransactionUtils.getLinkedTransaction(reportAction); + const transaction = transactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${reportAction.originalMessage.IOUTransactionID}`]; let draftSplitTransaction = draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transaction.transactionID}`]; if (!draftSplitTransaction) { @@ -135,6 +139,10 @@ function EditSplitBillPage({report, route, draftSplitTransactions}) { currency: defaultCurrency, }); }} + onNavigateToCurrency={() => { + const activeRoute = encodeURIComponent(Navigation.getActiveRoute().replace(/\?.*/, '')); + Navigation.navigate(ROUTES.EDIT_SPLIT_BILL_CURRENCY.getRoute(report.reportID, reportAction.reportActionID, defaultCurrency, activeRoute)); + }} /> ); } @@ -164,6 +172,9 @@ export default withOnyx({ report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, }, + transactions: { + key: ONYXKEYS.COLLECTION.TRANSACTION, + }, draftSplitTransactions: { key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, }, From 20be465b05111c04ef42302dc736337969df3733 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 02:36:35 +0800 Subject: [PATCH 21/59] Add success & failure data to original transaction --- src/libs/actions/IOU.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 47ecfae7be54..2e18265dc2cc 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1537,9 +1537,23 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre }, ]; - const successData = []; + const successData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${updatedTransaction.transactionID}`, + value: {pendingAction: null}, + }, + ]; - const failureData = []; + const failureData = [ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${updatedTransaction.transactionID}`, + value: { + errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + }, + }, + ]; const splitParticipants = updatedTransaction.comment.splits; const {modifiedAmount: amount, modifiedCurrency: currency} = updatedTransaction; From 1e715023596d07497a92c9c22d748bd3536f467d Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 13:31:06 +0800 Subject: [PATCH 22/59] Cleanup splitOrRequestOptions --- src/components/MoneyRequestConfirmationList.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index b7d6bff535e8..d12fffb0b5fe 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -197,6 +197,7 @@ function MoneyRequestConfirmationList(props) { const {translate, toLocaleDigit} = useLocalize(); const isTypeRequest = props.iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST; + const isSplitBill = props.iouType === CONST.IOU.MONEY_REQUEST_TYPE.SPLIT; const {unit, rate, currency} = props.mileageRate; const distance = lodashGet(transaction, 'routes.route0.distance', 0); @@ -266,21 +267,21 @@ function MoneyRequestConfirmationList(props) { const splitOrRequestOptions = useMemo(() => { let text; - if (props.receiptPath && props.hasMultipleParticipants && props.isScanning && props.iouAmount === 0) { + if (isSplitBill && props.iouAmount === 0) { text = translate('iou.split'); - } else if ((props.receiptPath && props.iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST) || isDistanceRequestWithoutRoute) { + } else if ((props.receiptPath && isTypeRequest) || isDistanceRequestWithoutRoute) { text = translate('iou.request'); } else { - const translationKey = props.hasMultipleParticipants ? 'iou.splitAmount' : 'iou.requestAmount'; + const translationKey = isSplitBill ? 'iou.splitAmount' : 'iou.requestAmount'; text = translate(translationKey, {amount: formattedAmount}); } return [ { text: text[0].toUpperCase() + text.slice(1), - value: props.hasMultipleParticipants ? CONST.IOU.MONEY_REQUEST_TYPE.SPLIT : CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, + value: props.iouType, }, ]; - }, [props.hasMultipleParticipants, props.iouType, props.iouAmount, props.receiptPath, props.isScanning, translate, formattedAmount, isDistanceRequestWithoutRoute]); + }, [isSplitBill, isTypeRequest, props.iouAmount, props.receiptPathtranslate, formattedAmount, isDistanceRequestWithoutRoute]); const selectedParticipants = useMemo(() => _.filter(props.selectedParticipants, (participant) => participant.selected), [props.selectedParticipants]); const payeePersonalDetails = useMemo(() => props.payeePersonalDetails || props.currentUserPersonalDetails, [props.payeePersonalDetails, props.currentUserPersonalDetails]); From e3dc9413bf1c12464f284b7a3db7629ca9f8611a Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 13:32:48 +0800 Subject: [PATCH 23/59] Fix typo --- src/components/MoneyRequestConfirmationList.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index d12fffb0b5fe..2474abd32e1a 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -209,7 +209,7 @@ function MoneyRequestConfirmationList(props) { // A flag and a toggler for showing the rest of the form fields const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false); - const shouldShowAllFields = props.isDistanceRequest || shouldExpandFields || props.isEdittingSplitBill || !props.shouldShowSmartScanFields; + const shouldShowAllFields = props.isDistanceRequest || shouldExpandFields || props.isEditingSplitBill || !props.shouldShowSmartScanFields; // Fetches the first tag list of the policy const policyTag = PolicyUtils.getTag(props.policyTags); @@ -520,7 +520,7 @@ function MoneyRequestConfirmationList(props) { if (props.isDistanceRequest) { return; } - if (props.isEdittingSplitBill) { + if (props.isEditingSplitBill) { Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.AMOUNT)); return; } @@ -537,7 +537,7 @@ function MoneyRequestConfirmationList(props) { title={props.iouComment} description={translate('common.description')} onPress={() => { - if (props.isEdittingSplitBill) { + if (props.isEditingSplitBill) { Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.DESCRIPTION)); return; } @@ -573,7 +573,7 @@ function MoneyRequestConfirmationList(props) { style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} onPress={() => { - if (props.isEdittingSplitBill) { + if (props.isEditingSplitBill) { Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.DATE)); return; } @@ -601,7 +601,7 @@ function MoneyRequestConfirmationList(props) { style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} onPress={() => { - if (props.isEdittingSplitBill) { + if (props.isEditingSplitBill) { Navigation.navigate(ROUTES.EDIT_SPLIT_BILL.getRoute(props.reportID, props.reportActionID, CONST.EDIT_REQUEST_FIELD.MERCHANT)); return; } From 45d90fba9f605e9493146bbce8eaf5b5c82eed80 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 13:38:01 +0800 Subject: [PATCH 24/59] Apply suggestions from code review Co-authored-by: Abdelhafidh Belalia <16493223+s77rt@users.noreply.github.com> --- src/ROUTES.ts | 4 ++-- src/libs/actions/IOU.js | 13 ++++--------- src/pages/EditSplitBillPage.js | 6 +++--- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 165fda46df2b..c006148242d5 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -167,11 +167,11 @@ export default { }, EDIT_SPLIT_BILL: { route: `r/:reportID/split/:reportActionID/edit/:field`, - getRoute: (reportID: number, reportActionID: number, field: ValueOf) => `r/${reportID}/split/${reportActionID}/edit/${field}`, + getRoute: (reportID: string, reportActionID: string, field: ValueOf) => `r/${reportID}/split/${reportActionID}/edit/${field}`, }, EDIT_SPLIT_BILL_CURRENCY: { route: 'r/:reportID/split/:reportActionID/edit/currency', - getRoute: (reportID: number, reportActionID: number, currency: string, backTo: string) => `r/${reportID}/split/${reportActionID}/edit/currency?currency=${currency}&backTo=${backTo}`, + getRoute: (reportID: string, reportActionID: string, currency: string, backTo: string) => `r/${reportID}/split/${reportActionID}/edit/currency?currency=${currency}&backTo=${backTo}`, }, TASK_TITLE: { route: 'r/:reportID/title', diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 2e18265dc2cc..864151f8f258 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -58,12 +58,7 @@ Onyx.connect({ key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, waitForCollectionCallback: true, callback: (val) => { - if (!val) { - allDraftSplitTransactions = {}; - return; - } - - allDraftSplitTransactions = val; + allDraftSplitTransactions = val || {}; }, }); @@ -1564,7 +1559,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre const splits = []; _.each(splitParticipants, (participant) => { // Skip creating the transaction for the current user - if (participant.email && participant.email === currentUserEmail) { + if (participant.email === currentUserEmailForIOUSplit) { return; } const isPolicyExpenseChat = !_.isEmpty(participant.policyID); @@ -1612,7 +1607,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre isPolicyExpenseChat ? -splitAmount : splitAmount, currency, oneOnOneIOUReport.reportID, - updatedTransaction.comment, + updatedTransaction.comment.comment, updatedTransaction.modifiedCreated, CONST.IOU.MONEY_REQUEST_TYPE.SPLIT, updatedTransaction.transactionID, @@ -1627,7 +1622,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre CONST.IOU.REPORT_ACTION_TYPE.CREATE, splitAmount, currency, - updatedTransaction.modifiedComment, + updatedTransaction.comment.comment, [participant], oneOnOneTransaction.transactionID, '', diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index 8f529c0918ec..e3a4fa4563b3 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -29,7 +29,7 @@ const propTypes = { field: PropTypes.string, /** reportID for the "transaction thread" */ - threadReportID: PropTypes.string, + reportActionID: PropTypes.string, }), }).isRequired, @@ -88,12 +88,12 @@ function EditSplitBillPage({report, route, transactions, draftSplitTransactions} { - if (transactionChanges.comment === transactionDescription) { + if (transactionChanges.comment.trim() === transactionDescription) { Navigation.dismissModal(); return; } setDraftSplitTransaction({ - comment: transactionChanges.comment, + comment: transactionChanges.comment.trim(), }); }} /> From 3231d675e49bdf551968527030e5578df7d876a1 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 13:48:27 +0800 Subject: [PATCH 25/59] Add failure data reverting changes made in optimistic data --- .../MoneyRequestConfirmationList.js | 5 +++ src/libs/actions/IOU.js | 33 ++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 2474abd32e1a..bdc6a3b96d27 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -265,6 +265,11 @@ function MoneyRequestConfirmationList(props) { const [didConfirm, setDidConfirm] = useState(false); + // If completing a split bill fails, set didConfirm to false to allow the user to edit the fields again + if (props.isEditingSplitBill && didConfirm) { + setDidConfirm(false); + } + const splitOrRequestOptions = useMemo(() => { let text; if (isSplitBill && props.iouAmount === 0) { diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 864151f8f258..1b6855366b66 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1505,19 +1505,30 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co Report.notifyNewAction(splitChatReport.chatReportID, currentUserAccountID); } +/** Used for editing a split bill while it's still scanning or when SmartScan fails, it completes a split bill started by startSplitBill above. + * + * @param {number} chatReportID - The group chat or workspace reportID + * @param {Object} reportAction - The split action that lives in the chatReport above + * @param {Object} updatedTransaction - The updated **draft** split transaction + * @param {Number} currentUserAccountID + * @param {String} currentUserEmail + */ function completeSplitBill(chatReportID, reportAction, updatedTransaction, currentUserAccountID, currentUserEmail) { const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserEmail); + const {transactionID} = updatedTransaction; + const unmodifiedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; // Save optimistic updated transaction and action const optimisticData = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION}${updatedTransaction.transactionID}`, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: { ...updatedTransaction, receipt: { state: CONST.IOU.RECEIPT_STATE.OPEN, }, + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, { @@ -1527,6 +1538,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre [reportAction.reportActionID]: { lastModified: DateUtils.getDBTime(), whisperedToAccountIDs: [], + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, }, @@ -1535,7 +1547,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre const successData = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION}${updatedTransaction.transactionID}`, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: {pendingAction: null}, }, ]; @@ -1543,11 +1555,22 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre const failureData = [ { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.TRANSACTION}${updatedTransaction.transactionID}`, + key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: { + ...unmodifiedTransaction, errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`, + value: { + [reportAction.reportActionID]: { + ...reportAction, + errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), + }, + }, + }, ]; const splitParticipants = updatedTransaction.comment.splits; @@ -1610,7 +1633,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre updatedTransaction.comment.comment, updatedTransaction.modifiedCreated, CONST.IOU.MONEY_REQUEST_TYPE.SPLIT, - updatedTransaction.transactionID, + transactionID, updatedTransaction.modifiedMerchant, {...updatedTransaction.receipt, state: CONST.IOU.RECEIPT_STATE.OPEN}, updatedTransaction.filename, @@ -1672,7 +1695,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre API.write( 'CompleteSplitBill', { - transactionID: updatedTransaction.transactionID, + transactionID, amount: updatedTransaction.modifiedAmount, currency: updatedTransaction.modifiedCurrency, created: updatedTransaction.modifiedCreated, From cc9a41c73362fbe45346702a1a7df3dc8f92ad1a Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 14:05:19 +0800 Subject: [PATCH 26/59] Fix typo --- src/pages/iou/SplitBillDetailsPage.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 434effd61313..558b498f8970 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -86,12 +86,12 @@ function SplitBillDetailsPage(props) { const participantsExcludingPayee = _.filter(participants, (participant) => participant.accountID !== reportAction.actorAccountID); const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); - const isEdittingSplitBill = + const isEditingSplitBill = props.session.accountID === reportAction.actorAccountID && (isScanning || (TransactionUtils.hasReceipt(transaction) && transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED)); const draftSplitTransaction = props.draftSplitTransactions && props.draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`]; - if (isEdittingSplitBill && !draftSplitTransaction) { + if (isEditingSplitBill && !draftSplitTransaction) { IOU.setDraftSplitTransaction(transaction.transactionID); } @@ -102,7 +102,7 @@ function SplitBillDetailsPage(props) { merchant: splitMerchant, created: splitCreated, category: splitCategory, - } = isEdittingSplitBill && draftSplitTransaction ? ReportUtils.getTransactionDetails(draftSplitTransaction) : ReportUtils.getTransactionDetails(transaction); + } = isEditingSplitBill && draftSplitTransaction ? ReportUtils.getTransactionDetails(draftSplitTransaction) : ReportUtils.getTransactionDetails(transaction); const onConfirm = useCallback( () => IOU.completeSplitBill(props.report.reportID, reportAction, draftSplitTransaction, props.session.accountID, props.session.email), @@ -130,13 +130,13 @@ function SplitBillDetailsPage(props) { iouMerchant={splitMerchant} iouCategory={splitCategory} iouType={CONST.IOU.MONEY_REQUEST_TYPE.SPLIT} - isReadOnly={!isEdittingSplitBill} + isReadOnly={!isEditingSplitBill} shouldShowSmartScanFields receiptPath={transaction.receipt && transaction.receipt.source} receiptFilename={transaction.filename} shouldShowFooter={false} isScanning={isScanning} - isEdittingSplitBill={isEdittingSplitBill} + isEditingSplitBill={isEditingSplitBill} reportActionID={reportAction.reportActionID} reportID={lodashGet(props.report, 'reportID', '')} onConfirm={onConfirm} From b87312d7dbf3d8cda5e9201763fcb518a94ad3d9 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 14:31:12 +0800 Subject: [PATCH 27/59] Optimize retrieval of Onyx data --- src/pages/EditSplitBillPage.js | 47 ++++++++++++++-------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index e3a4fa4563b3..63e025f67549 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -2,7 +2,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; -import compose from '../libs/compose'; import CONST from '../CONST'; import ROUTES from '../ROUTES'; import Navigation from '../libs/Navigation/Navigation'; @@ -11,7 +10,6 @@ import reportPropTypes from './reportPropTypes'; import transactionPropTypes from '../components/transactionPropTypes'; import * as ReportActionsUtils from '../libs/ReportActionsUtils'; import * as ReportUtils from '../libs/ReportUtils'; -import * as TransactionUtils from '../libs/TransactionUtils'; import * as IOU from '../libs/actions/IOU'; import * as CurrencyUtils from '../libs/CurrencyUtils'; import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView'; @@ -28,44 +26,36 @@ const propTypes = { /** Which field we are editing */ field: PropTypes.string, - /** reportID for the "transaction thread" */ + /** The chat reportID of the split */ + reportID: PropTypes.string, + + /** reportActionID of the split action */ reportActionID: PropTypes.string, }), }).isRequired, - /** The report object for the thread report */ - report: reportPropTypes, - /** All the transactions */ transactions: PropTypes.shape(transactionPropTypes), /** Used for retrieving the draft transaction of the split bill being edited */ draftSplitTransactions: PropTypes.shape(transactionPropTypes), - - /** Session info for the currently logged in user. */ - session: PropTypes.shape({ - /** Currently logged in user email */ - email: PropTypes.string, - }), }; const defaultProps = { - report: {}, - session: { - email: null, - }, draftSplitTransactions: {}, transactions: {}, }; -function EditSplitBillPage({report, route, transactions, draftSplitTransactions}) { +function EditSplitBillPage({route, reportActions, transactions, draftSplitTransactions}) { const fieldToEdit = lodashGet(route, ['params', 'field'], ''); - const reportAction = ReportActionsUtils.getReportAction(report.reportID, lodashGet(route, ['params', 'reportActionID'], '')); - const transaction = transactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${reportAction.originalMessage.IOUTransactionID}`]; + const reportID = lodashGet(route, ['params', 'reportID'], ''); + const reportActionID = lodashGet(route, ['params', 'reportActionID'], ''); + const transactionID = lodashGet(reportActions[reportActionID], 'originalMessage.IOUTransactionID', 0); + const transaction = transactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; - let draftSplitTransaction = draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transaction.transactionID}`]; + let draftSplitTransaction = draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`]; if (!draftSplitTransaction) { - IOU.setDraftSplitTransaction(transaction.transactionID); + IOU.setDraftSplitTransaction(transactionID); } const { @@ -79,8 +69,8 @@ function EditSplitBillPage({report, route, transactions, draftSplitTransactions} const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; function setDraftSplitTransaction(transactionChanges) { - IOU.setDraftSplitTransaction(transaction.transactionID, transactionChanges); - Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(report.reportID, reportAction.reportActionID)); + IOU.setDraftSplitTransaction(transactionID, transactionChanges); + Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(reportID, reportActionID)); } if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.DESCRIPTION) { @@ -105,7 +95,7 @@ function EditSplitBillPage({report, route, transactions, draftSplitTransactions} { if (transactionChanges.created === transactionCreated) { Navigation.dismissModal(); @@ -124,7 +114,7 @@ function EditSplitBillPage({report, route, transactions, draftSplitTransactions} { const amount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(transactionChanges)); @@ -141,7 +131,7 @@ function EditSplitBillPage({report, route, transactions, draftSplitTransactions} }} onNavigateToCurrency={() => { const activeRoute = encodeURIComponent(Navigation.getActiveRoute().replace(/\?.*/, '')); - Navigation.navigate(ROUTES.EDIT_SPLIT_BILL_CURRENCY.getRoute(report.reportID, reportAction.reportActionID, defaultCurrency, activeRoute)); + Navigation.navigate(ROUTES.EDIT_SPLIT_BILL_CURRENCY.getRoute(reportID, reportActionID, defaultCurrency, activeRoute)); }} /> ); @@ -169,8 +159,9 @@ EditSplitBillPage.displayName = 'EditSplitBillPage'; EditSplitBillPage.propTypes = propTypes; EditSplitBillPage.defaultProps = defaultProps; export default withOnyx({ - report: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, + reportActions: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${route.params.reportID}`, + canEvict: false, }, transactions: { key: ONYXKEYS.COLLECTION.TRANSACTION, From 6a8de3f3189073a979e3b4502c37487c8e3e69eb Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 14:59:12 +0800 Subject: [PATCH 28/59] Optimize Onyx data more --- src/pages/EditSplitBillPage.js | 64 +++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index 63e025f67549..a25071cf27ec 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -4,14 +4,13 @@ import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; import CONST from '../CONST'; import ROUTES from '../ROUTES'; -import Navigation from '../libs/Navigation/Navigation'; import ONYXKEYS from '../ONYXKEYS'; -import reportPropTypes from './reportPropTypes'; +import compose from '../libs/compose'; import transactionPropTypes from '../components/transactionPropTypes'; -import * as ReportActionsUtils from '../libs/ReportActionsUtils'; import * as ReportUtils from '../libs/ReportUtils'; import * as IOU from '../libs/actions/IOU'; import * as CurrencyUtils from '../libs/CurrencyUtils'; +import Navigation from '../libs/Navigation/Navigation'; import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView'; import EditRequestDescriptionPage from './EditRequestDescriptionPage'; import EditRequestMerchantPage from './EditRequestMerchantPage'; @@ -34,28 +33,26 @@ const propTypes = { }), }).isRequired, - /** All the transactions */ - transactions: PropTypes.shape(transactionPropTypes), + /** The current transaction */ + transaction: PropTypes.shape(transactionPropTypes), - /** Used for retrieving the draft transaction of the split bill being edited */ - draftSplitTransactions: PropTypes.shape(transactionPropTypes), + /** The draft transaction that holds data to be persisited on the current transaction */ + draftTransaction: PropTypes.shape(transactionPropTypes), }; const defaultProps = { - draftSplitTransactions: {}, + draftTransaction: {}, transactions: {}, + reportActions: {}, }; -function EditSplitBillPage({route, reportActions, transactions, draftSplitTransactions}) { +function EditSplitBillPage({route, transaction, draftTransaction}) { const fieldToEdit = lodashGet(route, ['params', 'field'], ''); const reportID = lodashGet(route, ['params', 'reportID'], ''); const reportActionID = lodashGet(route, ['params', 'reportActionID'], ''); - const transactionID = lodashGet(reportActions[reportActionID], 'originalMessage.IOUTransactionID', 0); - const transaction = transactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; - let draftSplitTransaction = draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`]; - if (!draftSplitTransaction) { - IOU.setDraftSplitTransaction(transactionID); + if (!draftTransaction) { + IOU.setDraftSplitTransaction(transaction.transactionID); } const { @@ -64,12 +61,12 @@ function EditSplitBillPage({route, reportActions, transactions, draftSplitTransa comment: transactionDescription, merchant: transactionMerchant, created: transactionCreated, - } = draftSplitTransaction ? ReportUtils.getTransactionDetails(draftSplitTransaction) : ReportUtils.getTransactionDetails(transaction); + } = draftTransaction ? ReportUtils.getTransactionDetails(draftTransaction) : ReportUtils.getTransactionDetails(transaction); const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; function setDraftSplitTransaction(transactionChanges) { - IOU.setDraftSplitTransaction(transactionID, transactionChanges); + IOU.setDraftSplitTransaction(transaction.transactionID, transactionChanges); Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(reportID, reportActionID)); } @@ -158,15 +155,26 @@ function EditSplitBillPage({route, reportActions, transactions, draftSplitTransa EditSplitBillPage.displayName = 'EditSplitBillPage'; EditSplitBillPage.propTypes = propTypes; EditSplitBillPage.defaultProps = defaultProps; -export default withOnyx({ - reportActions: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${route.params.reportID}`, - canEvict: false, - }, - transactions: { - key: ONYXKEYS.COLLECTION.TRANSACTION, - }, - draftSplitTransactions: { - key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, - }, -})(EditSplitBillPage); +export default compose( + withOnyx({ + reportActions: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${route.params.reportID}`, + canEvict: false, + }, + }), + // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file + withOnyx({ + transaction: { + key: ({route, reportActions}) => { + const reportAction = reportActions[`${route.params.reportActionID.toString()}`]; + return `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(reportAction, 'originalMessage.IOUTransactionID', 0)}`; + }, + }, + draftTransaction: { + key: ({route, reportActions}) => { + const reportAction = reportActions[`${route.params.reportActionID.toString()}`]; + return `${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${lodashGet(reportAction, 'originalMessage.IOUTransactionID', 0)}`; + }, + }, + }), +)(EditSplitBillPage); From c25228c3d18693c7219df0c748d4b331ee3b35d0 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 15:22:50 +0800 Subject: [PATCH 29/59] Address comments --- .../MoneyRequestConfirmationList.js | 2 +- src/libs/actions/IOU.js | 27 +++----- src/pages/EditRequestAmountPage.js | 5 -- src/pages/EditSplitBillPage.js | 4 -- src/pages/iou/SplitBillDetailsPage.js | 65 ++++++++++++------- 5 files changed, 51 insertions(+), 52 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index bdc6a3b96d27..97d396f8e7e0 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -286,7 +286,7 @@ function MoneyRequestConfirmationList(props) { value: props.iouType, }, ]; - }, [isSplitBill, isTypeRequest, props.iouAmount, props.receiptPathtranslate, formattedAmount, isDistanceRequestWithoutRoute]); + }, [isSplitBill, isTypeRequest, props.iouType, props.iouAmount, props.receiptPath, formattedAmount, isDistanceRequestWithoutRoute, translate, props.receiptPathtranslate]); const selectedParticipants = useMemo(() => _.filter(props.selectedParticipants, (participant) => participant.selected), [props.selectedParticipants]); const payeePersonalDetails = useMemo(() => props.payeePersonalDetails || props.currentUserPersonalDetails, [props.payeePersonalDetails, props.currentUserPersonalDetails]); diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 1b6855366b66..15c0dcb7116c 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -62,13 +62,6 @@ Onyx.connect({ }, }); -let allRecentlyUsedCategories = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES, - waitForCollectionCallback: true, - callback: (val) => (allRecentlyUsedCategories = val), -}); - let allRecentlyUsedTags = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS, @@ -1510,11 +1503,11 @@ function startSplitBill(participants, currentUserLogin, currentUserAccountID, co * @param {number} chatReportID - The group chat or workspace reportID * @param {Object} reportAction - The split action that lives in the chatReport above * @param {Object} updatedTransaction - The updated **draft** split transaction - * @param {Number} currentUserAccountID - * @param {String} currentUserEmail + * @param {Number} sessionAccountID - accountID of the current user + * @param {String} sessionEmail - email of the current user */ -function completeSplitBill(chatReportID, reportAction, updatedTransaction, currentUserAccountID, currentUserEmail) { - const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserEmail); +function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessionAccountID, sessionEmail) { + const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(sessionEmail); const {transactionID} = updatedTransaction; const unmodifiedTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -1528,7 +1521,6 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre receipt: { state: CONST.IOU.RECEIPT_STATE.OPEN, }, - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, { @@ -1538,7 +1530,6 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre [reportAction.reportActionID]: { lastModified: DateUtils.getDBTime(), whisperedToAccountIDs: [], - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, }, }, }, @@ -1606,7 +1597,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre // The workspace chat reportID is saved in the splits array when starting a split bill with a workspace oneOnOneChatReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${participant.chatReportID}`]; } else { - let existingChatReport = ReportUtils.getChatByParticipants([participant.accountID]); + const existingChatReport = ReportUtils.getChatByParticipants([participant.accountID]); isNewOneOnOneChatReport = !existingChatReport; oneOnOneChatReport = existingChatReport || ReportUtils.buildOptimisticChatReport([participant.accountID]); } @@ -1617,13 +1608,13 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, curre if (shouldCreateNewOneOnOneIOUReport) { oneOnOneIOUReport = isPolicyExpenseChat - ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, participant.policyID, currentUserAccountID, splitAmount, currency) - : ReportUtils.buildOptimisticIOUReport(currentUserAccountID, participant.accountID, splitAmount, oneOnOneChatReport.reportID, currency); - } else if (isOwnPolicyExpenseChat) { + ? ReportUtils.buildOptimisticExpenseReport(oneOnOneChatReport.reportID, participant.policyID, sessionAccountID, splitAmount, currency) + : ReportUtils.buildOptimisticIOUReport(sessionAccountID, participant.accountID, splitAmount, oneOnOneChatReport.reportID, currency); + } else if (isPolicyExpenseChat) { // Because of the Expense reports are stored as negative values, we subtract the total from the amount oneOnOneIOUReport.total -= splitAmount; } else { - oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, currentUserAccountID, splitAmount, currency); + oneOnOneIOUReport = IOUUtils.updateIOUOwnerAndTotal(oneOnOneIOUReport, sessionAccountID, splitAmount, currency); } const oneOnOneTransaction = TransactionUtils.buildOptimisticTransaction( diff --git a/src/pages/EditRequestAmountPage.js b/src/pages/EditRequestAmountPage.js index 82c288d62db9..a082d55af59f 100644 --- a/src/pages/EditRequestAmountPage.js +++ b/src/pages/EditRequestAmountPage.js @@ -4,10 +4,8 @@ import {useFocusEffect} from '@react-navigation/native'; import PropTypes from 'prop-types'; import ScreenWrapper from '../components/ScreenWrapper'; import HeaderWithBackButton from '../components/HeaderWithBackButton'; -import Navigation from '../libs/Navigation/Navigation'; import useLocalize from '../hooks/useLocalize'; import MoneyRequestAmountForm from './iou/steps/MoneyRequestAmountForm'; -import ROUTES from '../ROUTES'; const propTypes = { /** Transaction default amount value */ @@ -21,9 +19,6 @@ const propTypes = { /** Callback to fire when we press on the currency */ onNavigateToCurrency: PropTypes.func.isRequired, - - /** reportID for the transaction thread */ - reportID: PropTypes.string.isRequired, }; function EditRequestAmountPage({defaultAmount, defaultCurrency, onNavigateToCurrency, onSubmit}) { diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index a25071cf27ec..b5a24c93e426 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -51,10 +51,6 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { const reportID = lodashGet(route, ['params', 'reportID'], ''); const reportActionID = lodashGet(route, ['params', 'reportActionID'], ''); - if (!draftTransaction) { - IOU.setDraftSplitTransaction(transaction.transactionID); - } - const { amount: transactionAmount, currency: transactionCurrency, diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 558b498f8970..e1305d952eec 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -36,8 +36,11 @@ const propTypes = { /** Array of report actions for this report */ reportActions: PropTypes.shape(reportActionPropTypes), - /** Used for retrieving the draft transaction of the split bill being edited */ - draftSplitTransactions: PropTypes.shape(transactionPropTypes), + /** The current transaction */ + transaction: PropTypes.shape(transactionPropTypes), + + /** The draft transaction that holds data to be persisited on the current transaction */ + draftTransaction: PropTypes.shape(transactionPropTypes), /** Route params */ route: PropTypes.shape({ @@ -54,6 +57,9 @@ const propTypes = { session: PropTypes.shape({ /** Currently logged in user accountID */ accountID: PropTypes.number, + + /** Currently logged in user email */ + email: PropTypes.string, }).isRequired, ...withLocalizePropTypes, @@ -62,13 +68,13 @@ const propTypes = { const defaultProps = { personalDetails: {}, reportActions: {}, - draftSplitTransactions: {}, + draftTransaction: undefined, }; function SplitBillDetailsPage(props) { + const {reportID} = props.report; + console.log(props.route); const reportAction = props.reportActions[`${props.route.params.reportActionID.toString()}`]; - const transactionID = reportAction.originalMessage.IOUTransactionID; - const transaction = props.allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const participantAccountIDs = reportAction.originalMessage.participantAccountIDs; // In case this is workspace split bill, we manually add the workspace as the second participant of the split bill @@ -85,15 +91,10 @@ function SplitBillDetailsPage(props) { const payeePersonalDetails = props.personalDetails[reportAction.actorAccountID]; const participantsExcludingPayee = _.filter(participants, (participant) => participant.accountID !== reportAction.actorAccountID); - const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); + const isScanning = TransactionUtils.hasReceipt(props.transaction) && TransactionUtils.isReceiptBeingScanned(props.transaction); const isEditingSplitBill = - props.session.accountID === reportAction.actorAccountID && (isScanning || (TransactionUtils.hasReceipt(transaction) && transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED)); - - const draftSplitTransaction = props.draftSplitTransactions && props.draftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`]; - - if (isEditingSplitBill && !draftSplitTransaction) { - IOU.setDraftSplitTransaction(transaction.transactionID); - } + props.session.accountID === reportAction.actorAccountID && + (isScanning || (TransactionUtils.hasReceipt(props.transaction) && props.transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED)); const { amount: splitAmount, @@ -102,16 +103,16 @@ function SplitBillDetailsPage(props) { merchant: splitMerchant, created: splitCreated, category: splitCategory, - } = isEditingSplitBill && draftSplitTransaction ? ReportUtils.getTransactionDetails(draftSplitTransaction) : ReportUtils.getTransactionDetails(transaction); + } = isEditingSplitBill && props.draftTransaction ? ReportUtils.getTransactionDetails(props.draftTransaction) : ReportUtils.getTransactionDetails(props.transaction); const onConfirm = useCallback( - () => IOU.completeSplitBill(props.report.reportID, reportAction, draftSplitTransaction, props.session.accountID, props.session.email), - [props.report.reportID, reportAction, draftSplitTransaction, props.session.accountID, props.session.email], + () => IOU.completeSplitBill(reportID, reportAction, props.draftTransaction, props.session.accountID, props.session.email), + [reportID, reportAction, props.draftTransaction, props.session.accountID, props.session.email], ); return ( - + )} @@ -156,11 +157,12 @@ export default compose( withLocalize, withReportAndReportActionOrNotFound, withOnyx({ - allTransactions: { - key: ONYXKEYS.COLLECTION.TRANSACTION, + report: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, }, - draftSplitTransactions: { - key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, + reportActions: { + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${route.params.reportID}`, + canEvict: false, }, personalDetails: { key: ONYXKEYS.PERSONAL_DETAILS_LIST, @@ -169,4 +171,19 @@ export default compose( key: ONYXKEYS.SESSION, }, }), + // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file + withOnyx({ + transaction: { + key: ({route, reportActions}) => { + const reportAction = reportActions[`${route.params.reportActionID.toString()}`]; + return `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(reportAction, 'originalMessage.IOUTransactionID', 0)}`; + }, + }, + draftTransaction: { + key: ({route, reportActions}) => { + const reportAction = reportActions[`${route.params.reportActionID.toString()}`]; + return `${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${lodashGet(reportAction, 'originalMessage.IOUTransactionID', 0)}`; + }, + }, + }), )(SplitBillDetailsPage); From ba0174c2fb20559f33032d735e7fc4b31ed1a5c5 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 15:39:14 +0800 Subject: [PATCH 30/59] Trim merchant --- src/pages/EditSplitBillPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index b5a24c93e426..0411669cb9dd 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -135,11 +135,11 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { { - if (transactionMerchant === transactionChanges.merchant) { + if (transactionChanges.merchant.trim() === transactionMerchant) { Navigation.goBack(); return; } - setDraftSplitTransaction({merchant: transactionChanges.merchant}); + setDraftSplitTransaction({merchant: transactionChanges.merchant.trim()}); }} /> ); From 4e54b1bc2f04e83fc36037e3c53448333c3cb6b9 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 15:46:18 +0800 Subject: [PATCH 31/59] Always navigate back to split details --- src/pages/EditSplitBillPage.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index 0411669cb9dd..d6908e0d2e43 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -61,9 +61,13 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { const defaultCurrency = lodashGet(route, 'params.currency', '') || transactionCurrency; + function navigateBackToSplitDetails() { + Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(reportID, reportActionID)); + } + function setDraftSplitTransaction(transactionChanges) { IOU.setDraftSplitTransaction(transaction.transactionID, transactionChanges); - Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(reportID, reportActionID)); + navigateBackToSplitDetails(); } if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.DESCRIPTION) { @@ -72,7 +76,7 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { defaultDescription={transactionDescription} onSubmit={(transactionChanges) => { if (transactionChanges.comment.trim() === transactionDescription) { - Navigation.dismissModal(); + navigateBackToSplitDetails(); return; } setDraftSplitTransaction({ @@ -91,7 +95,7 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { reportID={reportID} onSubmit={(transactionChanges) => { if (transactionChanges.created === transactionCreated) { - Navigation.dismissModal(); + navigateBackToSplitDetails(); return; } setDraftSplitTransaction({ @@ -113,7 +117,7 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { const amount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(transactionChanges)); if (amount === transactionAmount && transactionCurrency === defaultCurrency) { - Navigation.goBack(); + Navigation.dismissModal(); return; } @@ -136,7 +140,7 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { defaultMerchant={transactionMerchant} onSubmit={(transactionChanges) => { if (transactionChanges.merchant.trim() === transactionMerchant) { - Navigation.goBack(); + navigateBackToSplitDetails(); return; } setDraftSplitTransaction({merchant: transactionChanges.merchant.trim()}); From 63733b2e3df76d89b8196224a366c5453593b2c4 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 15:48:55 +0800 Subject: [PATCH 32/59] Fix jerky animation (might be reverted not sure if this is okay) --- src/pages/EditRequestAmountPage.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/EditRequestAmountPage.js b/src/pages/EditRequestAmountPage.js index a082d55af59f..2afe156c913b 100644 --- a/src/pages/EditRequestAmountPage.js +++ b/src/pages/EditRequestAmountPage.js @@ -33,7 +33,9 @@ function EditRequestAmountPage({defaultAmount, defaultCurrency, onNavigateToCurr if (!textInput.current) { return; } - textInput.current.focus(); + setTimeout(() => { + textInput.current.focus(); + }, 50); }); }; From a518d616d23d7df7636fe23e99ee81a4fa4d74e0 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 16:37:33 +0800 Subject: [PATCH 33/59] Show error fields next to missing fields --- src/components/MoneyRequestConfirmationList.js | 12 +++++++++++- src/pages/EditSplitBillPage.js | 17 ----------------- src/pages/iou/SplitBillDetailsPage.js | 7 ++++--- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 97d396f8e7e0..1b95fbdf519f 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -193,8 +193,9 @@ const defaultProps = { function MoneyRequestConfirmationList(props) { // Destructure functions from props to pass it as a dependecy to useCallback/useMemo hooks. // Prop functions pass props itself as a "this" value to the function which means they change every time props change. - const {onSendMoney, onConfirm, onSelectParticipant, transaction} = props; + const {onSendMoney, onConfirm, onSelectParticipant} = props; const {translate, toLocaleDigit} = useLocalize(); + const transaction = props.isEditingSplitBill ? props.draftTransaction || props.transaction : props.transaction; const isTypeRequest = props.iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST; const isSplitBill = props.iouType === CONST.IOU.MONEY_REQUEST_TYPE.SPLIT; @@ -534,6 +535,8 @@ function MoneyRequestConfirmationList(props) { style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} disabled={didConfirm || props.isReadOnly} + brickRoadIndicator={props.hasSmartScanFailed && transaction.modifiedAmount === 0 && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} + error={props.hasSmartScanFailed && transaction.modifiedAmount === 0 && translate('common.error.enterAmount')} /> )} )} {props.isDistanceRequest && ( @@ -613,6 +618,8 @@ function MoneyRequestConfirmationList(props) { Navigation.navigate(ROUTES.MONEY_REQUEST_MERCHANT.getRoute(props.iouType, props.reportID)); }} disabled={didConfirm || props.isReadOnly} + brickRoadIndicator={props.hasSmartScanFailed && _.isEmpty(transaction.modifiedMerchant) && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} + error={props.hasSmartScanFailed && _.isEmpty(transaction.modifiedMerchant) && translate('common.error.enterMerchant')} /> )} {shouldShowCategories && ( @@ -673,6 +680,9 @@ export default compose( key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, selector: DistanceRequestUtils.getDefaultMileageRate, }, + draftTransaction: { + key: ({transactionID}) => `${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`, + }, transaction: { key: ({transactionID}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, }, diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index d6908e0d2e43..087f59670e02 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -75,10 +75,6 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { { - if (transactionChanges.comment.trim() === transactionDescription) { - navigateBackToSplitDetails(); - return; - } setDraftSplitTransaction({ comment: transactionChanges.comment.trim(), }); @@ -94,10 +90,6 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { defaultAmount={transactionAmount} reportID={reportID} onSubmit={(transactionChanges) => { - if (transactionChanges.created === transactionCreated) { - navigateBackToSplitDetails(); - return; - } setDraftSplitTransaction({ created: transactionChanges.created, }); @@ -116,11 +108,6 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { onSubmit={(transactionChanges) => { const amount = CurrencyUtils.convertToBackendAmount(Number.parseFloat(transactionChanges)); - if (amount === transactionAmount && transactionCurrency === defaultCurrency) { - Navigation.dismissModal(); - return; - } - setDraftSplitTransaction({ amount, currency: defaultCurrency, @@ -139,10 +126,6 @@ function EditSplitBillPage({route, transaction, draftTransaction}) { { - if (transactionChanges.merchant.trim() === transactionMerchant) { - navigateBackToSplitDetails(); - return; - } setDraftSplitTransaction({merchant: transactionChanges.merchant.trim()}); }} /> diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index e1305d952eec..1aca4f5892f9 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -92,9 +92,8 @@ function SplitBillDetailsPage(props) { const participantsExcludingPayee = _.filter(participants, (participant) => participant.accountID !== reportAction.actorAccountID); const isScanning = TransactionUtils.hasReceipt(props.transaction) && TransactionUtils.isReceiptBeingScanned(props.transaction); - const isEditingSplitBill = - props.session.accountID === reportAction.actorAccountID && - (isScanning || (TransactionUtils.hasReceipt(props.transaction) && props.transaction.receipt.state === CONST.IOU.RECEIPT_STATE.FAILED)); + const hasSmartScanFailed = TransactionUtils.hasReceipt(props.transaction) && props.transaction.receipt.state === CONST.IOU.RECEIPT_STATE.SCANFAILED; + const isEditingSplitBill = props.session.accountID === reportAction.actorAccountID && (isScanning || hasSmartScanFailed); const { amount: splitAmount, @@ -138,8 +137,10 @@ function SplitBillDetailsPage(props) { shouldShowFooter={false} isScanning={isScanning} isEditingSplitBill={isEditingSplitBill} + hasSmartScanFailed reportID={reportID} reportActionID={reportAction.reportActionID} + transactionID={props.transaction.transactionID} onConfirm={onConfirm} /> )} From cdf376b6295478ad0d27241cf0125af2110e4786 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 16:53:14 +0800 Subject: [PATCH 34/59] Linting --- src/components/MoneyRequestConfirmationList.js | 6 +----- src/pages/EditSplitBillPage.js | 4 +--- src/pages/iou/SplitBillDetailsPage.js | 3 +-- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 1b95fbdf519f..0f1d99cbd2da 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -141,9 +141,6 @@ const propTypes = { /** Whether the money request is a distance request */ isDistanceRequest: PropTypes.bool, - /** Whether the receipt associated with this report is being scanned */ - isScanning: PropTypes.bool, - /** Whether we should show the amount, date, and merchant fields. */ shouldShowSmartScanFields: PropTypes.bool, @@ -185,7 +182,6 @@ const defaultProps = { transaction: {}, mileageRate: {unit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, rate: 0, currency: 'USD'}, isDistanceRequest: false, - isScanning: false, shouldShowSmartScanFields: true, isPolicyExpenseChat: false, }; @@ -287,7 +283,7 @@ function MoneyRequestConfirmationList(props) { value: props.iouType, }, ]; - }, [isSplitBill, isTypeRequest, props.iouType, props.iouAmount, props.receiptPath, formattedAmount, isDistanceRequestWithoutRoute, translate, props.receiptPathtranslate]); + }, [isSplitBill, isTypeRequest, props.iouType, props.iouAmount, props.receiptPath, formattedAmount, isDistanceRequestWithoutRoute, translate]); const selectedParticipants = useMemo(() => _.filter(props.selectedParticipants, (participant) => participant.selected), [props.selectedParticipants]); const payeePersonalDetails = useMemo(() => props.payeePersonalDetails || props.currentUserPersonalDetails, [props.payeePersonalDetails, props.currentUserPersonalDetails]); diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index 087f59670e02..22a9f013a025 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -34,7 +34,7 @@ const propTypes = { }).isRequired, /** The current transaction */ - transaction: PropTypes.shape(transactionPropTypes), + transaction: PropTypes.shape(transactionPropTypes).isRequired, /** The draft transaction that holds data to be persisited on the current transaction */ draftTransaction: PropTypes.shape(transactionPropTypes), @@ -42,8 +42,6 @@ const propTypes = { const defaultProps = { draftTransaction: {}, - transactions: {}, - reportActions: {}, }; function EditSplitBillPage({route, transaction, draftTransaction}) { diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 1aca4f5892f9..b84e3c773f0d 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -37,7 +37,7 @@ const propTypes = { reportActions: PropTypes.shape(reportActionPropTypes), /** The current transaction */ - transaction: PropTypes.shape(transactionPropTypes), + transaction: PropTypes.shape(transactionPropTypes).isRequired, /** The draft transaction that holds data to be persisited on the current transaction */ draftTransaction: PropTypes.shape(transactionPropTypes), @@ -73,7 +73,6 @@ const defaultProps = { function SplitBillDetailsPage(props) { const {reportID} = props.report; - console.log(props.route); const reportAction = props.reportActions[`${props.route.params.reportActionID.toString()}`]; const participantAccountIDs = reportAction.originalMessage.participantAccountIDs; From 95dc96f38937fb1ef21ab5d1d48c9e943a17712a Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 17:00:38 +0800 Subject: [PATCH 35/59] Remove testing code --- src/pages/iou/SplitBillDetailsPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index b84e3c773f0d..2a1b49816247 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -136,7 +136,7 @@ function SplitBillDetailsPage(props) { shouldShowFooter={false} isScanning={isScanning} isEditingSplitBill={isEditingSplitBill} - hasSmartScanFailed + hasSmartScanFailed={hasSmartScanFailed} reportID={reportID} reportActionID={reportAction.reportActionID} transactionID={props.transaction.transactionID} From cc00910a27980c02b9ea32ffb7ebcd5a8db7bba1 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 18:33:04 +0800 Subject: [PATCH 36/59] Lint --- src/libs/TransactionUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index ac9c9623a74c..e0402140ef5e 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -96,7 +96,7 @@ function areRequiredFieldsEmpty(transaction: Transaction): boolean { /** * Given the edit made to the money request, return an updated transaction object. */ -function getUpdatedTransaction(transaction: Transaction, transactionChanges: TransactionChanges, isFromExpenseReport: boolean, shouldUpdateReceiptState = true): Transaction { +function getUpdatedTransaction(transaction: Transaction, transactionChanges: TransactionChanges, isFromExpenseReport: boolean, shouldUpdateReceiptState: boolean = true): Transaction { // Only changing the first level fields so no need for deep clone now const updatedTransaction = {...transaction}; let shouldStopSmartscan = false; From 5aad7a8528db9fa437c009949df181b34ffa1978 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 18:50:15 +0800 Subject: [PATCH 37/59] Delete draft split transaction in success data --- src/libs/actions/IOU.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 15c0dcb7116c..aa2cafc28a83 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1541,6 +1541,11 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, value: {pendingAction: null}, }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`, + value: null, + }, ]; const failureData = [ From be6be0fff42accc62789c3ec0e7262a8c2e5421f Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 18:59:06 +0800 Subject: [PATCH 38/59] Display form error when SmartScan fails --- src/components/MoneyRequestConfirmationList.js | 6 +++++- src/languages/en.ts | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 0f1d99cbd2da..eb8b2c836ea0 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -231,9 +231,13 @@ function MoneyRequestConfirmationList(props) { const isFocused = useIsFocused(); const [formError, setFormError] = useState(''); useEffect(() => { + if (props.isEditingSplitBill && props.hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction)) { + setFormError('iou.receiptScanningFailed'); + return; + } // reset the form error whenever the screen gains or loses focus setFormError(''); - }, [isFocused]); + }, [isFocused, transaction, props.isEditingSplitBill, props.hasSmartScanFailed]); useEffect(() => { if (!shouldCalculateDistanceAmount) { diff --git a/src/languages/en.ts b/src/languages/en.ts index b4d83ac36217..67dcb935d487 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -527,6 +527,7 @@ export default { receiptMissingDetails: 'Receipt missing details', receiptStatusTitle: 'Scanning…', receiptStatusText: "Only you can see this receipt when it's scanning. Check back later or enter the details now.", + receiptScanningFailed: 'Receipt scanning failed. Enter the details manually', requestCount: ({count, scanningReceipts = 0}: RequestCountParams) => `${count} requests${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}`, deleteRequest: 'Delete request', deleteConfirmation: 'Are you sure that you want to delete this request?', From 56dc41011e1d775adc14df80c976ad763c38aa1f Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 19:06:52 +0800 Subject: [PATCH 39/59] Rename param --- src/components/MoneyRequestConfirmationList.js | 2 +- src/libs/actions/IOU.js | 8 ++++---- src/pages/EditSplitBillPage.js | 2 +- src/pages/iou/SplitBillDetailsPage.js | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index eb8b2c836ea0..8a2521128226 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -681,7 +681,7 @@ export default compose( selector: DistanceRequestUtils.getDefaultMileageRate, }, draftTransaction: { - key: ({transactionID}) => `${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`, + key: ({transactionID}) => `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, }, transaction: { key: ({transactionID}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`, diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index aa2cafc28a83..18847fd191be 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -55,7 +55,7 @@ Onyx.connect({ let allDraftSplitTransactions; Onyx.connect({ - key: ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION, + key: ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT, waitForCollectionCallback: true, callback: (val) => { allDraftSplitTransactions = val || {}; @@ -1543,7 +1543,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi }, { onyxMethod: Onyx.METHOD.MERGE, - key: `${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`, + key: `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, value: null, }, ]; @@ -1708,7 +1708,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi * @param {Object} transactionChanges */ function setDraftSplitTransaction(transactionID, transactionChanges = {}) { - let draftSplitTransaction = allDraftSplitTransactions[`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`]; + let draftSplitTransaction = allDraftSplitTransactions[`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`]; if (!draftSplitTransaction) { draftSplitTransaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; @@ -1716,7 +1716,7 @@ function setDraftSplitTransaction(transactionID, transactionChanges = {}) { const updatedTransaction = TransactionUtils.getUpdatedTransaction(draftSplitTransaction, transactionChanges, false, false); - Onyx.merge(`${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${transactionID}`, updatedTransaction); + Onyx.merge(`${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`, updatedTransaction); } /** diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index 22a9f013a025..d23597563b75 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -154,7 +154,7 @@ export default compose( draftTransaction: { key: ({route, reportActions}) => { const reportAction = reportActions[`${route.params.reportActionID.toString()}`]; - return `${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${lodashGet(reportAction, 'originalMessage.IOUTransactionID', 0)}`; + return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${lodashGet(reportAction, 'originalMessage.IOUTransactionID', 0)}`; }, }, }), diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 2a1b49816247..419e02299b9a 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -182,7 +182,7 @@ export default compose( draftTransaction: { key: ({route, reportActions}) => { const reportAction = reportActions[`${route.params.reportActionID.toString()}`]; - return `${ONYXKEYS.COLLECTION.DRAFT_SPLIT_TRANSACTION}${lodashGet(reportAction, 'originalMessage.IOUTransactionID', 0)}`; + return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${lodashGet(reportAction, 'originalMessage.IOUTransactionID', 0)}`; }, }, }), From 2f976ef35c8546438ec2a7e7b7ec83ddc07504a7 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 19:07:01 +0800 Subject: [PATCH 40/59] Include current user in splits --- 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 18847fd191be..ed76a1036115 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1575,7 +1575,7 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi // Exclude the current user when calculating the split amount, `calculateAmount` takes it into account const splitAmount = IOUUtils.calculateAmount(splitParticipants.length - 1, amount, currency, false); - const splits = []; + const splits = [{email: currentUserEmailForIOUSplit}]; _.each(splitParticipants, (participant) => { // Skip creating the transaction for the current user if (participant.email === currentUserEmailForIOUSplit) { From f80a6583b7243a58489ecefa8e304bfbc6deb504 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 19:14:12 +0800 Subject: [PATCH 41/59] Lint --- src/libs/TransactionUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index e0402140ef5e..ac9c9623a74c 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -96,7 +96,7 @@ function areRequiredFieldsEmpty(transaction: Transaction): boolean { /** * Given the edit made to the money request, return an updated transaction object. */ -function getUpdatedTransaction(transaction: Transaction, transactionChanges: TransactionChanges, isFromExpenseReport: boolean, shouldUpdateReceiptState: boolean = true): Transaction { +function getUpdatedTransaction(transaction: Transaction, transactionChanges: TransactionChanges, isFromExpenseReport: boolean, shouldUpdateReceiptState = true): Transaction { // Only changing the first level fields so no need for deep clone now const updatedTransaction = {...transaction}; let shouldStopSmartscan = false; From 6a28df32abe1e0d6216463918d4f99b5da6d8be6 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 19:14:20 +0800 Subject: [PATCH 42/59] Dismiss modal and notify users after completing split bill --- 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 ed76a1036115..3bfb4a3f0cc5 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -1701,6 +1701,8 @@ function completeSplitBill(chatReportID, reportAction, updatedTransaction, sessi }, {optimisticData, successData, failureData}, ); + Navigation.dismissModal(chatReportID); + Report.notifyNewAction(chatReportID, sessionAccountID); } /** From 1e21419ae91147ee74dcf9237d63bd0a81a87b1f Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 19:29:12 +0800 Subject: [PATCH 43/59] Update translations --- src/languages/en.ts | 2 +- src/languages/es.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 03288cfb7b77..681c486c6b88 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -528,7 +528,7 @@ export default { receiptMissingDetails: 'Receipt missing details', receiptStatusTitle: 'Scanning…', receiptStatusText: "Only you can see this receipt when it's scanning. Check back later or enter the details now.", - receiptScanningFailed: 'Receipt scanning failed. Enter the details manually', + receiptScanningFailed: 'Receipt scanning failed. Enter the details manually.', requestCount: ({count, scanningReceipts = 0}: RequestCountParams) => `${count} requests${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}`, deleteRequest: 'Delete request', deleteConfirmation: 'Are you sure that you want to delete this request?', diff --git a/src/languages/es.ts b/src/languages/es.ts index eed5c75e2269..58f7e556ddf0 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -520,6 +520,7 @@ export default { receiptMissingDetails: 'Recibo con campos vacíos', receiptStatusTitle: 'Escaneando…', receiptStatusText: 'Solo tú puedes ver este recibo cuando se está escaneando. Vuelve más tarde o introduce los detalles ahora.', + receiptScanningFailed: 'El escaneo de recibo ha fallado. Introduce los detalles manualmente.', requestCount: ({count, scanningReceipts = 0}: RequestCountParams) => `${count} solicitudes${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}`, deleteRequest: 'Eliminar pedido', deleteConfirmation: '¿Estás seguro de que quieres eliminar este pedido?', From c7b54821b22af40906a048a5b9db6d1ecde3bb6d Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 20:34:28 +0800 Subject: [PATCH 44/59] Use existing timeout logic for focusing text input --- src/pages/EditRequestAmountPage.js | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/pages/EditRequestAmountPage.js b/src/pages/EditRequestAmountPage.js index 2afe156c913b..d65fdafb3b59 100644 --- a/src/pages/EditRequestAmountPage.js +++ b/src/pages/EditRequestAmountPage.js @@ -1,10 +1,10 @@ import React, {useCallback, useRef} from 'react'; -import {InteractionManager} from 'react-native'; import {useFocusEffect} from '@react-navigation/native'; import PropTypes from 'prop-types'; +import CONST from '../CONST'; +import useLocalize from '../hooks/useLocalize'; import ScreenWrapper from '../components/ScreenWrapper'; import HeaderWithBackButton from '../components/HeaderWithBackButton'; -import useLocalize from '../hooks/useLocalize'; import MoneyRequestAmountForm from './iou/steps/MoneyRequestAmountForm'; const propTypes = { @@ -23,25 +23,19 @@ const propTypes = { function EditRequestAmountPage({defaultAmount, defaultCurrency, onNavigateToCurrency, onSubmit}) { const {translate} = useLocalize(); - const textInput = useRef(null); - const focusTextInput = () => { - // Component may not be initialized due to navigation transitions - // Wait until interactions are complete before trying to focus - InteractionManager.runAfterInteractions(() => { - // Focus text input - if (!textInput.current) { - return; - } - setTimeout(() => { - textInput.current.focus(); - }, 50); - }); - }; + const textInput = useRef(null); + const focusTimeoutRef = useRef(null); useFocusEffect( useCallback(() => { - focusTextInput(); + focusTimeoutRef.current = setTimeout(() => textInput.current && textInput.current.focus(), CONST.ANIMATED_TRANSITION); + return () => { + if (!focusTimeoutRef.current) { + return; + } + clearTimeout(focusTimeoutRef.current); + }; }, []), ); From 26a731119773989c9024ee87ac12c592632d000b Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 20:38:00 +0800 Subject: [PATCH 45/59] Display form error when completing split bill with missing fields --- src/components/MoneyRequestConfirmationList.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 8a2521128226..a023819e502e 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -424,6 +424,12 @@ function MoneyRequestConfirmationList(props) { return; } + if (isEditingSplitBill && TransactionUtils.hasMissingSmartscanFields(transaction)) { + // TODO in this PR: also show errors next to the fields if user confirms while transaction has missing fields + setFormError('iou.receiptScanningFailed'); + return; + } + setDidConfirm(true); onConfirm(selectedParticipants); } From 48d684b83bd7be6ebbb53e8f0a514d2b73871096 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 20:44:05 +0800 Subject: [PATCH 46/59] Bug fix --- src/components/MoneyRequestConfirmationList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index a023819e502e..65530cfcfbe4 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -424,7 +424,7 @@ function MoneyRequestConfirmationList(props) { return; } - if (isEditingSplitBill && TransactionUtils.hasMissingSmartscanFields(transaction)) { + if (props.isEditingSplitBill && TransactionUtils.hasMissingSmartscanFields(transaction)) { // TODO in this PR: also show errors next to the fields if user confirms while transaction has missing fields setFormError('iou.receiptScanningFailed'); return; From 362a1aee90365b5f3d288a7d90b68eee8a86fe56 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 20:45:04 +0800 Subject: [PATCH 47/59] Use areRequiredFieldsEmpty --- src/components/MoneyRequestConfirmationList.js | 2 +- src/libs/TransactionUtils.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 65530cfcfbe4..a70a43538b08 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -424,7 +424,7 @@ function MoneyRequestConfirmationList(props) { return; } - if (props.isEditingSplitBill && TransactionUtils.hasMissingSmartscanFields(transaction)) { + if (props.isEditingSplitBill && TransactionUtils.areRequiredFieldsEmpty(transaction)) { // TODO in this PR: also show errors next to the fields if user confirms while transaction has missing fields setFormError('iou.receiptScanningFailed'); return; diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index ac9c9623a74c..0e82ee728625 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -402,6 +402,7 @@ export { getValidWaypoints, isDistanceRequest, getWaypoints, + areRequiredFieldsEmpty, hasMissingSmartscanFields, getWaypointIndex, waypointHasValidAddress, From f8484aeaedfb4923484a835a16b2838c4ef6c6ab Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 21:01:07 +0800 Subject: [PATCH 48/59] Fix lint and change form error when user completes split bill --- src/components/MoneyRequestConfirmationList.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index a70a43538b08..e8ea77ab9aef 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -426,7 +426,7 @@ function MoneyRequestConfirmationList(props) { if (props.isEditingSplitBill && TransactionUtils.areRequiredFieldsEmpty(transaction)) { // TODO in this PR: also show errors next to the fields if user confirms while transaction has missing fields - setFormError('iou.receiptScanningFailed'); + setFormError('iou.error.genericSmartscanFailureMessage'); return; } @@ -434,7 +434,18 @@ function MoneyRequestConfirmationList(props) { onConfirm(selectedParticipants); } }, - [selectedParticipants, onSendMoney, onConfirm, props.iouType, props.isDistanceRequest, isDistanceRequestWithoutRoute, props.iouCurrencyCode, props.iouAmount], + [ + selectedParticipants, + onSendMoney, + onConfirm, + props.isEditingSplitBill, + props.iouType, + props.isDistanceRequest, + isDistanceRequestWithoutRoute, + props.iouCurrencyCode, + props.iouAmount, + transaction, + ], ); const footerContent = useMemo(() => { From 583a607e6014c9b491561bc823167690de4f7cb1 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 21:27:10 +0800 Subject: [PATCH 49/59] Display field errors next to missing smartscan fields when use confirms --- .../MoneyRequestConfirmationList.js | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index e8ea77ab9aef..bdd38822aa91 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -230,14 +230,30 @@ function MoneyRequestConfirmationList(props) { const isFocused = useIsFocused(); const [formError, setFormError] = useState(''); + + const [didConfirm, setDidConfirm] = useState(false); + const [didConfirmSplit, setDidConfirmSplit] = useState(false); + + const shouldDisplayFieldError = useMemo(() => { + if (!props.isEditingSplitBill) { + return false; + } + + return (props.hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction)) || (didConfirmSplit && TransactionUtils.areRequiredFieldsEmpty(transaction)); + }, [props.isEditingSplitBill, props.hasSmartScanFailed, transaction, didConfirmSplit]); + useEffect(() => { - if (props.isEditingSplitBill && props.hasSmartScanFailed && TransactionUtils.hasMissingSmartscanFields(transaction)) { + if (shouldDisplayFieldError && props.hasSmartScanFailed) { setFormError('iou.receiptScanningFailed'); return; } + if (shouldDisplayFieldError && didConfirmSplit) { + setFormError('iou.error.genericSmartscanFailureMessage'); + return; + } // reset the form error whenever the screen gains or loses focus setFormError(''); - }, [isFocused, transaction, props.isEditingSplitBill, props.hasSmartScanFailed]); + }, [isFocused, transaction, shouldDisplayFieldError, props.hasSmartScanFailed, didConfirmSplit]); useEffect(() => { if (!shouldCalculateDistanceAmount) { @@ -264,8 +280,6 @@ function MoneyRequestConfirmationList(props) { [props.iouAmount, props.iouCurrencyCode], ); - const [didConfirm, setDidConfirm] = useState(false); - // If completing a split bill fails, set didConfirm to false to allow the user to edit the fields again if (props.isEditingSplitBill && didConfirm) { setDidConfirm(false); @@ -425,7 +439,7 @@ function MoneyRequestConfirmationList(props) { } if (props.isEditingSplitBill && TransactionUtils.areRequiredFieldsEmpty(transaction)) { - // TODO in this PR: also show errors next to the fields if user confirms while transaction has missing fields + setDidConfirmSplit(true); setFormError('iou.error.genericSmartscanFailureMessage'); return; } @@ -447,6 +461,8 @@ function MoneyRequestConfirmationList(props) { transaction, ], ); + console.log(transaction); + console.log(TransactionUtils.areRequiredFieldsEmpty(transaction)); const footerContent = useMemo(() => { if (props.isReadOnly) { @@ -552,8 +568,8 @@ function MoneyRequestConfirmationList(props) { style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} disabled={didConfirm || props.isReadOnly} - brickRoadIndicator={props.hasSmartScanFailed && transaction.modifiedAmount === 0 && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} - error={props.hasSmartScanFailed && transaction.modifiedAmount === 0 && translate('common.error.enterAmount')} + brickRoadIndicator={shouldDisplayFieldError && transaction.modifiedAmount === 0 && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} + error={shouldDisplayFieldError && transaction.modifiedAmount === 0 && translate('common.error.enterAmount')} /> )} )} {props.isDistanceRequest && ( @@ -635,8 +651,8 @@ function MoneyRequestConfirmationList(props) { Navigation.navigate(ROUTES.MONEY_REQUEST_MERCHANT.getRoute(props.iouType, props.reportID)); }} disabled={didConfirm || props.isReadOnly} - brickRoadIndicator={props.hasSmartScanFailed && _.isEmpty(transaction.modifiedMerchant) && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} - error={props.hasSmartScanFailed && _.isEmpty(transaction.modifiedMerchant) && translate('common.error.enterMerchant')} + brickRoadIndicator={shouldDisplayFieldError && _.isEmpty(transaction.modifiedMerchant) && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} + error={shouldDisplayFieldError && _.isEmpty(transaction.modifiedMerchant) && translate('common.error.enterMerchant')} /> )} {shouldShowCategories && ( From bf021a59e5036e9744cb7d3268dfe601bf05d72f Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 21:31:04 +0800 Subject: [PATCH 50/59] Cleanup --- src/components/MoneyRequestConfirmationList.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index bdd38822aa91..74a50db6564e 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -461,8 +461,6 @@ function MoneyRequestConfirmationList(props) { transaction, ], ); - console.log(transaction); - console.log(TransactionUtils.areRequiredFieldsEmpty(transaction)); const footerContent = useMemo(() => { if (props.isReadOnly) { From 5867982da8c4539842f917e32ae5f1b711223f82 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 21:33:23 +0800 Subject: [PATCH 51/59] Apply suggestions from code review Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- src/pages/EditSplitBillPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index d23597563b75..41d73f020a3b 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -22,7 +22,7 @@ const propTypes = { route: PropTypes.shape({ /** Params from the route */ params: PropTypes.shape({ - /** Which field we are editing */ + /** The transaction field we are editing */ field: PropTypes.string, /** The chat reportID of the split */ @@ -36,7 +36,7 @@ const propTypes = { /** The current transaction */ transaction: PropTypes.shape(transactionPropTypes).isRequired, - /** The draft transaction that holds data to be persisited on the current transaction */ + /** The draft transaction that holds data to be persisted on the current transaction */ draftTransaction: PropTypes.shape(transactionPropTypes), }; From 7a6f4b2d9c7c050867acc9cc3de115fd7afaa5b8 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 21:34:30 +0800 Subject: [PATCH 52/59] Revert change, should be handled in follow up clean up --- src/components/MoneyRequestConfirmationList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 74a50db6564e..d6f02b556d12 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -660,7 +660,7 @@ function MoneyRequestConfirmationList(props) { description={translate('common.category')} onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_CATEGORY.getRoute(props.iouType, props.reportID))} style={[styles.moneyRequestMenuItem]} - disabled={didConfirm} + disabled={didConfirm || props.isReadOnly} /> )} {shouldShowTags && ( From a7401504b139e8d057714f048f4143bb99559119 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 22:52:38 +0800 Subject: [PATCH 53/59] Fix isScanning state to also check for required fields being empty --- src/pages/iou/SplitBillDetailsPage.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 419e02299b9a..0b4670e7df58 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -90,7 +90,8 @@ function SplitBillDetailsPage(props) { const payeePersonalDetails = props.personalDetails[reportAction.actorAccountID]; const participantsExcludingPayee = _.filter(participants, (participant) => participant.accountID !== reportAction.actorAccountID); - const isScanning = TransactionUtils.hasReceipt(props.transaction) && TransactionUtils.isReceiptBeingScanned(props.transaction); + const isScanning = + TransactionUtils.hasReceipt(props.transaction) && TransactionUtils.isReceiptBeingScanned(props.transaction) && TransactionUtils.areRequiredFieldsEmpty(props.transaction); const hasSmartScanFailed = TransactionUtils.hasReceipt(props.transaction) && props.transaction.receipt.state === CONST.IOU.RECEIPT_STATE.SCANFAILED; const isEditingSplitBill = props.session.accountID === reportAction.actorAccountID && (isScanning || hasSmartScanFailed); From f73674d995a140e11d1998010a251565a2043fc9 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Wed, 11 Oct 2023 23:31:52 +0800 Subject: [PATCH 54/59] Fix areRequiredFieldsEmpty to check for non existent modified fields --- src/libs/TransactionUtils.ts | 17 +++++++++++------ src/pages/iou/SplitBillDetailsPage.js | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 0e82ee728625..b0349bf37fb2 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -83,14 +83,19 @@ function hasReceipt(transaction: Transaction | undefined | null): boolean { } function areRequiredFieldsEmpty(transaction: Transaction): boolean { - return ( + const isMerchantEmpty = + transaction.merchant === CONST.TRANSACTION.UNKNOWN_MERCHANT || transaction.merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || transaction.merchant === ''; + + const isModifiedMerchantEmpty = + !transaction.modifiedMerchant || transaction.modifiedMerchant === CONST.TRANSACTION.UNKNOWN_MERCHANT || transaction.modifiedMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT || - (transaction.modifiedMerchant === '' && - (transaction.merchant === CONST.TRANSACTION.UNKNOWN_MERCHANT || transaction.merchant === '' || transaction.merchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT)) || - (transaction.modifiedAmount === 0 && transaction.amount === 0) || - (transaction.modifiedCreated === '' && transaction.created === '') - ); + transaction.modifiedMerchant === ''; + + const isModifiedAmountEmpty = !transaction.modifiedAmount || transaction.modifiedAmount === 0; + const isModifiedCreatedEmpty = !transaction.modifiedCreated || transaction.modifiedCreated === ''; + + return (isModifiedMerchantEmpty && isMerchantEmpty) || (isModifiedAmountEmpty && transaction.amount === 0) || (isModifiedCreatedEmpty && transaction.created === ''); } /** diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 0b4670e7df58..9114be7acb7e 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -93,7 +93,7 @@ function SplitBillDetailsPage(props) { const isScanning = TransactionUtils.hasReceipt(props.transaction) && TransactionUtils.isReceiptBeingScanned(props.transaction) && TransactionUtils.areRequiredFieldsEmpty(props.transaction); const hasSmartScanFailed = TransactionUtils.hasReceipt(props.transaction) && props.transaction.receipt.state === CONST.IOU.RECEIPT_STATE.SCANFAILED; - const isEditingSplitBill = props.session.accountID === reportAction.actorAccountID && (isScanning || hasSmartScanFailed); + const isEditingSplitBill = props.session.accountID === reportAction.actorAccountID && (TransactionUtils.areRequiredFieldsEmpty(props.transaction) || hasSmartScanFailed); const { amount: splitAmount, From 0126d5feee0f2d5ed0b37a7f9a3d277400caaacc Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Thu, 12 Oct 2023 02:29:59 +0800 Subject: [PATCH 55/59] Use non-interactive style instead of disabled style --- .../MoneyRequestConfirmationList.js | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index d6f02b556d12..9e5f824dea78 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -553,6 +553,7 @@ function MoneyRequestConfirmationList(props) { shouldShowRightIcon={!props.isReadOnly && !props.isDistanceRequest} title={formattedAmount} description={translate('iou.amount')} + interactive={!props.isReadOnly} onPress={() => { if (props.isDistanceRequest) { return; @@ -565,7 +566,7 @@ function MoneyRequestConfirmationList(props) { }} style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} - disabled={didConfirm || props.isReadOnly} + disabled={didConfirm} brickRoadIndicator={shouldDisplayFieldError && transaction.modifiedAmount === 0 && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} error={shouldDisplayFieldError && transaction.modifiedAmount === 0 && translate('common.error.enterAmount')} /> @@ -584,7 +585,8 @@ function MoneyRequestConfirmationList(props) { }} style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} - disabled={didConfirm || props.isReadOnly} + disabled={didConfirm} + interactive={!props.isReadOnly} numberOfLinesTitle={2} /> {!shouldShowAllFields && ( @@ -618,7 +620,8 @@ function MoneyRequestConfirmationList(props) { } Navigation.navigate(ROUTES.MONEY_REQUEST_DATE.getRoute(props.iouType, props.reportID)); }} - disabled={didConfirm || props.isReadOnly} + disabled={didConfirm} + interactive={!props.isReadOnly} brickRoadIndicator={shouldDisplayFieldError && _.isEmpty(transaction.modifiedCreated) && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} error={shouldDisplayFieldError && _.isEmpty(transaction.modifiedCreated) && translate('common.error.enterDate')} /> @@ -631,7 +634,8 @@ function MoneyRequestConfirmationList(props) { style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_DISTANCE.getRoute(props.iouType, props.reportID))} - disabled={didConfirm || props.isReadOnly || !isTypeRequest} + disabled={didConfirm || !isTypeRequest} + interactive={!props.isReadOnly} /> )} {props.shouldShowSmartScanFields && ( @@ -648,7 +652,8 @@ function MoneyRequestConfirmationList(props) { } Navigation.navigate(ROUTES.MONEY_REQUEST_MERCHANT.getRoute(props.iouType, props.reportID)); }} - disabled={didConfirm || props.isReadOnly} + disabled={didConfirm} + interactive={!props.isReadOnly} brickRoadIndicator={shouldDisplayFieldError && _.isEmpty(transaction.modifiedMerchant) && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} error={shouldDisplayFieldError && _.isEmpty(transaction.modifiedMerchant) && translate('common.error.enterMerchant')} /> @@ -660,7 +665,8 @@ function MoneyRequestConfirmationList(props) { description={translate('common.category')} onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_CATEGORY.getRoute(props.iouType, props.reportID))} style={[styles.moneyRequestMenuItem]} - disabled={didConfirm || props.isReadOnly} + disabled={didConfirm} + interactive={!props.isReadOnly} /> )} {shouldShowTags && ( @@ -670,7 +676,8 @@ function MoneyRequestConfirmationList(props) { description={policyTagListName} onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_TAG.getRoute(props.iouType, props.reportID))} style={[styles.moneyRequestMenuItem]} - disabled={didConfirm || props.isReadOnly} + disabled={didConfirm} + interactive={!props.isReadOnly} /> )} {shouldShowBillable && ( From 5cd7d9b79b1a9146ba11c26227bea923b7f38317 Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Thu, 12 Oct 2023 03:39:49 +0800 Subject: [PATCH 56/59] Fix MenuItem console warning and checking for modified amount --- src/components/MoneyRequestConfirmationList.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 9e5f824dea78..31c8754b3b8d 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -567,8 +567,8 @@ function MoneyRequestConfirmationList(props) { style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} disabled={didConfirm} - brickRoadIndicator={shouldDisplayFieldError && transaction.modifiedAmount === 0 && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} - error={shouldDisplayFieldError && transaction.modifiedAmount === 0 && translate('common.error.enterAmount')} + brickRoadIndicator={shouldDisplayFieldError && _.isEmpty(transaction.modifiedAmount) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + error={shouldDisplayFieldError && _.isEmpty(transaction.modifiedAmount) ? translate('common.error.enterAmount') : ''} /> )} )} {props.isDistanceRequest && ( @@ -654,8 +654,8 @@ function MoneyRequestConfirmationList(props) { }} disabled={didConfirm} interactive={!props.isReadOnly} - brickRoadIndicator={shouldDisplayFieldError && _.isEmpty(transaction.modifiedMerchant) && CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR} - error={shouldDisplayFieldError && _.isEmpty(transaction.modifiedMerchant) && translate('common.error.enterMerchant')} + brickRoadIndicator={shouldDisplayFieldError && _.isEmpty(transaction.modifiedMerchant) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + error={shouldDisplayFieldError && _.isEmpty(transaction.modifiedMerchant) ? translate('common.error.enterMerchant') : ''} /> )} {shouldShowCategories && ( From 95b3b9f431b70f87507f9b31f36839cc755a659b Mon Sep 17 00:00:00 2001 From: Youssef Lourayad Date: Thu, 12 Oct 2023 04:15:07 +0800 Subject: [PATCH 57/59] Fix checking for modifiedAmount --- src/components/MoneyRequestConfirmationList.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 31c8754b3b8d..931c56c661ce 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -567,8 +567,8 @@ function MoneyRequestConfirmationList(props) { style={[styles.moneyRequestMenuItem, styles.mt2]} titleStyle={styles.moneyRequestConfirmationAmount} disabled={didConfirm} - brickRoadIndicator={shouldDisplayFieldError && _.isEmpty(transaction.modifiedAmount) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} - error={shouldDisplayFieldError && _.isEmpty(transaction.modifiedAmount) ? translate('common.error.enterAmount') : ''} + brickRoadIndicator={shouldDisplayFieldError && !transaction.modifiedAmount ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} + error={shouldDisplayFieldError && !transaction.modifiedAmount ? translate('common.error.enterAmount') : ''} /> )} Date: Thu, 12 Oct 2023 04:17:47 +0800 Subject: [PATCH 58/59] Keep merchant error if it equal partial marchant (none) --- src/components/MoneyRequestConfirmationList.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 931c56c661ce..0f62bac198f8 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -654,8 +654,16 @@ function MoneyRequestConfirmationList(props) { }} disabled={didConfirm} interactive={!props.isReadOnly} - brickRoadIndicator={shouldDisplayFieldError && _.isEmpty(transaction.modifiedMerchant) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''} - error={shouldDisplayFieldError && _.isEmpty(transaction.modifiedMerchant) ? translate('common.error.enterMerchant') : ''} + brickRoadIndicator={ + shouldDisplayFieldError && (transaction.modifiedMerchant === '' || transaction.modifiedMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT) + ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR + : '' + } + error={ + shouldDisplayFieldError && (transaction.modifiedMerchant === '' || transaction.modifiedMerchant === CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT) + ? translate('common.error.enterMerchant') + : '' + } /> )} {shouldShowCategories && ( From 1a51105922878818c2df54746ab3517cff323ee7 Mon Sep 17 00:00:00 2001 From: Vit Horacek Date: Wed, 11 Oct 2023 23:57:26 +0100 Subject: [PATCH 59/59] Fix console warning --- src/pages/EditSplitBillPage.js | 2 +- src/pages/iou/SplitBillDetailsPage.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js index 41d73f020a3b..217b1a100572 100644 --- a/src/pages/EditSplitBillPage.js +++ b/src/pages/EditSplitBillPage.js @@ -34,7 +34,7 @@ const propTypes = { }).isRequired, /** The current transaction */ - transaction: PropTypes.shape(transactionPropTypes).isRequired, + transaction: transactionPropTypes.isRequired, /** The draft transaction that holds data to be persisted on the current transaction */ draftTransaction: PropTypes.shape(transactionPropTypes), diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js index 9114be7acb7e..1b3052e9e72c 100644 --- a/src/pages/iou/SplitBillDetailsPage.js +++ b/src/pages/iou/SplitBillDetailsPage.js @@ -37,7 +37,7 @@ const propTypes = { reportActions: PropTypes.shape(reportActionPropTypes), /** The current transaction */ - transaction: PropTypes.shape(transactionPropTypes).isRequired, + transaction: transactionPropTypes.isRequired, /** The draft transaction that holds data to be persisited on the current transaction */ draftTransaction: PropTypes.shape(transactionPropTypes),