Skip to content

Commit cf4e837

Browse files
authored
Merge pull request #23977 from dukenv0307/fix/23568
Fix crash app when opening split bill detail page by deep link
2 parents 0495ed8 + 70e497f commit cf4e837

2 files changed

Lines changed: 155 additions & 18 deletions

File tree

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import PropTypes from 'prop-types';
2+
import React, {useEffect, useCallback} from 'react';
3+
import {withOnyx} from 'react-native-onyx';
4+
import _ from 'underscore';
5+
import getComponentDisplayName from '../../../libs/getComponentDisplayName';
6+
import NotFoundPage from '../../ErrorPage/NotFoundPage';
7+
import ONYXKEYS from '../../../ONYXKEYS';
8+
import reportPropTypes from '../../reportPropTypes';
9+
import reportActionPropTypes from './reportActionPropTypes';
10+
import FullscreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator';
11+
import * as ReportUtils from '../../../libs/ReportUtils';
12+
import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
13+
import * as Report from '../../../libs/actions/Report';
14+
import compose from '../../../libs/compose';
15+
import withWindowDimensions from '../../../components/withWindowDimensions';
16+
17+
export default function (WrappedComponent) {
18+
const propTypes = {
19+
/** The HOC takes an optional ref as a prop and passes it as a ref to the wrapped component.
20+
* That way, if a ref is passed to a component wrapped in the HOC, the ref is a reference to the wrapped component, not the HOC. */
21+
forwardedRef: PropTypes.func,
22+
23+
/** The report currently being looked at */
24+
report: reportPropTypes,
25+
26+
/** Array of report actions for this report */
27+
reportActions: PropTypes.shape(reportActionPropTypes),
28+
29+
/** The policies which the user has access to */
30+
policies: PropTypes.objectOf(
31+
PropTypes.shape({
32+
/** The policy name */
33+
name: PropTypes.string,
34+
35+
/** The type of the policy */
36+
type: PropTypes.string,
37+
}),
38+
),
39+
40+
/** Route params */
41+
route: PropTypes.shape({
42+
params: PropTypes.shape({
43+
/** Report ID passed via route */
44+
reportID: PropTypes.string,
45+
46+
/** ReportActionID passed via route */
47+
reportActionID: PropTypes.string,
48+
}),
49+
}).isRequired,
50+
51+
/** Beta features list */
52+
betas: PropTypes.arrayOf(PropTypes.string),
53+
54+
/** Indicated whether the report data is loading */
55+
isLoadingReportData: PropTypes.bool,
56+
57+
/** Is the window width narrow, like on a mobile device? */
58+
isSmallScreenWidth: PropTypes.bool.isRequired,
59+
};
60+
61+
const defaultProps = {
62+
forwardedRef: () => {},
63+
reportActions: {},
64+
report: {},
65+
policies: {},
66+
betas: [],
67+
isLoadingReportData: true,
68+
};
69+
70+
// eslint-disable-next-line rulesdir/no-negated-variables
71+
function WithReportAndReportActionOrNotFound(props) {
72+
const getReportAction = useCallback(() => {
73+
let reportAction = props.reportActions[`${props.route.params.reportActionID}`];
74+
75+
// Handle threads if needed
76+
if (reportAction === undefined || reportAction.reportActionID === undefined) {
77+
reportAction = ReportActionsUtils.getParentReportAction(props.report);
78+
}
79+
80+
return reportAction;
81+
}, [props.report, props.reportActions, props.route.params.reportActionID]);
82+
83+
const reportAction = getReportAction();
84+
85+
// For small screen, we don't call openReport API when we go to a sub report page by deeplink
86+
// So we need to call openReport here for small screen
87+
useEffect(() => {
88+
if (!props.isSmallScreenWidth || (!_.isEmpty(props.report) && !_.isEmpty(reportAction))) {
89+
return;
90+
}
91+
Report.openReport(props.route.params.reportID);
92+
// eslint-disable-next-line react-hooks/exhaustive-deps
93+
}, [props.isSmallScreenWidth, props.route.params.reportID]);
94+
95+
// Perform all the loading checks
96+
const isLoadingReport = props.isLoadingReportData && (_.isEmpty(props.report) || !props.report.reportID);
97+
const isLoadingReportAction = _.isEmpty(props.reportActions) || (props.report.isLoadingReportActions && _.isEmpty(getReportAction()));
98+
const shouldHideReport = !isLoadingReport && (_.isEmpty(props.report) || !props.report.reportID || !ReportUtils.canAccessReport(props.report, props.policies, props.betas));
99+
100+
if ((isLoadingReport || isLoadingReportAction) && !shouldHideReport) {
101+
return <FullscreenLoadingIndicator />;
102+
}
103+
104+
// Perform the access/not found checks
105+
if (shouldHideReport || _.isEmpty(reportAction)) {
106+
return <NotFoundPage />;
107+
}
108+
109+
const rest = _.omit(props, ['forwardedRef']);
110+
return (
111+
<WrappedComponent
112+
// eslint-disable-next-line react/jsx-props-no-spreading
113+
{...rest}
114+
ref={props.forwardedRef}
115+
/>
116+
);
117+
}
118+
119+
WithReportAndReportActionOrNotFound.propTypes = propTypes;
120+
WithReportAndReportActionOrNotFound.defaultProps = defaultProps;
121+
WithReportAndReportActionOrNotFound.displayName = `withReportAndReportActionOrNotFound(${getComponentDisplayName(WrappedComponent)})`;
122+
123+
// eslint-disable-next-line rulesdir/no-negated-variables
124+
const withReportAndReportActionOrNotFound = React.forwardRef((props, ref) => (
125+
<WithReportAndReportActionOrNotFound
126+
// eslint-disable-next-line react/jsx-props-no-spreading
127+
{...props}
128+
forwardedRef={ref}
129+
/>
130+
));
131+
132+
return compose(
133+
withWindowDimensions,
134+
withOnyx({
135+
report: {
136+
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`,
137+
},
138+
isLoadingReportData: {
139+
key: ONYXKEYS.IS_LOADING_REPORT_DATA,
140+
},
141+
betas: {
142+
key: ONYXKEYS.BETAS,
143+
},
144+
policies: {
145+
key: ONYXKEYS.COLLECTION.POLICY,
146+
},
147+
reportActions: {
148+
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${route.params.reportID}`,
149+
canEvict: false,
150+
},
151+
}),
152+
)(withReportAndReportActionOrNotFound);
153+
}

