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

[TS migration] Migrate 'withPolicy.js' HOC to TypeScript #29554

Merged
merged 12 commits into from
Oct 31, 2023
2 changes: 2 additions & 0 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,9 +386,11 @@ type OnyxValues = {
// Collections
[ONYXKEYS.COLLECTION.DOWNLOAD]: OnyxTypes.Download;
[ONYXKEYS.COLLECTION.POLICY]: OnyxTypes.Policy;
[ONYXKEYS.COLLECTION.POLICY_DRAFTS]: OnyxTypes.Policy;
[ONYXKEYS.COLLECTION.POLICY_CATEGORIES]: OnyxTypes.PolicyCategory;
[ONYXKEYS.COLLECTION.POLICY_TAGS]: OnyxTypes.PolicyTags;
[ONYXKEYS.COLLECTION.POLICY_MEMBERS]: OnyxTypes.PolicyMember;
[ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS]: OnyxTypes.PolicyMember;
[ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES]: OnyxTypes.RecentlyUsedCategories;
[ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST]: OnyxTypes.PolicyMembers;
[ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT]: Record<string, number>;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import {useNavigationState} from '@react-navigation/native';
import lodashGet from 'lodash/get';
import {RouteProp, useNavigationState} from '@react-navigation/native';
import PropTypes from 'prop-types';
import React from 'react';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import getComponentDisplayName from '@libs/getComponentDisplayName';
import React, {ComponentType, ForwardedRef, forwardRef, RefAttributes} from 'react';
import {OnyxEntry, withOnyx} from 'react-native-onyx';
import policyMemberPropType from '@pages/policyMemberPropType';
import * as Policy from '@userActions/Policy';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import * as OnyxTypes from '@src/types/onyx';

/**
* @param {Object} route
* @returns {String}
*/
function getPolicyIDFromRoute(route) {
return lodashGet(route, 'params.policyID', '');
type PolicyRoute = RouteProp<{params: {policyID: string}}>;

function getPolicyIDFromRoute(route: PolicyRoute): string {
return route?.params?.policyID ?? '';
}

const policyPropTypes = {
Expand All @@ -28,10 +24,10 @@ const policyPropTypes = {
name: PropTypes.string,

/** The current user's role in the policy */
role: PropTypes.oneOf(_.values(CONST.POLICY.ROLE)),
role: PropTypes.oneOf(Object.values(CONST.POLICY.ROLE)),

/** The policy type */
type: PropTypes.oneOf(_.values(CONST.POLICY.TYPE)),
type: PropTypes.oneOf(Object.values(CONST.POLICY.TYPE)),

/** The email of the policy owner */
owner: PropTypes.string,
Expand Down Expand Up @@ -61,61 +57,49 @@ const policyPropTypes = {
policyMembers: PropTypes.objectOf(policyMemberPropType),
};

const policyDefaultProps = {
policy: {},
type WithPolicyOnyxProps = {
policy: OnyxEntry<OnyxTypes.Policy>;
policyMembers: OnyxEntry<OnyxTypes.PolicyMember>;
policyDraft: OnyxEntry<OnyxTypes.Policy>;
policyMembersDraft: OnyxEntry<OnyxTypes.PolicyMember>;
};

type WithPolicyProps = WithPolicyOnyxProps & {
route: PolicyRoute;
};

const policyDefaultProps: WithPolicyOnyxProps = {
policy: {} as OnyxTypes.Policy,
policyMembers: {},
policyDraft: {} as OnyxTypes.Policy,
policyMembersDraft: {},
};

/*
* HOC for connecting a policy in Onyx corresponding to the policyID in route params
*/
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,
export default function <TProps extends WithPolicyProps, TRef>(WrappedComponent: ComponentType<TProps & RefAttributes<TRef>>): React.ComponentType<Omit<TProps, keyof WithPolicyOnyxProps>> {
function WithPolicy(props: TProps, ref: ForwardedRef<TRef>) {
const routes = useNavigationState((state) => state.routes || []);
const currentRoute = routes?.at(-1);
Copy link
Contributor

Choose a reason for hiding this comment

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

@blazejkustra why did we use useNavigationState here to get the current route instead of just using useRoute?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I reused the logic that was written before, with Typescript migration I usually try to avoid refactoring that could cause regressions, also at the time navigation wasn't migrated yet so I just didn't want to touch it here 😄

const currentRoute = _.last(useNavigationState((state) => state.routes || []));

const policyID = getPolicyIDFromRoute(currentRoute as PolicyRoute);

...policyPropTypes,
};

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

...policyDefaultProps,
};

function WithPolicy(props) {
const currentRoute = _.last(useNavigationState((state) => state.routes || []));
const policyID = getPolicyIDFromRoute(currentRoute);

if (_.isString(policyID) && !_.isEmpty(policyID)) {
if (policyID.length > 0) {
Policy.updateLastAccessedWorkspace(policyID);
}

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

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

WithPolicyWithRef.displayName = 'WithPolicyWithRef';
WithPolicy.displayName = `WithPolicy`;

return withOnyx({
return withOnyx<TProps & RefAttributes<TRef>, WithPolicyOnyxProps>({
policy: {
key: (props) => `${ONYXKEYS.COLLECTION.POLICY}${getPolicyIDFromRoute(props.route)}`,
},
Expand All @@ -128,7 +112,7 @@ export default function (WrappedComponent) {
policyMembersDraft: {
key: (props) => `${ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS}${getPolicyIDFromRoute(props.route)}`,
},
})(WithPolicyWithRef);
})(forwardRef(WithPolicy));
}

export {policyPropTypes, policyDefaultProps};
Loading