Skip to content

Commit

Permalink
Merge pull request #23977 from dukenv0307/fix/23568
Browse files Browse the repository at this point in the history
Fix crash app when opening split bill detail page by deep link
  • Loading branch information
Li357 authored Aug 2, 2023
2 parents 0495ed8 + 70e497f commit cf4e837
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 18 deletions.
153 changes: 153 additions & 0 deletions src/pages/home/report/withReportAndReportActionOrNotFound.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
import PropTypes from 'prop-types';
import React, {useEffect, useCallback} from 'react';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import getComponentDisplayName from '../../../libs/getComponentDisplayName';
import NotFoundPage from '../../ErrorPage/NotFoundPage';
import ONYXKEYS from '../../../ONYXKEYS';
import reportPropTypes from '../../reportPropTypes';
import reportActionPropTypes from './reportActionPropTypes';
import FullscreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator';
import * as ReportUtils from '../../../libs/ReportUtils';
import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
import * as Report from '../../../libs/actions/Report';
import compose from '../../../libs/compose';
import withWindowDimensions from '../../../components/withWindowDimensions';

export default function (WrappedComponent) {
const propTypes = {
/** The HOC takes an optional ref as a prop and passes it as a ref to the wrapped component.
* 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. */
forwardedRef: PropTypes.func,

/** The report currently being looked at */
report: reportPropTypes,

/** Array of report actions for this report */
reportActions: PropTypes.shape(reportActionPropTypes),

/** The policies which the user has access to */
policies: PropTypes.objectOf(
PropTypes.shape({
/** The policy name */
name: PropTypes.string,

/** The type of the policy */
type: PropTypes.string,
}),
),

/** Route params */
route: PropTypes.shape({
params: PropTypes.shape({
/** Report ID passed via route */
reportID: PropTypes.string,

/** ReportActionID passed via route */
reportActionID: PropTypes.string,
}),
}).isRequired,

/** Beta features list */
betas: PropTypes.arrayOf(PropTypes.string),

/** Indicated whether the report data is loading */
isLoadingReportData: PropTypes.bool,

/** Is the window width narrow, like on a mobile device? */
isSmallScreenWidth: PropTypes.bool.isRequired,
};

const defaultProps = {
forwardedRef: () => {},
reportActions: {},
report: {},
policies: {},
betas: [],
isLoadingReportData: true,
};

// eslint-disable-next-line rulesdir/no-negated-variables
function WithReportAndReportActionOrNotFound(props) {
const getReportAction = useCallback(() => {
let reportAction = props.reportActions[`${props.route.params.reportActionID}`];

// Handle threads if needed
if (reportAction === undefined || reportAction.reportActionID === undefined) {
reportAction = ReportActionsUtils.getParentReportAction(props.report);
}

return reportAction;
}, [props.report, props.reportActions, props.route.params.reportActionID]);

const reportAction = getReportAction();

// For small screen, we don't call openReport API when we go to a sub report page by deeplink
// So we need to call openReport here for small screen
useEffect(() => {
if (!props.isSmallScreenWidth || (!_.isEmpty(props.report) && !_.isEmpty(reportAction))) {
return;
}
Report.openReport(props.route.params.reportID);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.isSmallScreenWidth, props.route.params.reportID]);

// Perform all the loading checks
const isLoadingReport = props.isLoadingReportData && (_.isEmpty(props.report) || !props.report.reportID);
const isLoadingReportAction = _.isEmpty(props.reportActions) || (props.report.isLoadingReportActions && _.isEmpty(getReportAction()));
const shouldHideReport = !isLoadingReport && (_.isEmpty(props.report) || !props.report.reportID || !ReportUtils.canAccessReport(props.report, props.policies, props.betas));

if ((isLoadingReport || isLoadingReportAction) && !shouldHideReport) {
return <FullscreenLoadingIndicator />;
}

// Perform the access/not found checks
if (shouldHideReport || _.isEmpty(reportAction)) {
return <NotFoundPage />;
}

const rest = _.omit(props, ['forwardedRef']);
return (
<WrappedComponent
// eslint-disable-next-line react/jsx-props-no-spreading
{...rest}
ref={props.forwardedRef}
/>
);
}

WithReportAndReportActionOrNotFound.propTypes = propTypes;
WithReportAndReportActionOrNotFound.defaultProps = defaultProps;
WithReportAndReportActionOrNotFound.displayName = `withReportAndReportActionOrNotFound(${getComponentDisplayName(WrappedComponent)})`;

// eslint-disable-next-line rulesdir/no-negated-variables
const withReportAndReportActionOrNotFound = React.forwardRef((props, ref) => (
<WithReportAndReportActionOrNotFound
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
forwardedRef={ref}
/>
));

return compose(
withWindowDimensions,
withOnyx({
report: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`,
},
isLoadingReportData: {
key: ONYXKEYS.IS_LOADING_REPORT_DATA,
},
betas: {
key: ONYXKEYS.BETAS,
},
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
},
reportActions: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${route.params.reportID}`,
canEvict: false,
},
}),
)(withReportAndReportActionOrNotFound);
}
20 changes: 2 additions & 18 deletions src/pages/iou/SplitBillDetailsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize
import compose from '../../libs/compose';
import reportActionPropTypes from '../home/report/reportActionPropTypes';
import reportPropTypes from '../reportPropTypes';
import withReportOrNotFound from '../home/report/withReportOrNotFound';
import withReportAndReportActionOrNotFound from '../home/report/withReportAndReportActionOrNotFound';
import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
import CONST from '../../CONST';
import HeaderWithBackButton from '../../components/HeaderWithBackButton';
Expand Down Expand Up @@ -50,18 +50,6 @@ const defaultProps = {
reportActions: {},
};

/**
* Get the reportID for the associated chatReport
*
* @param {Object} route
* @param {Object} route.params
* @param {String} route.params.reportID
* @returns {String}
*/
function getReportID(route) {
return route.params.reportID.toString();
}

function SplitBillDetailsPage(props) {
const reportAction = props.reportActions[`${props.route.params.reportActionID.toString()}`];
const participantAccountIDs = reportAction.originalMessage.participantAccountIDs;
Expand Down Expand Up @@ -108,14 +96,10 @@ SplitBillDetailsPage.displayName = 'SplitBillDetailsPage';

export default compose(
withLocalize,
withReportOrNotFound,
withReportAndReportActionOrNotFound,
withOnyx({
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
reportActions: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getReportID(route)}`,
canEvict: false,
},
}),
)(SplitBillDetailsPage);

0 comments on commit cf4e837

Please sign in to comment.