Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create HOC for get report data or navigate to home #12089

Merged
merged 3 commits into from
Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions src/pages/ReportDetailsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import MenuItem from '../components/MenuItem';
import Text from '../components/Text';
import CONST from '../CONST';
import reportPropTypes from './reportPropTypes';
import withReportOrNavigateHome from './home/report/withReportOrNavigateHome';

const propTypes = {
...withLocalizePropTypes,
Expand Down Expand Up @@ -66,7 +67,7 @@ class ReportDetailsPage extends Component {
key: CONST.REPORT_DETAILS_MENU_ITEM.MEMBERS,
translationKey: 'common.members',
icon: Expensicons.Users,
subtitle: props.report.participants.length,
subtitle: lodashGet(props.report, 'participants', []).length,
action: () => { Navigation.navigate(ROUTES.getReportParticipantsRoute(props.report.reportID)); },
});

Expand Down Expand Up @@ -177,10 +178,8 @@ ReportDetailsPage.propTypes = propTypes;

export default compose(
withLocalize,
withReportOrNavigateHome,
withOnyx({
report: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`,
},
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS,
},
Expand Down
5 changes: 2 additions & 3 deletions src/pages/ReportParticipantsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
import compose from '../libs/compose';
import * as ReportUtils from '../libs/ReportUtils';
import reportPropTypes from './reportPropTypes';
import withReportOrNavigateHome from './home/report/withReportOrNavigateHome';

const propTypes = {
/* Onyx Props */
Expand Down Expand Up @@ -113,12 +114,10 @@ ReportParticipantsPage.displayName = 'ReportParticipantsPage';

export default compose(
withLocalize,
withReportOrNavigateHome,
withOnyx({
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS,
},
report: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`,
},
}),
)(ReportParticipantsPage);
5 changes: 2 additions & 3 deletions src/pages/ReportSettingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Picker from '../components/Picker';
import * as ValidationUtils from '../libs/ValidationUtils';
import OfflineWithFeedback from '../components/OfflineWithFeedback';
import reportPropTypes from './reportPropTypes';
import withReportOrNavigateHome from './home/report/withReportOrNavigateHome';

const propTypes = {
/** Route params */
Expand Down Expand Up @@ -243,10 +244,8 @@ ReportSettingsPage.propTypes = propTypes;

export default compose(
withLocalize,
withReportOrNavigateHome,
withOnyx({
report: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`,
},
policies: {
key: ONYXKEYS.COLLECTION.POLICY,
},
Expand Down
59 changes: 59 additions & 0 deletions src/pages/home/report/withReportOrNavigateHome.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import PropTypes from 'prop-types';
import React, {Component} from 'react';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import getComponentDisplayName from '../../../libs/getComponentDisplayName';
import Navigation from '../../../libs/Navigation/Navigation';
import ONYXKEYS from '../../../ONYXKEYS';
import reportPropTypes from '../../reportPropTypes';

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,
};

const defaultProps = {
forwardedRef: () => {},
report: {},
};

class WithReportOrNavigateHome extends Component {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ouch, did we really need an HOC for this? Very confused about what purpose this even serves. @Beamanator would you mind summarizing why we need this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is your question "Why a HOC for this functionality" or "What is the point of the code in this HOC"? Will happily respond to either one tomorrow (end of my day & brain is foggy from timezone shifting)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes to both.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"What is the point of the code in this HOC" should be pretty straightforward: If the user is on a page that needs report data (from Onyx), we check if this.props.report is empty or not. If it's empty, we dismiss the open modal (this is what we were calling "navigate home" though that's not really accurate since we don't have a "home" screen...). If it's not empty, we show that page.

"Why a HOC for this functionality": We wanted to use this functionality across multiple pages, so thought it was clean to put it in an HOC. This lets us not have to subscribe to ${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}, on multiple pages, and instead we just wrap the page with this new HOC. We could do the same thing with a new action or lib that we call whenever these pages are mounted, but in my brain an HOC seemed more useful.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, thanks and sorry for my initial reaction. I think we got the main solution for this wrong which is the important thing. I tend to only pull out the HOC when we the code reuse is expected to be very high for a solution. But if you thought we might re-use this then the HOC is certainly one way to do that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we got the main solution for this wrong which is the important thing

I think you're referring to the fact that we aren't actually sure if we want to navigate at this point, right? Like we probably want to see if the user has access to that report or not before navigating away? (this is what our other discussion is about in a different thread, I believe)

I tend to only pull out the HOC when we the code reuse is expected to be very high for a solution. But if you thought we might re-use this then the HOC is certainly one way to do that.

Yeah exactly that was my thought process too, BUT maybe you would have waited till we have a few more use cases for this kind of code before making it a HOC - I'll happily defer to you on this, though I guess the "next steps" probably depend on what the "correct solution" is (again referring to our other discussion - showing a "you don't have accesss" page or navigating somewhere)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we aren't actually sure if we want to navigate at this point, right

Yes. I think there are different possible states of report access and different app states depending on if those reports were previously accessible or not.

Using the existence of the report in storage doesn't tell us whether you have "access" or not especially when you are offline...

Offline and never attempted to fetch a report: No way to really tell if the user has access or not but that's fine the same error message works in this case.
Offline and previous attempt returned 404: Tell them they can't access it i.e. "Hmm... it's not here"
Online and attempt returns 404: Tell them they can't access it i.e. "Hmm... it's not here"

I don't think there is any situation where we'd want to redirect without any explanation (but this deserves a wider discussion to get more input than just me 😅).

componentDidMount() {
if (!_.isEmpty(this.props.report)) {
return;
}
Navigation.dismissModal();
}

render() {
const rest = _.omit(this.props, ['forwardedRef']);

return (
<WrappedComponent
// eslint-disable-next-line react/jsx-props-no-spreading
{...rest}
ref={this.props.forwardedRef}
/>
);
}
}

WithReportOrNavigateHome.propTypes = propTypes;
WithReportOrNavigateHome.defaultProps = defaultProps;
WithReportOrNavigateHome.displayName = `withReportOrNavigateHome(${getComponentDisplayName(WrappedComponent)})`;
const withReportOrNavigateHome = React.forwardRef((props, ref) => (
// eslint-disable-next-line react/jsx-props-no-spreading
<WithReportOrNavigateHome {...props} forwardedRef={ref} />
));

return withOnyx({
report: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`,
},
})(withReportOrNavigateHome);
}