src/pages/iou/SplitBillDetailsPage.js

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize
1414
import compose from '../../libs/compose';
1515
import reportActionPropTypes from '../home/report/reportActionPropTypes';
1616
import reportPropTypes from '../reportPropTypes';
17-
import withReportOrNotFound from '../home/report/withReportOrNotFound';
17+
import withReportAndReportActionOrNotFound from '../home/report/withReportAndReportActionOrNotFound';
1818
import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
1919
import CONST from '../../CONST';
2020
import HeaderWithBackButton from '../../components/HeaderWithBackButton';
@@ -50,18 +50,6 @@ const defaultProps = {
5050
reportActions: {},
5151
};
5252

53-
/**
54-
* Get the reportID for the associated chatReport
55-
*
56-
* @param {Object} route
57-
* @param {Object} route.params
58-
* @param {String} route.params.reportID
59-
* @returns {String}
60-
*/
61-
function getReportID(route) {
62-
return route.params.reportID.toString();
63-
}
64-
6553
function SplitBillDetailsPage(props) {
6654
const reportAction = props.reportActions[`${props.route.params.reportActionID.toString()}`];
6755
const participantAccountIDs = reportAction.originalMessage.participantAccountIDs;
@@ -108,14 +96,10 @@ SplitBillDetailsPage.displayName = 'SplitBillDetailsPage';
10896

10997
export default compose(
11098
withLocalize,
111-
withReportOrNotFound,
99+
withReportAndReportActionOrNotFound,
112100
withOnyx({
113101
personalDetails: {
114102
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
115103
},
116-
reportActions: {
117-
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getReportID(route)}`,
118-
canEvict: false,
119-
},
120104
}),
121105
)(SplitBillDetailsPage);

0 commit comments

Comments
 (0)