diff --git a/src/CONST.js b/src/CONST.js
index daefbe0ec6be..60d444e65fe5 100644
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -64,6 +64,7 @@ const CONST = {
HOMEPAGE_REPORTS_LOADED: 'homepage_reports_loaded',
SWITCH_REPORT: 'switch_report',
COLD: 'cold',
+ REPORT_ACTION_ITEM_LAYOUT_DEBOUNCE_TIME: 1500,
},
MESSAGES: {
// eslint-disable-next-line max-len
diff --git a/src/libs/actions/Timing.js b/src/libs/actions/Timing.js
index 4d1eae31a36f..9dd385750d3e 100644
--- a/src/libs/actions/Timing.js
+++ b/src/libs/actions/Timing.js
@@ -17,10 +17,11 @@ function start(eventName) {
*
* @param {String} eventName - event name used as timestamp key
* @param {String} [secondaryName] - optional secondary event name, passed to grafana
+ * @param {Number} [offset] - optional param to offset the time
*/
-function end(eventName, secondaryName = '') {
+function end(eventName, secondaryName = '', offset = 0) {
if (eventName in timestampData) {
- const eventTime = Date.now() - timestampData[eventName];
+ const eventTime = Date.now() - timestampData[eventName] - offset;
const grafanaEventName = secondaryName
? `expensify.cash.${eventName}.${secondaryName}`
: `expensify.cash.${eventName}`;
diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js
index 7929fd272407..9ff91edb14ac 100644
--- a/src/pages/home/report/ReportActionItem.js
+++ b/src/pages/home/report/ReportActionItem.js
@@ -38,6 +38,9 @@ const propTypes = {
// Should we display the new indicator on top of the comment?
shouldDisplayNewIndicator: PropTypes.bool.isRequired,
+
+ // Runs when the view enclosing the chat message lays out indicating it has rendered
+ onLayout: PropTypes.func.isRequired,
};
const defaultProps = {
@@ -122,7 +125,7 @@ class ReportActionItem extends Component {
{this.props.shouldDisplayNewIndicator && (
)}
-
+
{!this.props.displayAsGroup
? (
diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js
index 4cb8af7c7071..ae9e4ef1e80e 100644
--- a/src/pages/home/report/ReportActionsView.js
+++ b/src/pages/home/report/ReportActionsView.js
@@ -89,6 +89,13 @@ class ReportActionsView extends React.Component {
this.loadMoreChats = this.loadMoreChats.bind(this);
this.sortedReportActions = [];
+ // We are debouncing this call with a specific delay so that when all items in the list layout we can measure
+ // the total time it took to complete.
+ this.recordTimeToMeasureItemLayout = _.debounce(
+ this.recordTimeToMeasureItemLayout.bind(this),
+ CONST.TIMING.REPORT_ACTION_ITEM_LAYOUT_DEBOUNCE_TIME,
+ );
+
this.state = {
isLoadingMoreChats: false,
};
@@ -113,7 +120,6 @@ class ReportActionsView extends React.Component {
setNewMarkerPosition(this.props.reportID, oldestUnreadSequenceNumber);
fetchActions(this.props.reportID);
- Timing.end(CONST.TIMING.SWITCH_REPORT, CONST.TIMING.COLD);
}
shouldComponentUpdate(nextProps, nextState) {
@@ -187,6 +193,10 @@ class ReportActionsView extends React.Component {
this.keyboardEvent.remove();
}
+ // We must cancel the debounce function so that we do not call the function when switching to a new chat before
+ // the previous one has finished loading completely.
+ this.recordTimeToMeasureItemLayout.cancel();
+
AppState.removeEventListener('change', this.onVisibilityChange);
unsubscribeFromReportChannel(this.props.reportID);
@@ -297,6 +307,16 @@ class ReportActionsView extends React.Component {
updateLastReadActionID(this.props.reportID);
}
+ /**
+ * Runs each time a ReportActionItem is laid out. This method is debounced so we wait until the component has
+ * finished laying out items before recording the chat as switched.
+ */
+ recordTimeToMeasureItemLayout() {
+ // We are offsetting the time measurement here so that we can subtract our debounce time from the initial time
+ // and get the actual time it took to load the report
+ Timing.end(CONST.TIMING.SWITCH_REPORT, CONST.TIMING.COLD, CONST.TIMING.REPORT_ACTION_ITEM_LAYOUT_DEBOUNCE_TIME);
+ }
+
/**
* This function overrides the CellRendererComponent (defaults to a plain View), giving each ReportActionItem a
* higher z-index than the one below it. This prevents issues where the ReportActionContextMenu overlapping between
@@ -343,6 +363,7 @@ class ReportActionsView extends React.Component {
isMostRecentIOUReportAction={item.action.sequenceNumber === this.mostRecentIOUReportSequenceNumber}
iouReportID={this.props.report.iouReportID}
hasOutstandingIOU={this.props.report.hasOutstandingIOU}
+ onLayout={this.recordTimeToMeasureItemLayout}
/>
);
}