diff --git a/src/pages/iou/MoneyRequestWaypointPage.tsx b/src/pages/iou/MoneyRequestWaypointPage.tsx index 35778f37a9ef..dd65b76c8d38 100644 --- a/src/pages/iou/MoneyRequestWaypointPage.tsx +++ b/src/pages/iou/MoneyRequestWaypointPage.tsx @@ -15,6 +15,7 @@ type MoneyRequestWaypointPageProps = StackScreenProps({ - userLocation: { - key: ONYXKEYS.USER_LOCATION, - }, - recentWaypoints: { - key: ONYXKEYS.NVP_RECENT_WAYPOINTS, +// eslint-disable-next-line rulesdir/no-negated-variables +const IOURequestStepWaypointWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepWaypoint); +// eslint-disable-next-line rulesdir/no-negated-variables +const IOURequestStepWaypointWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepWaypointWithWritableReportOrNotFound); - // Only grab the most recent 5 waypoints because that's all that is shown in the UI. This also puts them into the format of data - // that the google autocomplete component expects for it's "predefined places" feature. - selector: (waypoints) => - (waypoints ? waypoints.slice(0, 5) : []).map((waypoint) => ({ - name: waypoint.name, - description: waypoint.address ?? '', - geometry: { - location: { - lat: waypoint.lat ?? 0, - lng: waypoint.lng ?? 0, - }, - }, - })), - }, - })(IOURequestStepWaypoint), - ), -); +export default withOnyx({ + userLocation: { + key: ONYXKEYS.USER_LOCATION, + }, + recentWaypoints: { + key: ONYXKEYS.NVP_RECENT_WAYPOINTS, + + // Only grab the most recent 5 waypoints because that's all that is shown in the UI. This also puts them into the format of data + // that the google autocomplete component expects for it's "predefined places" feature. + selector: (waypoints) => + (waypoints ? waypoints.slice(0, 5) : []).map((waypoint) => ({ + name: waypoint.name, + description: waypoint.address ?? '', + geometry: { + location: { + lat: waypoint.lat ?? 0, + lng: waypoint.lng ?? 0, + }, + }, + })), + }, + // @ts-expect-error TODO: Remove this once withFullTransactionOrNotFound (https://github.com/Expensify/App/issues/36123) is migrated to TypeScript. +})(IOURequestStepWaypointWithFullTransactionOrNotFound); diff --git a/src/pages/iou/request/step/withFullTransactionOrNotFound.js b/src/pages/iou/request/step/withFullTransactionOrNotFound.js new file mode 100644 index 000000000000..7cdbb3484999 --- /dev/null +++ b/src/pages/iou/request/step/withFullTransactionOrNotFound.js @@ -0,0 +1,78 @@ +import {useIsFocused} from '@react-navigation/native'; +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import React from 'react'; +import {withOnyx} from 'react-native-onyx'; +import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; +import transactionPropTypes from '@components/transactionPropTypes'; +import getComponentDisplayName from '@libs/getComponentDisplayName'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; + +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 corresponding to the reportID in the route params */ + transaction: transactionPropTypes, + + route: IOURequestStepRoutePropTypes.isRequired, +}; + +const defaultProps = { + forwardedRef: () => {}, + transaction: {}, +}; + +export default function (WrappedComponent) { + // eslint-disable-next-line rulesdir/no-negated-variables + function WithFullTransactionOrNotFound({forwardedRef, ...props}) { + const { + transaction: {transactionID}, + } = props; + + const isFocused = useIsFocused(); + + // If the transaction does not have a transactionID, then the transaction no longer exists in Onyx as a full transaction and the not-found page should be shown. + // In addition, the not-found page should be shown only if the component screen's route is active (i.e. is focused). + // This is to prevent it from showing when the modal is being dismissed while navigating to a different route (e.g. on requesting money). + if (!transactionID) { + return ; + } + + return ( + + ); + } + + WithFullTransactionOrNotFound.propTypes = propTypes; + WithFullTransactionOrNotFound.defaultProps = defaultProps; + WithFullTransactionOrNotFound.displayName = `withFullTransactionOrNotFound(${getComponentDisplayName(WrappedComponent)})`; + + // eslint-disable-next-line rulesdir/no-negated-variables + const WithFullTransactionOrNotFoundWithRef = React.forwardRef((props, ref) => ( + + )); + + WithFullTransactionOrNotFoundWithRef.displayName = 'WithFullTransactionOrNotFoundWithRef'; + + return withOnyx({ + transaction: { + key: ({route}) => { + const transactionID = lodashGet(route, 'params.transactionID', 0); + const userAction = lodashGet(route, 'params.action', CONST.IOU.ACTION.CREATE); + return `${userAction === CONST.IOU.ACTION.CREATE ? ONYXKEYS.COLLECTION.TRANSACTION_DRAFT : ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; + }, + }, + })(WithFullTransactionOrNotFoundWithRef); +} diff --git a/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx b/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx deleted file mode 100644 index d4e605c6a7c5..000000000000 --- a/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import type {RouteProp} from '@react-navigation/native'; -import {useIsFocused} from '@react-navigation/native'; -import type {ComponentType, ForwardedRef, RefAttributes} from 'react'; -import React, {forwardRef} from 'react'; -import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; -import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; -import getComponentDisplayName from '@libs/getComponentDisplayName'; -import type {MoneyRequestNavigatorParamList} from '@libs/Navigation/types'; -import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; -import type SCREENS from '@src/SCREENS'; -import type {Transaction} from '@src/types/onyx'; - -type WithFullTransactionOrNotFoundOnyxProps = { - /** Indicates whether the report data is loading */ - transaction: OnyxEntry; -}; - -type Route = RouteProp; - -type WithFullTransactionOrNotFoundProps = WithFullTransactionOrNotFoundOnyxProps & {route: Route}; - -export default function (WrappedComponent: ComponentType>) { - // eslint-disable-next-line rulesdir/no-negated-variables - function WithFullTransactionOrNotFound(props: TProps, ref: ForwardedRef) { - const transactionID = props.transaction?.transactionID; - - const isFocused = useIsFocused(); - - // If the transaction does not have a transactionID, then the transaction no longer exists in Onyx as a full transaction and the not-found page should be shown. - // In addition, the not-found page should be shown only if the component screen's route is active (i.e. is focused). - // This is to prevent it from showing when the modal is being dismissed while navigating to a different route (e.g. on requesting money). - if (!transactionID) { - return ; - } - - return ( - - ); - } - - WithFullTransactionOrNotFound.displayName = `withFullTransactionOrNotFound(${getComponentDisplayName(WrappedComponent)})`; - - return withOnyx, WithFullTransactionOrNotFoundOnyxProps>({ - transaction: { - key: ({route}) => { - const transactionID = route.params.transactionID ?? 0; - const userAction = route.params.action ?? CONST.IOU.ACTION.CREATE; - - if (userAction === CONST.IOU.ACTION.CREATE) { - return `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}` as `${typeof ONYXKEYS.COLLECTION.TRANSACTION}${string}`; - } - return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`; - }, - }, - })(forwardRef(WithFullTransactionOrNotFound)); -} - -export type {WithFullTransactionOrNotFoundProps};