From 6cc8fc00460f581d38f2544f451cc6ec8a8ac3d2 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Tue, 9 May 2023 13:32:36 -1000 Subject: [PATCH 01/12] add isMoneyRequestThreadReport --- src/libs/ReportUtils.js | 12 ++++++++++++ src/pages/home/ReportScreen.js | 1 + 2 files changed, 13 insertions(+) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index f2e28ad7016f..53349b6f68aa 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1809,6 +1809,17 @@ function getWhisperDisplayNames(participants) { return _.map(participants, (login) => getDisplayNameForParticipant(login, !isWhisperOnlyVisibleToCurrentUSer)).join(', '); } +function isMoneyRequestThreadReport(reportID) { + const parentReportID = allReports[reportID].parentReportID; + + // No parentReportID - can't possibly be a thread + if (parentReportID) { + return false; + } + + return isMoneyRequestReport(allReports[parentReportID]); +} + export { getReportParticipantsTitle, isReportMessageAttachment, @@ -1886,4 +1897,5 @@ export { canRequestMoney, getWhisperDisplayNames, getWorkspaceAvatar, + isMoneyRequestThreadReport, }; diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 7eb837346b12..af4eb0416de5 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -289,6 +289,7 @@ class ReportScreen extends React.Component { report={this.props.report} policies={this.props.policies} personalDetails={this.props.personalDetails} + isSingleTransactionView={ReportUtils.isMoneyRequestThreadReport(this.props.report)} /> ) : ( Date: Tue, 9 May 2023 13:40:33 -1000 Subject: [PATCH 02/12] render MoneyRequestHeader when it is a MoneyRequestReport or MoneyRequestThreadReport --- src/pages/home/ReportScreen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index af4eb0416de5..2acc5ea4be27 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -284,7 +284,7 @@ class ReportScreen extends React.Component { errors={addWorkspaceRoomOrChatErrors} shouldShowErrorMessages={false} > - {ReportUtils.isMoneyRequestReport(this.props.report) ? ( + {(ReportUtils.isMoneyRequestReport(this.props.report) || ReportUtils.isMoneyRequestReport(this.props.report)) ? ( Date: Tue, 9 May 2023 13:40:52 -1000 Subject: [PATCH 03/12] Fix rightside of || --- src/pages/home/ReportScreen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 2acc5ea4be27..1bdae4632433 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -284,7 +284,7 @@ class ReportScreen extends React.Component { errors={addWorkspaceRoomOrChatErrors} shouldShowErrorMessages={false} > - {(ReportUtils.isMoneyRequestReport(this.props.report) || ReportUtils.isMoneyRequestReport(this.props.report)) ? ( + {(ReportUtils.isMoneyRequestReport(this.props.report) || ReportUtils.isMoneyRequestThreadReport(this.props.report)) ? ( Date: Tue, 9 May 2023 13:46:07 -1000 Subject: [PATCH 04/12] Call the method once --- src/pages/home/ReportScreen.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 1bdae4632433..6766e4456ae7 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -245,7 +245,7 @@ class ReportScreen extends React.Component { // the moment the ReportScreen becomes unfrozen we want to start the animation of the placeholder skeleton content // (which is shown, until all the actual views of the ReportScreen have been rendered) const shouldAnimate = !shouldFreeze; - + const isMoneyRequestThreadReport = ReportUtils.isMoneyRequestThreadReport(this.props.report); return ( - {(ReportUtils.isMoneyRequestReport(this.props.report) || ReportUtils.isMoneyRequestThreadReport(this.props.report)) ? ( + {(ReportUtils.isMoneyRequestReport(this.props.report) || isMoneyRequestThreadReport) ? ( ) : ( Date: Tue, 9 May 2023 13:57:33 -1000 Subject: [PATCH 05/12] Add some stuff to alert us if the parent report does not exist for the thread. Also fix the JSDoc --- src/libs/ReportUtils.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 53349b6f68aa..dd95634c4aa9 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -22,6 +22,7 @@ import isReportMessageAttachment from './isReportMessageAttachment'; import * as defaultWorkspaceAvatars from '../components/Icon/WorkspaceDefaultAvatars'; import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as CurrencyUtils from './CurrencyUtils'; +import Log from './Log'; let sessionEmail; Onyx.connect({ @@ -1809,14 +1810,23 @@ function getWhisperDisplayNames(participants) { return _.map(participants, (login) => getDisplayNameForParticipant(login, !isWhisperOnlyVisibleToCurrentUSer)).join(', '); } +/** + * @param {string} reportID + * @returns {boolean} + */ function isMoneyRequestThreadReport(reportID) { const parentReportID = allReports[reportID].parentReportID; - // No parentReportID - can't possibly be a thread + // No parentReportID - this can't possibly be a thread if (parentReportID) { return false; } + if (allReports[parentReportID]) { + Log.alert('Tried to access a parent report for a thread, but the parent report does not exist'); + return false; + } + return isMoneyRequestReport(allReports[parentReportID]); } From fda42d52c6d39383b451f6838d227a393b0f441c Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 15 May 2023 12:54:55 -1000 Subject: [PATCH 06/12] put a comma back in --- src/components/ReportActionItem/IOUPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ReportActionItem/IOUPreview.js b/src/components/ReportActionItem/IOUPreview.js index ec74e82a22d8..a63aaca4ff88 100644 --- a/src/components/ReportActionItem/IOUPreview.js +++ b/src/components/ReportActionItem/IOUPreview.js @@ -148,7 +148,7 @@ const IOUPreview = (props) => { // If props.action is undefined then we are displaying within IOUDetailsModal and should use the full report amount const requestAmount = props.isIOUAction ? moneyRequestAction.total : ReportUtils.getMoneyRequestTotal(props.iouReport); const requestCurrency = props.isIOUAction ? moneyRequestAction.currency : props.iouReport.currency; - const requestComment = Str.htmlDecode(moneyRequestAction.comment).trim() + const requestComment = Str.htmlDecode(moneyRequestAction.comment).trim(); const getSettledMessage = () => { switch (lodashGet(props.action, 'originalMessage.paymentType', '')) { From 358d75e8c09e6cf102d8347649a17ee61cdb59c9 Mon Sep 17 00:00:00 2001 From: Marc Glasser Date: Mon, 15 May 2023 20:22:16 -1000 Subject: [PATCH 07/12] Render reportaction rows in MoneyRequestHeader --- src/components/MoneyRequestHeader.js | 26 ++++++++++++++++++++++++++ src/libs/DateUtils.js | 14 ++++++++++++++ src/libs/ReportUtils.js | 21 --------------------- src/pages/home/ReportScreen.js | 4 +++- 4 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 91f9e782930d..613ba6b23293 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -19,6 +19,8 @@ import Navigation from '../libs/Navigation/Navigation'; import ROUTES from '../ROUTES'; import Icon from './Icon'; import * as CurrencyUtils from '../libs/CurrencyUtils'; +import MenuItemWithTopDescription from './MenuItemWithTopDescription'; +import DateUtils from '../libs/DateUtils'; const propTypes = { /** The report currently being looked at */ @@ -44,6 +46,14 @@ const defaultProps = { }; const MoneyRequestHeader = (props) => { + // These are only used for the single transaction view and not "money requests" + const transactionAmount = lodashGet(props.parentReportAction, ['originalMessage', 'amount']); + const transactionCurrency = lodashGet(props.parentReportAction, ['originalMessage', 'currency']); + const transactionDescription = lodashGet(props.parentReportAction, ['originalMessage', 'comment']); + const formattedTransactionAmount = transactionAmount && transactionCurrency && CurrencyUtils.convertToDisplayString(transactionAmount, transactionCurrency); + const transactionDate = lodashGet(props.parentReportAction, ['created']); + const formattedTransactionDate = DateUtils.getDateStringFromISOTimestamp(transactionDate); + const formattedAmount = CurrencyUtils.convertToDisplayString(ReportUtils.getMoneyRequestTotal(props.report), props.report.currency); const isSettled = ReportUtils.isSettled(props.report.reportID); const isExpenseReport = ReportUtils.isExpenseReport(props.report); @@ -111,6 +121,22 @@ const MoneyRequestHeader = (props) => { + {props.isSingleTransactionView && ( + <> + + + + + )} ); }; diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js index 91609af7b173..0a3388cc1c2e 100644 --- a/src/libs/DateUtils.js +++ b/src/libs/DateUtils.js @@ -185,6 +185,19 @@ function subtractMillisecondsFromDateTime(dateTime, milliseconds) { return getDBTime(newTimestamp); } +/** + * @param {string} isoTimestamp example: 2023-05-16 05:34:14.388 + * @returns {string} example: 2023-05-16 + */ +function getDateStringFromISOTimestamp(isoTimestamp) { + if (!isoTimestamp) { + return ''; + } + + const [dateString] = isoTimestamp.split(' '); + return dateString; +} + /** * @namespace DateUtils */ @@ -199,6 +212,7 @@ const DateUtils = { getMicroseconds, getDBTime, subtractMillisecondsFromDateTime, + getDateStringFromISOTimestamp, }; export default DateUtils; diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 3488149d4de3..721d40667128 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -22,7 +22,6 @@ import isReportMessageAttachment from './isReportMessageAttachment'; import * as defaultWorkspaceAvatars from '../components/Icon/WorkspaceDefaultAvatars'; import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as CurrencyUtils from './CurrencyUtils'; -import Log from './Log'; let sessionEmail; Onyx.connect({ @@ -2142,25 +2141,6 @@ function isReportDataReady() { return !_.isEmpty(allReports) && _.some(_.keys(allReports), (key) => allReports[key].reportID); } -/** - * @param {object} report - * @returns {boolean} - */ -function isSingleTransactionThreadReport(report) { - const parentReportAction = ReportActionsUtils.getParentReportAction(report); - if (_.isEmpty(parentReportAction)) { - if (report.parentReportActionID) { - Log.alert('parentReportActionID found, but no reportAction exists locally for this ID!'); - } else { - Log.info('No parentReportActionID for this report. Not a thread.'); - } - console.log(report); - return false; - } - - return ReportActionsUtils.isTransactionThread(parentReportAction); -} - export { getReportParticipantsTitle, isReportMessageAttachment, @@ -2243,7 +2223,6 @@ export { canRequestMoney, getWhisperDisplayNames, getWorkspaceAvatar, - isSingleTransactionThreadReport, isThread, isThreadParent, isThreadFirstChat, diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 2a729b4b192d..5ae3b0e8e294 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -244,7 +244,8 @@ class ReportScreen extends React.Component { // the moment the ReportScreen becomes unfrozen we want to start the animation of the placeholder skeleton content // (which is shown, until all the actual views of the ReportScreen have been rendered) const shouldAnimate = !shouldFreeze; - const isSingleTransactionView = ReportUtils.isSingleTransactionThreadReport(this.props.report); + const parentReportAction = ReportActionsUtils.getParentReportAction(this.props.report); + const isSingleTransactionView = ReportActionsUtils.isTransactionThread(parentReportAction); return ( ) : ( Date: Mon, 15 May 2023 20:32:52 -1000 Subject: [PATCH 08/12] Add new kansas font style --- src/components/MoneyRequestHeader.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 613ba6b23293..566f74bd7563 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -126,6 +126,7 @@ const MoneyRequestHeader = (props) => { Date: Tue, 16 May 2023 07:12:31 -1000 Subject: [PATCH 09/12] Get parentReport via Onyx to populate header avatars/names --- src/components/MoneyRequestHeader.js | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 566f74bd7563..70bfbb627dbd 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -2,6 +2,7 @@ import React from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; +import {withOnyx} from 'react-native-onyx'; import HeaderWithCloseButton from './HeaderWithCloseButton'; import iouReportPropTypes from '../pages/iouReportPropTypes'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; @@ -21,11 +22,15 @@ import Icon from './Icon'; import * as CurrencyUtils from '../libs/CurrencyUtils'; import MenuItemWithTopDescription from './MenuItemWithTopDescription'; import DateUtils from '../libs/DateUtils'; +import ONYXKEYS from '../ONYXKEYS'; const propTypes = { /** The report currently being looked at */ report: iouReportPropTypes.isRequired, + /** The expense report or iou report (only will have a value if this is a transaction thread) */ + parentReport: iouReportPropTypes, + /** The policies which the user has access to and which the report could be tied to */ policies: PropTypes.shape({ /** Name of the policy */ @@ -43,6 +48,7 @@ const propTypes = { const defaultProps = { isSingleTransactionView: false, + parentReport: {}, }; const MoneyRequestHeader = (props) => { @@ -55,11 +61,13 @@ const MoneyRequestHeader = (props) => { const formattedTransactionDate = DateUtils.getDateStringFromISOTimestamp(transactionDate); const formattedAmount = CurrencyUtils.convertToDisplayString(ReportUtils.getMoneyRequestTotal(props.report), props.report.currency); - const isSettled = ReportUtils.isSettled(props.report.reportID); - const isExpenseReport = ReportUtils.isExpenseReport(props.report); - const payeeName = isExpenseReport ? ReportUtils.getPolicyName(props.report, props.policies) : ReportUtils.getDisplayNameForParticipant(props.report.managerEmail); + + const moneyRequestReport = props.isSingleTransactionView ? props.parentReport : props.report; + const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); + const isExpenseReport = ReportUtils.isExpenseReport(moneyRequestReport); + const payeeName = isExpenseReport ? ReportUtils.getPolicyName(moneyRequestReport, props.policies) : ReportUtils.getDisplayNameForParticipant(props.report.managerEmail); const payeeAvatar = isExpenseReport - ? ReportUtils.getWorkspaceAvatar(props.report) + ? ReportUtils.getWorkspaceAvatar(moneyRequestReport) : ReportUtils.getAvatar(lodashGet(props.personalDetails, [props.report.managerEmail, 'avatar']), props.report.managerEmail); return ( @@ -74,7 +82,7 @@ const MoneyRequestHeader = (props) => { }, ]} threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton} - report={props.report} + report={moneyRequestReport} policies={props.policies} personalDetails={props.personalDetails} shouldShowCloseButton={false} @@ -146,4 +154,12 @@ MoneyRequestHeader.displayName = 'MoneyRequestHeader'; MoneyRequestHeader.propTypes = propTypes; MoneyRequestHeader.defaultProps = defaultProps; -export default compose(withWindowDimensions, withLocalize)(MoneyRequestHeader); +export default compose( + withWindowDimensions, + withLocalize, + withOnyx({ + parentReport: { + key: (props) => `${ONYXKEYS.COLLECTION.REPORT}${props.report.parentReportID}`, + }, + }), +)(MoneyRequestHeader); From 6c1fd5514db86d8efbd97036e7a84a51243c2a8f Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 17 May 2023 07:15:39 -0600 Subject: [PATCH 10/12] Update src/components/MoneyRequestHeader.js Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- src/components/MoneyRequestHeader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 2c8d0e2f4436..89adaa2919ab 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -68,7 +68,7 @@ const MoneyRequestHeader = (props) => { const payeeName = isExpenseReport ? ReportUtils.getPolicyName(moneyRequestReport, props.policies) : ReportUtils.getDisplayNameForParticipant(props.report.managerEmail); const payeeAvatar = isExpenseReport ? ReportUtils.getWorkspaceAvatar(moneyRequestReport) - : ReportUtils.getAvatar(lodashGet(props.personalDetails, [props.report.managerEmail, 'avatar']), props.report.managerEmail); + : ReportUtils.getAvatar(lodashGet(props.personalDetails, [moneyRequestReport.managerEmail, 'avatar']), moneyRequestReport.managerEmail); return ( Date: Wed, 17 May 2023 07:15:47 -0600 Subject: [PATCH 11/12] Update src/components/MoneyRequestHeader.js Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- src/components/MoneyRequestHeader.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index 89adaa2919ab..b028cbaf8e5e 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -65,7 +65,7 @@ const MoneyRequestHeader = (props) => { const moneyRequestReport = props.isSingleTransactionView ? props.parentReport : props.report; const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); const isExpenseReport = ReportUtils.isExpenseReport(moneyRequestReport); - const payeeName = isExpenseReport ? ReportUtils.getPolicyName(moneyRequestReport, props.policies) : ReportUtils.getDisplayNameForParticipant(props.report.managerEmail); + const payeeName = isExpenseReport ? ReportUtils.getPolicyName(moneyRequestReport, props.policies) : ReportUtils.getDisplayNameForParticipant(moneyRequestReport.managerEmail); const payeeAvatar = isExpenseReport ? ReportUtils.getWorkspaceAvatar(moneyRequestReport) : ReportUtils.getAvatar(lodashGet(props.personalDetails, [moneyRequestReport.managerEmail, 'avatar']), moneyRequestReport.managerEmail); From 0dce9ec893b3c0a2b1ded1c7ffaaa66d0c047e3e Mon Sep 17 00:00:00 2001 From: Carlos Martins Date: Wed, 17 May 2023 07:36:45 -0600 Subject: [PATCH 12/12] add translations --- src/components/MoneyRequestHeader.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js index b028cbaf8e5e..7e1685a4e8c8 100644 --- a/src/components/MoneyRequestHeader.js +++ b/src/components/MoneyRequestHeader.js @@ -133,15 +133,15 @@ const MoneyRequestHeader = (props) => { <>