diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 60b2ed63ab49..9d273cc53454 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -349,47 +349,48 @@ type MoneyRequestNavigatorParamList = { iouType: string; reportID: string; currency: string; - backTo: string; + backTo: Routes; }; [SCREENS.MONEY_REQUEST.STEP_DATE]: { action: ValueOf; iouType: ValueOf; transactionID: string; reportID: string; - backTo: string; + backTo: Routes; }; [SCREENS.MONEY_REQUEST.STEP_DESCRIPTION]: { action: ValueOf; iouType: ValueOf; transactionID: string; reportID: string; - backTo: string; + backTo: Routes; + reportActionID: string; }; [SCREENS.MONEY_REQUEST.STEP_CATEGORY]: { action: ValueOf; iouType: ValueOf; transactionID: string; reportID: string; - backTo: string; + backTo: Routes; }; [SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT]: { iouType: string; transactionID: string; reportID: string; - backTo: string; + backTo: Routes; }; [SCREENS.MONEY_REQUEST.STEP_TAG]: { action: ValueOf; iouType: ValueOf; transactionID: string; reportID: string; - backTo: string; + backTo: Routes; }; [SCREENS.MONEY_REQUEST.STEP_TAX_RATE]: { iouType: string; transactionID: string; reportID: string; - backTo: string; + backTo: Routes; }; [SCREENS.MONEY_REQUEST.STEP_WAYPOINT]: { iouType: ValueOf; @@ -404,7 +405,7 @@ type MoneyRequestNavigatorParamList = { iouType: ValueOf; transactionID: string; reportID: string; - backTo: string; + backTo: Routes; }; [SCREENS.IOU_SEND.ENABLE_PAYMENTS]: undefined; [SCREENS.IOU_SEND.ADD_BANK_ACCOUNT]: undefined; @@ -420,7 +421,7 @@ type MoneyRequestNavigatorParamList = { iouType: ValueOf; transactionID: string; reportID: string; - backTo: string; + backTo: Routes; }; [SCREENS.MONEY_REQUEST.RECEIPT]: { iouType: string; diff --git a/src/pages/iou/request/step/IOURequestStepDate.js b/src/pages/iou/request/step/IOURequestStepDate.tsx similarity index 57% rename from src/pages/iou/request/step/IOURequestStepDate.js rename to src/pages/iou/request/step/IOURequestStepDate.tsx index f7b8b1ca3869..682204a4510f 100644 --- a/src/pages/iou/request/step/IOURequestStepDate.js +++ b/src/pages/iou/request/step/IOURequestStepDate.tsx @@ -1,58 +1,46 @@ -import lodashGet from 'lodash/get'; import lodashIsEmpty from 'lodash/isEmpty'; -import PropTypes from 'prop-types'; import React from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import categoryPropTypes from '@components/categoryPropTypes'; import DatePicker from '@components/DatePicker'; import FormProvider from '@components/Form/FormProvider'; import InputWrapper from '@components/Form/InputWrapper'; -import tagPropTypes from '@components/tagPropTypes'; -import transactionPropTypes from '@components/transactionPropTypes'; +import type {FormOnyxValues} from '@components/Form/types'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as IOUUtils from '@libs/IOUUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as TransactionUtils from '@libs/TransactionUtils'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {policyPropTypes} from '@src/pages/workspace/withPolicy'; +import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/MoneyRequestDateForm'; -import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; +import type * as OnyxTypes from '@src/types/onyx'; import StepScreenWrapper from './StepScreenWrapper'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; +import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: IOURequestStepRoutePropTypes.isRequired, - - /** Onyx Props */ - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - transaction: transactionPropTypes, - +type IOURequestStepDateOnyxProps = { /** The draft transaction that holds data to be persisted on the current transaction */ - splitDraftTransaction: transactionPropTypes, + splitDraftTransaction: OnyxEntry; /** The policy of the report */ - policy: policyPropTypes.policy, + policy: OnyxEntry; /** Collection of categories attached to a policy */ - policyCategories: PropTypes.objectOf(categoryPropTypes), + policyCategories: OnyxEntry; /** Collection of tags attached to a policy */ - policyTags: tagPropTypes, + policyTags: OnyxEntry; }; -const defaultProps = { - transaction: {}, - splitDraftTransaction: {}, - policy: null, - policyTags: null, - policyCategories: null, -}; +type IOURequestStepDateProps = IOURequestStepDateOnyxProps & + WithWritableReportOrNotFoundProps & { + /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ + transaction: OnyxEntry; + }; function IOURequestStepDate({ route: { @@ -63,7 +51,7 @@ function IOURequestStepDate({ policy, policyTags, policyCategories, -}) { +}: IOURequestStepDateProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const isEditing = action === CONST.IOU.ACTION.EDIT; @@ -75,11 +63,7 @@ function IOURequestStepDate({ Navigation.goBack(backTo); }; - /** - * @param {Object} value - * @param {String} value.moneyRequestCreated - */ - const updateDate = (value) => { + const updateDate = (value: FormOnyxValues) => { const newCreated = value.moneyRequestCreated; // Only update created if it has changed @@ -90,15 +74,15 @@ function IOURequestStepDate({ // In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value if (isEditingSplitBill) { - IOU.setDraftSplitTransaction(transaction.transactionID, {created: newCreated}); + IOU.setDraftSplitTransaction(transaction?.transactionID ?? '0', {created: newCreated}); navigateBack(); return; } - IOU.setMoneyRequestCreated(transaction.transactionID, newCreated, action === CONST.IOU.ACTION.CREATE); + IOU.setMoneyRequestCreated(transaction?.transactionID ?? '0', newCreated, action === CONST.IOU.ACTION.CREATE); if (isEditing) { - IOU.updateMoneyRequestDate(transaction.transactionID, reportID, newCreated, policy, policyTags, policyCategories); + IOU.updateMoneyRequestDate(transaction?.transactionID ?? '0', reportID, newCreated, policy, policyTags, policyCategories); } navigateBack(); @@ -108,7 +92,7 @@ function IOURequestStepDate({ @@ -132,28 +116,29 @@ function IOURequestStepDate({ ); } -IOURequestStepDate.propTypes = propTypes; -IOURequestStepDate.defaultProps = defaultProps; IOURequestStepDate.displayName = 'IOURequestStepDate'; -export default compose( - withWritableReportOrNotFound, - withFullTransactionOrNotFound, - withOnyx({ - splitDraftTransaction: { - key: ({route}) => { - const transactionID = lodashGet(route, 'params.transactionID', 0); - return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`; - }, - }, - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, - }, - policyCategories: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, - }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, +const IOURequestStepDateWithOnyx = withOnyx({ + splitDraftTransaction: { + key: ({route}) => { + const transactionID = route?.params.transactionID ?? 0; + return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`; }, - }), -)(IOURequestStepDate); + }, + policy: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, + }, + policyCategories: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, + }, + policyTags: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, + }, +})(IOURequestStepDate); + +// eslint-disable-next-line rulesdir/no-negated-variables +const IOURequestStepDateWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepDateWithOnyx); +// eslint-disable-next-line rulesdir/no-negated-variables +const IOURequestStepDateWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepDateWithWritableReportOrNotFound); + +export default IOURequestStepDateWithFullTransactionOrNotFound; diff --git a/src/pages/iou/request/step/IOURequestStepDescription.js b/src/pages/iou/request/step/IOURequestStepDescription.tsx similarity index 57% rename from src/pages/iou/request/step/IOURequestStepDescription.js rename to src/pages/iou/request/step/IOURequestStepDescription.tsx index 8c3327a5ee5c..d075ed81c956 100644 --- a/src/pages/iou/request/step/IOURequestStepDescription.js +++ b/src/pages/iou/request/step/IOURequestStepDescription.tsx @@ -1,81 +1,57 @@ import {useFocusEffect} from '@react-navigation/native'; -import lodashGet from 'lodash/get'; import lodashIsEmpty from 'lodash/isEmpty'; -import PropTypes from 'prop-types'; import React, {useCallback, useRef} from 'react'; import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import categoryPropTypes from '@components/categoryPropTypes'; import FormProvider from '@components/Form/FormProvider'; import InputWrapperWithRef from '@components/Form/InputWrapper'; -import tagPropTypes from '@components/tagPropTypes'; +import type {FormInputErrors, FormOnyxValues} from '@components/Form/types'; +import type {AnimatedTextInputRef} from '@components/RNTextInput'; import TextInput from '@components/TextInput'; -import transactionPropTypes from '@components/transactionPropTypes'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import updateMultilineInputRange from '@libs/updateMultilineInputRange'; -import reportActionPropTypes from '@pages/home/report/reportActionPropTypes'; -import reportPropTypes from '@pages/reportPropTypes'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import {policyPropTypes} from '@src/pages/workspace/withPolicy'; +import type SCREENS from '@src/SCREENS'; import INPUT_IDS from '@src/types/form/MoneyRequestDescriptionForm'; -import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; +import type * as OnyxTypes from '@src/types/onyx'; import StepScreenWrapper from './StepScreenWrapper'; import withFullTransactionOrNotFound from './withFullTransactionOrNotFound'; +import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound'; import withWritableReportOrNotFound from './withWritableReportOrNotFound'; -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: IOURequestStepRoutePropTypes.isRequired, - - /** Onyx Props */ - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - transaction: transactionPropTypes, - +type IOURequestStepDescriptionOnyxProps = { /** The draft transaction that holds data to be persisted on the current transaction */ - splitDraftTransaction: transactionPropTypes, + splitDraftTransaction: OnyxEntry; /** The policy of the report */ - policy: policyPropTypes.policy, + policy: OnyxEntry; /** Collection of categories attached to a policy */ - policyCategories: PropTypes.objectOf(categoryPropTypes), + policyCategories: OnyxEntry; /** Collection of tags attached to a policy */ - policyTags: tagPropTypes, + policyTags: OnyxEntry; /** The actions from the parent report */ - reportActions: PropTypes.shape(reportActionPropTypes), + reportActions: OnyxEntry; /** Session info for the currently logged in user. */ - session: PropTypes.shape({ - /** Currently logged in user accountID */ - accountID: PropTypes.number, - - /** Currently logged in user email */ - email: PropTypes.string, - }).isRequired, - - /** The report attached to the transaction */ - report: reportPropTypes, + session: OnyxEntry; }; -const defaultProps = { - transaction: {}, - splitDraftTransaction: {}, - policy: null, - policyTags: null, - policyCategories: null, - reportActions: {}, - report: {}, -}; +type IOURequestStepDescriptionProps = IOURequestStepDescriptionOnyxProps & + WithWritableReportOrNotFoundProps & { + /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ + transaction: OnyxEntry; + }; function IOURequestStepDescription({ route: { @@ -89,15 +65,14 @@ function IOURequestStepDescription({ reportActions, session, report, -}) { +}: IOURequestStepDescriptionProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const inputRef = useRef(null); - const focusTimeoutRef = useRef(null); + const inputRef = useRef(null); + const focusTimeoutRef = useRef(null); // In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value const isEditingSplitBill = iouType === CONST.IOU.TYPE.SPLIT && action === CONST.IOU.ACTION.EDIT; - const currentDescription = - isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? lodashGet(splitDraftTransaction, 'comment.comment', '') : lodashGet(transaction, 'comment.comment', ''); + const currentDescription = isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction?.comment.comment ?? '' : transaction?.comment.comment ?? ''; useFocusEffect( useCallback(() => { focusTimeoutRef.current = setTimeout(() => { @@ -115,11 +90,9 @@ function IOURequestStepDescription({ ); /** - * @param {Object} values - * @param {String} values.title - * @returns {Object} - An object containing the errors for each inputID + * @returns - An object containing the errors for each inputID */ - const validate = useCallback((values) => { + const validate = useCallback((values: FormOnyxValues): FormInputErrors => { const errors = {}; if (values.moneyRequestComment.length > CONST.DESCRIPTION_LIMIT) { @@ -136,11 +109,7 @@ function IOURequestStepDescription({ Navigation.goBack(backTo); }; - /** - * @param {Object} value - * @param {String} value.moneyRequestComment - */ - const updateComment = (value) => { + const updateComment = (value: FormOnyxValues) => { const newComment = value.moneyRequestComment.trim(); // Only update comment if it has changed @@ -151,24 +120,25 @@ function IOURequestStepDescription({ // In the split flow, when editing we use SPLIT_TRANSACTION_DRAFT to save draft value if (isEditingSplitBill) { - IOU.setDraftSplitTransaction(transaction.transactionID, {comment: newComment}); + IOU.setDraftSplitTransaction(transaction?.transactionID ?? '0', {comment: newComment}); navigateBack(); return; } - IOU.setMoneyRequestDescription(transaction.transactionID, newComment, action === CONST.IOU.ACTION.CREATE); + IOU.setMoneyRequestDescription(transaction?.transactionID ?? '0', newComment, action === CONST.IOU.ACTION.CREATE); if (action === CONST.IOU.ACTION.EDIT) { - IOU.updateMoneyRequestDescription(transaction.transactionID, reportID, newComment, policy, policyTags, policyCategories); + IOU.updateMoneyRequestDescription(transaction?.transactionID ?? '0', reportID, newComment, policy, policyTags, policyCategories); } navigateBack(); }; - const reportAction = reportActions[report.parentReportActionID || reportActionID]; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- nullish coalescing doesn't achieve the same result in this case + const reportAction = reportActions?.[report?.parentReportActionID || reportActionID] ?? null; const isEditing = action === CONST.IOU.ACTION.EDIT; const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; - const canEditSplitBill = isSplitBill && reportAction && session.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); + const canEditSplitBill = isSplitBill && reportAction && session?.accountID === reportAction.actorAccountID && TransactionUtils.areRequiredFieldsEmpty(transaction); // eslint-disable-next-line rulesdir/no-negated-variables const shouldShowNotFoundPage = isEditing && (isSplitBill ? !canEditSplitBill : !ReportUtils.canEditMoneyRequest(reportAction)); return ( @@ -213,46 +183,47 @@ function IOURequestStepDescription({ ); } -IOURequestStepDescription.propTypes = propTypes; -IOURequestStepDescription.defaultProps = defaultProps; IOURequestStepDescription.displayName = 'IOURequestStepDescription'; -export default compose( - withWritableReportOrNotFound, - withFullTransactionOrNotFound, - withOnyx({ - splitDraftTransaction: { - key: ({route}) => { - const transactionID = lodashGet(route, 'params.transactionID', 0); - return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`; - }, - }, - policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, - }, - policyCategories: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, +const IOURequestStepDescriptionWithOnyx = withOnyx({ + splitDraftTransaction: { + key: ({route}) => { + const transactionID = route?.params.transactionID ?? 0; + return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`; }, - policyTags: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, - }, - reportActions: { - key: ({ - report, - route: { - params: {action, iouType}, - }, - }) => { - let reportID = '0'; - if (action === CONST.IOU.ACTION.EDIT) { - reportID = iouType === CONST.IOU.TYPE.SPLIT ? report.reportID : report.parentReportID; - } - return `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`; + }, + policy: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report ? report.policyID : '0'}`, + }, + policyCategories: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report ? report.policyID : '0'}`, + }, + policyTags: { + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`, + }, + reportActions: { + key: ({ + report, + route: { + params: {action, iouType}, }, - canEvict: false, + }) => { + let reportID = '0'; + if (action === CONST.IOU.ACTION.EDIT) { + reportID = iouType === CONST.IOU.TYPE.SPLIT ? report?.reportID ?? '0' : report?.parentReportID ?? '0'; + } + return `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`; }, - session: { - key: ONYXKEYS.SESSION, - }, - }), -)(IOURequestStepDescription); + canEvict: false, + }, + session: { + key: ONYXKEYS.SESSION, + }, +})(IOURequestStepDescription); + +// eslint-disable-next-line rulesdir/no-negated-variables +const IOURequestStepDescriptionWithWritableReportOrNotFound = withWritableReportOrNotFound(IOURequestStepDescriptionWithOnyx); +// eslint-disable-next-line rulesdir/no-negated-variables +const IOURequestStepDescriptionWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepDescriptionWithWritableReportOrNotFound); + +export default IOURequestStepDescriptionWithFullTransactionOrNotFound; diff --git a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx index 4e61ac944aac..a186288e8a27 100644 --- a/src/pages/iou/request/step/IOURequestStepWaypoint.tsx +++ b/src/pages/iou/request/step/IOURequestStepWaypoint.tsx @@ -27,6 +27,7 @@ import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; import type {Waypoint} from '@src/types/onyx/Transaction'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; @@ -41,10 +42,10 @@ type IOURequestStepWaypointOnyxProps = { userLocation: OnyxEntry; }; -type IOURequestStepWaypointProps = { - transaction: OnyxEntry; -} & IOURequestStepWaypointOnyxProps & - WithWritableReportOrNotFoundProps; +type IOURequestStepWaypointProps = IOURequestStepWaypointOnyxProps & + WithWritableReportOrNotFoundProps & { + transaction: OnyxEntry; + }; function IOURequestStepWaypoint({ route: { diff --git a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx index d5d27d8268b1..de49a451da08 100644 --- a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx +++ b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx @@ -17,11 +17,13 @@ type WithWritableReportOrNotFoundOnyxProps = { report: OnyxEntry; }; -type Route = RouteProp; +type MoneyRequestRouteName = typeof SCREENS.MONEY_REQUEST.STEP_WAYPOINT | typeof SCREENS.MONEY_REQUEST.STEP_DESCRIPTION; -type WithWritableReportOrNotFoundProps = WithWritableReportOrNotFoundOnyxProps & {route: Route}; +type Route = RouteProp; -export default function ( +type WithWritableReportOrNotFoundProps = WithWritableReportOrNotFoundOnyxProps & {route: Route}; + +export default function , TRef>( WrappedComponent: ComponentType>, ): React.ComponentType, keyof WithWritableReportOrNotFoundOnyxProps>> { // eslint-disable-next-line rulesdir/no-negated-variables