Skip to content

Commit

Permalink
Merge pull request Expensify#29554 from software-mansion-labs/ts/with…
Browse files Browse the repository at this point in the history
…Policy

[TS migration] Migrate 'withPolicy.js' HOC to TypeScript
  • Loading branch information
Joel Bettner committed Oct 31, 2023
2 parents 5fb5ff8 + 2cbc764 commit e661395
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 52 deletions.
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);
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};

0 comments on commit e661395

Please sign in to comment.