diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 7fee9b5497ce..771f58599a9c 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -382,7 +382,7 @@ const ROUTES = { }, MONEY_REQUEST_STEP_WAYPOINT: { route: ':action/:iouType/waypoint/:transactionID/:reportID/:pageIndex', - getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID: string, pageIndex = '', backTo = '') => + getRoute: (action: ValueOf, iouType: ValueOf, transactionID: string, reportID?: string, pageIndex = '', backTo = '') => getUrlWithBackToParam(`${action}/${iouType}/waypoint/${transactionID}/${reportID}/${pageIndex}`, backTo), }, // This URL is used as a redirect to one of the create tabs below. This is so that we can message users with a link diff --git a/src/components/DistanceRequest/DistanceRequestRenderItem.tsx b/src/components/DistanceRequest/DistanceRequestRenderItem.tsx index 57e4fb0b530e..f4b11c159326 100644 --- a/src/components/DistanceRequest/DistanceRequestRenderItem.tsx +++ b/src/components/DistanceRequest/DistanceRequestRenderItem.tsx @@ -17,7 +17,7 @@ type DistanceRequestProps = { onSecondaryInteraction?: () => void; /** Function to get the index of the item */ - getIndex?: () => number; + getIndex?: () => number | undefined; /** Whether the item is active */ isActive?: boolean; diff --git a/src/libs/Navigation/OnyxTabNavigator.tsx b/src/libs/Navigation/OnyxTabNavigator.tsx index deab975e067b..734d8ee2a373 100644 --- a/src/libs/Navigation/OnyxTabNavigator.tsx +++ b/src/libs/Navigation/OnyxTabNavigator.tsx @@ -5,6 +5,7 @@ import React from 'react'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import type {TabSelectorProps} from '@components/TabSelector/TabSelector'; +import type {IOURequestType} from '@libs/actions/IOU'; import Tab from '@userActions/Tab'; import ONYXKEYS from '@src/ONYXKEYS'; import type {SelectedTabRequest} from '@src/types/onyx'; @@ -24,7 +25,7 @@ type OnyxTabNavigatorProps = OnyxTabNavigatorOnyxProps & selectedTab?: SelectedTabRequest; /** A function triggered when a tab has been selected */ - onTabSelected?: (newIouType: string) => void; + onTabSelected?: (newIouType: IOURequestType) => void; tabBar: (props: TabSelectorProps) => React.ReactNode; @@ -52,7 +53,7 @@ function OnyxTabNavigator({id, selectedTab, children, onTabSelected = () => {}, const index = state.index; const routeNames = state.routeNames; Tab.setSelectedTab(id, routeNames[index] as SelectedTabRequest); - onTabSelected(routeNames[index]); + onTabSelected(routeNames[index] as IOURequestType); }, ...(screenListeners ?? {}), }} diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index f378d17dc0b0..1776dd75726b 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -11,6 +11,7 @@ import type { Route, } from '@react-navigation/native'; import type {ValueOf} from 'type-fest'; +import type {IOURequestType} from '@libs/actions/IOU'; import type CONST from '@src/CONST'; import type {Country} from '@src/CONST'; import type NAVIGATORS from '@src/NAVIGATORS'; @@ -349,13 +350,6 @@ type RoomInviteNavigatorParamList = { }; type MoneyRequestNavigatorParamList = { - [SCREENS.MONEY_REQUEST.STEP_AMOUNT]: { - action: ValueOf; - iouType: ValueOf; - transactionID: string; - reportID: string; - backTo: string; - }; [SCREENS.MONEY_REQUEST.PARTICIPANTS]: { iouType: string; reportID: string; @@ -431,7 +425,7 @@ type MoneyRequestNavigatorParamList = { threadReportID: number; }; [SCREENS.MONEY_REQUEST.STEP_DISTANCE]: { - action: string; + action: ValueOf; iouType: ValueOf; transactionID: string; reportID: string; @@ -441,6 +435,29 @@ type MoneyRequestNavigatorParamList = { iouType: string; reportID: string; }; + [SCREENS.MONEY_REQUEST.CREATE]: { + iouType: ValueOf; + reportID: string; + transactionID: string; + + // These are not used in the screen, but are needed for the navigation + // for IOURequestStepDistance and IOURequestStepAmount components + backTo: never; + action: never; + }; + [SCREENS.MONEY_REQUEST.START]: { + iouType: ValueOf; + reportID: string; + transactionID: string; + iouRequestType: IOURequestType; + }; + [SCREENS.MONEY_REQUEST.STEP_AMOUNT]: { + iouType: ValueOf; + reportID: string; + transactionID: string; + backTo: Routes; + action: ValueOf; + }; [SCREENS.MONEY_REQUEST.STEP_PARTICIPANTS]: { iouType: ValueOf; transactionID: string; diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts index 55dd2eb4fe39..470be9a4f345 100644 --- a/src/libs/actions/IOU.ts +++ b/src/libs/actions/IOU.ts @@ -2177,15 +2177,24 @@ function updateMoneyRequestTaxRate( API.write('UpdateMoneyRequestTaxRate', params, onyxData); } +type UpdateMoneyRequestDistanceParams = { + transactionID: string; + transactionThreadReportID: string; + waypoints: WaypointCollection; + policy?: OnyxEntry; + policyTagList?: OnyxEntry; + policyCategories?: OnyxEntry; +}; + /** Updates the waypoints of a distance money request */ -function updateMoneyRequestDistance( - transactionID: string, - transactionThreadReportID: string, - waypoints: WaypointCollection, - policy: OnyxEntry, - policyTagList: OnyxEntry, - policyCategories: OnyxEntry, -) { +function updateMoneyRequestDistance({ + transactionID, + transactionThreadReportID, + waypoints, + policy = {} as OnyxTypes.Policy, + policyTagList = {}, + policyCategories = {}, +}: UpdateMoneyRequestDistanceParams) { const transactionChanges: TransactionChanges = { waypoints, }; @@ -3820,21 +3829,39 @@ function editMoneyRequest( } } +type UpdateMoneyRequestAmountAndCurrencyParams = { + transactionID: string; + transactionThreadReportID: string; + currency: string; + amount: number; + policy?: OnyxEntry; + policyTagList?: OnyxEntry; + policyCategories?: OnyxEntry; +}; + /** Updates the amount and currency fields of a money request */ -function updateMoneyRequestAmountAndCurrency( - transactionID: string, - transactionThreadReportID: string, - currency: string, - amount: number, - policy: OnyxEntry, - policyTagList: OnyxEntry, - policyCategories: OnyxEntry, -) { +function updateMoneyRequestAmountAndCurrency({ + transactionID, + transactionThreadReportID, + currency, + amount, + policy, + policyTagList, + policyCategories, +}: UpdateMoneyRequestAmountAndCurrencyParams) { const transactionChanges = { amount, currency, }; - const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, policy, policyTagList, policyCategories, true); + const {params, onyxData} = getUpdateMoneyRequestParams( + transactionID, + transactionThreadReportID, + transactionChanges, + policy ?? null, + policyTagList ?? null, + policyCategories ?? null, + true, + ); API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_AMOUNT_AND_CURRENCY, params, onyxData); } diff --git a/src/pages/iou/request/IOURequestRedirectToStartPage.js b/src/pages/iou/request/IOURequestRedirectToStartPage.tsx similarity index 72% rename from src/pages/iou/request/IOURequestRedirectToStartPage.js rename to src/pages/iou/request/IOURequestRedirectToStartPage.tsx index 2da235743705..033b3b3e2edd 100644 --- a/src/pages/iou/request/IOURequestRedirectToStartPage.js +++ b/src/pages/iou/request/IOURequestRedirectToStartPage.tsx @@ -1,34 +1,22 @@ -import PropTypes from 'prop-types'; import React, {useEffect} from 'react'; -import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import ScreenWrapper from '@components/ScreenWrapper'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; +import type {WithWritableReportOrNotFoundProps} from './step/withWritableReportOrNotFound'; -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: PropTypes.shape({ - /** Route specific parameters used on this screen */ - params: PropTypes.shape({ - /** The type of IOU report, i.e. bill, request, send */ - iouType: PropTypes.oneOf(_.values(CONST.IOU.TYPE)).isRequired, - - /** The type of IOU Request, i.e. manual, scan, distance */ - iouRequestType: PropTypes.oneOf(_.values(CONST.IOU.REQUEST_TYPE)).isRequired, - }), - }).isRequired, -}; +type IOURequestRedirectToStartPageProps = WithWritableReportOrNotFoundProps; function IOURequestRedirectToStartPage({ route: { params: {iouType, iouRequestType}, }, -}) { - const isIouTypeValid = _.values(CONST.IOU.TYPE).includes(iouType); - const isIouRequestTypeValid = _.values(CONST.IOU.REQUEST_TYPE).includes(iouRequestType); +}: IOURequestRedirectToStartPageProps) { + const isIouTypeValid = Object.values(CONST.IOU.TYPE).includes(iouType); + const isIouRequestTypeValid = Object.values(CONST.IOU.REQUEST_TYPE).includes(iouRequestType); useEffect(() => { if (!isIouTypeValid || !isIouRequestTypeValid) { @@ -64,6 +52,5 @@ function IOURequestRedirectToStartPage({ } IOURequestRedirectToStartPage.displayName = 'IOURequestRedirectToStartPage'; -IOURequestRedirectToStartPage.propTypes = propTypes; export default IOURequestRedirectToStartPage; diff --git a/src/pages/iou/request/IOURequestStartPage.js b/src/pages/iou/request/IOURequestStartPage.tsx similarity index 78% rename from src/pages/iou/request/IOURequestStartPage.js rename to src/pages/iou/request/IOURequestStartPage.tsx index e9057fef9226..6c69598893c5 100644 --- a/src/pages/iou/request/IOURequestStartPage.js +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -1,17 +1,14 @@ import {useFocusEffect, useNavigation} from '@react-navigation/native'; -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React, {useCallback, useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView'; import DragAndDropProvider from '@components/DragAndDrop/Provider'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import TabSelector from '@components/TabSelector/TabSelector'; -import transactionPropTypes from '@components/transactionPropTypes'; import useLocalize from '@hooks/useLocalize'; import usePermissions from '@hooks/usePermissions'; import usePrevious from '@hooks/usePrevious'; @@ -23,42 +20,33 @@ import Navigation from '@libs/Navigation/Navigation'; import OnyxTabNavigator, {TopTab} from '@libs/Navigation/OnyxTabNavigator'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; -import reportPropTypes from '@pages/reportPropTypes'; import * as IOU from '@userActions/IOU'; +import type {IOURequestType} from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; +import type {Policy, Report, SelectedTabRequest, Transaction} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; import IOURequestStepAmount from './step/IOURequestStepAmount'; import IOURequestStepDistance from './step/IOURequestStepDistance'; -import IOURequestStepRoutePropTypes from './step/IOURequestStepRoutePropTypes'; import IOURequestStepScan from './step/IOURequestStepScan'; +import type {WithWritableReportOrNotFoundProps} from './step/withWritableReportOrNotFound'; -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: IOURequestStepRoutePropTypes.isRequired, - - /* Onyx Props */ +type IOURequestStartPageOnyxProps = { /** The report that holds the transaction */ - report: reportPropTypes, + report: OnyxEntry; /** The policy tied to the report */ - policy: PropTypes.shape({ - /** Type of the policy */ - type: PropTypes.string, - }), + policy: OnyxEntry; /** The tab to select by default (whatever the user visited last) */ - selectedTab: PropTypes.oneOf(_.values(CONST.TAB_REQUEST)), + selectedTab: OnyxEntry; /** The transaction being modified */ - transaction: transactionPropTypes, + transaction: OnyxEntry; }; -const defaultProps = { - report: {}, - policy: {}, - selectedTab: CONST.TAB_REQUEST.SCAN, - transaction: {}, -}; +type IOURequestStartPageProps = IOURequestStartPageOnyxProps & WithWritableReportOrNotFoundProps; function IOURequestStartPage({ report, @@ -69,7 +57,7 @@ function IOURequestStartPage({ }, selectedTab, transaction, -}) { +}: IOURequestStartPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); const navigation = useNavigation(); @@ -83,11 +71,11 @@ function IOURequestStartPage({ const transactionRequestType = useRef(TransactionUtils.getRequestType(transaction)); const previousIOURequestType = usePrevious(transactionRequestType.current); const {canUseP2PDistanceRequests} = usePermissions(iouType); - const isFromGlobalCreate = _.isEmpty(report.reportID); + const isFromGlobalCreate = isEmptyObject(report?.reportID); useFocusEffect( useCallback(() => { - const handler = (event) => { + const handler = (event: KeyboardEvent) => { if (event.code !== CONST.KEYBOARD_SHORTCUTS.TAB.shortcutKey) { return; } @@ -102,7 +90,7 @@ function IOURequestStartPage({ // Clear out the temporary money request if the reportID in the URL has changed from the transaction's reportID useEffect(() => { - if (transaction.reportID === reportID) { + if (transaction?.reportID === reportID) { return; } IOU.initMoneyRequest(reportID, policy, isFromGlobalCreate, transactionRequestType.current); @@ -110,31 +98,30 @@ function IOURequestStartPage({ const isExpenseChat = ReportUtils.isPolicyExpenseChat(report); const isExpenseReport = ReportUtils.isExpenseReport(report); - - const shouldDisplayDistanceRequest = canUseP2PDistanceRequests || isExpenseChat || isExpenseReport || isFromGlobalCreate; + const shouldDisplayDistanceRequest = !!canUseP2PDistanceRequests || isExpenseChat || isExpenseReport || isFromGlobalCreate; // Allow the user to create the request if we are creating the request in global menu or the report can create the request - const isAllowedToCreateRequest = _.isEmpty(report.reportID) || ReportUtils.canCreateRequest(report, policy, iouType); + const isAllowedToCreateRequest = isEmptyObject(report?.reportID) || ReportUtils.canCreateRequest(report, policy, iouType); const navigateBack = () => { Navigation.dismissModal(); }; const resetIOUTypeIfChanged = useCallback( - (newIouType) => { + (newIouType: IOURequestType) => { if (newIouType === previousIOURequestType) { return; } - if (iouType === CONST.IOU.TYPE.SPLIT && transaction.isFromGlobalCreate) { - IOU.updateMoneyRequestTypeParams(navigation.getState().routes, CONST.IOU.TYPE.REQUEST, newIouType); + if (iouType === CONST.IOU.TYPE.SPLIT && transaction?.isFromGlobalCreate) { + IOU.updateMoneyRequestTypeParams(navigation.getState()?.routes ?? [], CONST.IOU.TYPE.REQUEST, newIouType); } IOU.initMoneyRequest(reportID, policy, isFromGlobalCreate, newIouType); transactionRequestType.current = newIouType; }, - [policy, previousIOURequestType, reportID, isFromGlobalCreate, iouType, navigation, transaction.isFromGlobalCreate], + [policy, previousIOURequestType, reportID, isFromGlobalCreate, iouType, navigation, transaction?.isFromGlobalCreate], ); - if (!transaction.transactionID) { + if (!transaction?.transactionID) { // The draft transaction is initialized only after the component is mounted, // which will lead to briefly displaying the Not Found page without this loader. return ; @@ -162,7 +149,6 @@ function IOURequestStartPage({ {iouType !== CONST.IOU.TYPE.SEND ? ( @@ -182,20 +168,18 @@ function IOURequestStartPage({ } IOURequestStartPage.displayName = 'IOURequestStartPage'; -IOURequestStartPage.propTypes = propTypes; -IOURequestStartPage.defaultProps = defaultProps; -export default withOnyx({ +export default withOnyx({ report: { - key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`, + key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route?.params?.reportID}`, }, policy: { - key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${lodashGet(report, 'policyID')}`, + key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`, }, selectedTab: { key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.IOU_REQUEST_TYPE}`, }, transaction: { - key: ({route}) => `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${lodashGet(route, 'params.transactionID', '0')}`, + key: ({route}) => `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${route?.params.transactionID ?? 0}`, }, })(IOURequestStartPage); diff --git a/src/pages/iou/request/step/IOURequestStepAmount.js b/src/pages/iou/request/step/IOURequestStepAmount.tsx similarity index 71% rename from src/pages/iou/request/step/IOURequestStepAmount.js rename to src/pages/iou/request/step/IOURequestStepAmount.tsx index b392ee310205..1936a132c665 100644 --- a/src/pages/iou/request/step/IOURequestStepAmount.js +++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx @@ -1,52 +1,45 @@ import {useFocusEffect} from '@react-navigation/native'; -import lodashGet from 'lodash/get'; -import lodashIsEmpty from 'lodash/isEmpty'; import React, {useCallback, useEffect, useRef} from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import transactionPropTypes from '@components/transactionPropTypes'; +import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types'; import useLocalize from '@hooks/useLocalize'; import * as TransactionEdit from '@libs/actions/TransactionEdit'; -import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; import * as TransactionUtils from '@libs/TransactionUtils'; import {getRequestType} from '@libs/TransactionUtils'; import MoneyRequestAmountForm from '@pages/iou/steps/MoneyRequestAmountForm'; -import reportPropTypes from '@pages/reportPropTypes'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; +import type SCREENS from '@src/SCREENS'; +import type {Transaction} from '@src/types/onyx'; +import {isEmptyObject} from '@src/types/utils/EmptyObject'; 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 */ - /** The report that the transaction belongs to */ - report: reportPropTypes, - - /** The transaction object being modified in Onyx */ - transaction: transactionPropTypes, +type AmountParams = { + amount: string; +}; +type IOURequestStepAmountOnyxProps = { /** The draft transaction that holds data to be persisted on the current transaction */ - splitDraftTransaction: transactionPropTypes, + splitDraftTransaction: OnyxEntry; /** The draft transaction object being modified in Onyx */ - draftTransaction: transactionPropTypes, + draftTransaction: OnyxEntry; }; -const defaultProps = { - report: {}, - transaction: {}, - splitDraftTransaction: {}, - draftTransaction: {}, -}; +type IOURequestStepAmountProps = IOURequestStepAmountOnyxProps & + WithWritableReportOrNotFoundProps & { + /** The transaction object being modified in Onyx */ + transaction: OnyxEntry; + }; function IOURequestStepAmount({ report, @@ -56,22 +49,22 @@ function IOURequestStepAmount({ transaction, splitDraftTransaction, draftTransaction, -}) { +}: IOURequestStepAmountProps) { const {translate} = useLocalize(); - const textInput = useRef(null); - const focusTimeoutRef = useRef(null); + const textInput = useRef(null); + const focusTimeoutRef = useRef(null); const isSaveButtonPressed = useRef(false); - const originalCurrency = useRef(null); + const originalCurrency = useRef(null); const iouRequestType = getRequestType(transaction); const isEditing = action === CONST.IOU.ACTION.EDIT; const isSplitBill = iouType === CONST.IOU.TYPE.SPLIT; const isEditingSplitBill = isEditing && isSplitBill; - const {amount: transactionAmount} = ReportUtils.getTransactionDetails(isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction); - const {currency} = ReportUtils.getTransactionDetails(isEditing ? draftTransaction : transaction); + const {amount: transactionAmount} = ReportUtils.getTransactionDetails(isEditingSplitBill && !isEmptyObject(splitDraftTransaction) ? splitDraftTransaction : transaction) ?? {amount: 0}; + const {currency} = ReportUtils.getTransactionDetails(isEditing ? draftTransaction : transaction) ?? {currency: CONST.CURRENCY.USD}; useFocusEffect( useCallback(() => { - focusTimeoutRef.current = setTimeout(() => textInput.current && textInput.current.focus(), CONST.ANIMATED_TRANSITION); + focusTimeoutRef.current = setTimeout(() => textInput.current?.focus(), CONST.ANIMATED_TRANSITION); return () => { if (!focusTimeoutRef.current) { return; @@ -86,16 +79,16 @@ function IOURequestStepAmount({ // A temporary solution to not prevent users from editing the currency // We create a backup transaction and use it to save the currency and remove this transaction backup if we don't save the amount // It should be removed after this issue https://github.com/Expensify/App/issues/34607 is fixed - TransactionEdit.createBackupTransaction(isEditingSplitBill && !lodashIsEmpty(splitDraftTransaction) ? splitDraftTransaction : transaction); + TransactionEdit.createBackupTransaction(isEditingSplitBill && !isEmptyObject(splitDraftTransaction) ? splitDraftTransaction : transaction); return () => { if (isSaveButtonPressed.current) { return; } - TransactionEdit.removeBackupTransaction(transaction.transactionID || ''); + TransactionEdit.removeBackupTransaction(transaction?.transactionID ?? ''); }; } - if (transaction.originalCurrency) { + if (transaction?.originalCurrency) { originalCurrency.current = transaction.originalCurrency; } else { originalCurrency.current = currency; @@ -105,7 +98,7 @@ function IOURequestStepAmount({ if (isSaveButtonPressed.current) { return; } - IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, originalCurrency.current, true); + IOU.setMoneyRequestCurrency_temporaryForRefactor(transactionID, originalCurrency.current ?? '', true); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -118,10 +111,7 @@ function IOURequestStepAmount({ Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(action, iouType, transactionID, reportID, backTo ? 'confirm' : '', Navigation.getActiveRouteWithoutParams())); }; - /** - * @param {Number} amount - */ - const navigateToNextPage = ({amount}) => { + const navigateToNextPage = ({amount}: AmountParams) => { isSaveButtonPressed.current = true; const amountInSmallestCurrencyUnits = CurrencyUtils.convertToBackendAmount(Number.parseFloat(amount)); @@ -135,7 +125,7 @@ function IOURequestStepAmount({ // If a reportID exists in the report object, it's because the user started this flow from using the + button in the composer // inside a report. In this case, the participants can be automatically assigned from the report and the user can skip the participants step and go straight // to the confirm step. - if (report.reportID) { + if (report?.reportID) { IOU.setMoneyRequestParticipantsFromReport(transactionID, report); Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); return; @@ -146,7 +136,7 @@ function IOURequestStepAmount({ Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_PARTICIPANTS.getRoute(iouType, transactionID, reportID)); }; - const saveAmountAndCurrency = ({amount}) => { + const saveAmountAndCurrency = ({amount}: AmountParams) => { if (!isEditing) { navigateToNextPage({amount}); return; @@ -166,7 +156,7 @@ function IOURequestStepAmount({ return; } - IOU.updateMoneyRequestAmountAndCurrency(transactionID, reportID, currency, newAmount); + IOU.updateMoneyRequestAmountAndCurrency({transactionID, transactionThreadReportID: reportID, currency, amount: newAmount}); Navigation.dismissModal(); }; @@ -175,11 +165,11 @@ function IOURequestStepAmount({ headerTitle={translate('iou.amount')} onBackButtonPress={navigateBack} testID={IOURequestStepAmount.displayName} - shouldShowWrapper={Boolean(backTo || isEditing)} + shouldShowWrapper={!!backTo || isEditing} includeSafeAreaPaddingBottom > (textInput.current = e)} @@ -191,25 +181,23 @@ function IOURequestStepAmount({ ); } -IOURequestStepAmount.propTypes = propTypes; -IOURequestStepAmount.defaultProps = defaultProps; IOURequestStepAmount.displayName = 'IOURequestStepAmount'; -export default compose( - withWritableReportOrNotFound, - withFullTransactionOrNotFound, - withOnyx({ - splitDraftTransaction: { - key: ({route}) => { - const transactionID = lodashGet(route, 'params.transactionID', 0); - return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`; +export default withWritableReportOrNotFound( + withFullTransactionOrNotFound( + withOnyx({ + splitDraftTransaction: { + key: ({route}) => { + const transactionID = route.params.transactionID ?? 0; + return `${ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT}${transactionID}`; + }, }, - }, - draftTransaction: { - key: ({route}) => { - const transactionID = lodashGet(route, 'params.transactionID', 0); - return `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`; + draftTransaction: { + key: ({route}) => { + const transactionID = route.params.transactionID ?? 0; + return `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`; + }, }, - }, - }), -)(IOURequestStepAmount); + })(IOURequestStepAmount), + ), +); diff --git a/src/pages/iou/request/step/IOURequestStepDistance.js b/src/pages/iou/request/step/IOURequestStepDistance.tsx similarity index 63% rename from src/pages/iou/request/step/IOURequestStepDistance.js rename to src/pages/iou/request/step/IOURequestStepDistance.tsx index 398b2f83712b..fae07ad2249c 100644 --- a/src/pages/iou/request/step/IOURequestStepDistance.js +++ b/src/pages/iou/request/step/IOURequestStepDistance.tsx @@ -1,56 +1,49 @@ -import lodashGet from 'lodash/get'; +import {isEmpty, isEqual} from 'lodash'; import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; +// eslint-disable-next-line no-restricted-imports +import type {ScrollView as RNScrollView} from 'react-native'; +import type {RenderItemParams} from 'react-native-draggable-flatlist/lib/typescript/types'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import Button from '@components/Button'; import DistanceRequestFooter from '@components/DistanceRequest/DistanceRequestFooter'; import DistanceRequestRenderItem from '@components/DistanceRequest/DistanceRequestRenderItem'; import DotIndicatorMessage from '@components/DotIndicatorMessage'; import DraggableList from '@components/DraggableList'; -import transactionPropTypes from '@components/transactionPropTypes'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import usePrevious from '@hooks/usePrevious'; import useThemeStyles from '@hooks/useThemeStyles'; -import compose from '@libs/compose'; import * as ErrorUtils from '@libs/ErrorUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as TransactionUtils from '@libs/TransactionUtils'; -import reportPropTypes from '@pages/reportPropTypes'; -import variables from '@styles/variables'; import * as IOU from '@userActions/IOU'; import * as MapboxToken from '@userActions/MapboxToken'; -import * as Transaction from '@userActions/Transaction'; +import * as TransactionAction from '@userActions/Transaction'; import * as TransactionEdit from '@userActions/TransactionEdit'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import IOURequestStepRoutePropTypes from './IOURequestStepRoutePropTypes'; +import type SCREENS from '@src/SCREENS'; +import type * as OnyxTypes from '@src/types/onyx'; +import type {Errors} from '@src/types/onyx/OnyxCommon'; +import type {WaypointCollection} from '@src/types/onyx/Transaction'; 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 */ - /** The report that the transaction belongs to */ - report: reportPropTypes, - - /** The transaction object being modified in Onyx */ - transaction: transactionPropTypes, - +type IOURequestStepDistanceOnyxProps = { /** backup version of the original transaction */ - transactionBackup: transactionPropTypes, + transactionBackup: OnyxEntry; }; -const defaultProps = { - report: {}, - transaction: {}, - transactionBackup: {}, -}; +type IOURequestStepDistanceProps = IOURequestStepDistanceOnyxProps & + WithWritableReportOrNotFoundProps & { + /** The transaction object being modified in Onyx */ + transaction: OnyxEntry; + }; function IOURequestStepDistance({ report, @@ -59,31 +52,34 @@ function IOURequestStepDistance({ }, transaction, transactionBackup, -}) { +}: IOURequestStepDistanceProps) { const styles = useThemeStyles(); const {isOffline} = useNetwork(); const {translate} = useLocalize(); - const [optimisticWaypoints, setOptimisticWaypoints] = useState(null); - const waypoints = useMemo(() => optimisticWaypoints || lodashGet(transaction, 'comment.waypoints', {waypoint0: {}, waypoint1: {}}), [optimisticWaypoints, transaction]); - const waypointsList = _.keys(waypoints); + const [optimisticWaypoints, setOptimisticWaypoints] = useState(null); + const waypoints = useMemo(() => optimisticWaypoints ?? transaction?.comment?.waypoints ?? {waypoint0: {}, waypoint1: {}}, [optimisticWaypoints, transaction]); + const waypointsList = Object.keys(waypoints); const previousWaypoints = usePrevious(waypoints); - const numberOfWaypoints = _.size(waypoints); - const numberOfPreviousWaypoints = _.size(previousWaypoints); - const scrollViewRef = useRef(null); - const isLoadingRoute = lodashGet(transaction, 'comment.isLoading', false); - const isLoading = lodashGet(transaction, 'isLoading', false); - const hasRouteError = !!lodashGet(transaction, 'errorFields.route'); + const numberOfWaypoints = Object.keys(waypoints).length; + const numberOfPreviousWaypoints = Object.keys(previousWaypoints).length; + const scrollViewRef = useRef(null); + const isLoadingRoute = transaction?.comment?.isLoading ?? false; + const isLoading = transaction?.isLoading ?? false; + const hasRouteError = !!transaction?.errorFields?.route; const hasRoute = TransactionUtils.hasRoute(transaction); const validatedWaypoints = TransactionUtils.getValidWaypoints(waypoints); const previousValidatedWaypoints = usePrevious(validatedWaypoints); - const haveValidatedWaypointsChanged = !_.isEqual(previousValidatedWaypoints, validatedWaypoints); + const haveValidatedWaypointsChanged = !isEqual(previousValidatedWaypoints, validatedWaypoints); const isRouteAbsentWithoutErrors = !hasRoute && !hasRouteError; - const shouldFetchRoute = (isRouteAbsentWithoutErrors || haveValidatedWaypointsChanged) && !isLoadingRoute && _.size(validatedWaypoints) > 1; + const shouldFetchRoute = (isRouteAbsentWithoutErrors || haveValidatedWaypointsChanged) && !isLoadingRoute && Object.keys(validatedWaypoints).length > 1; const [shouldShowAtLeastTwoDifferentWaypointsError, setShouldShowAtLeastTwoDifferentWaypointsError] = useState(false); - const nonEmptyWaypointsCount = useMemo(() => _.filter(_.keys(waypoints), (key) => !_.isEmpty(waypoints[key])).length, [waypoints]); - const duplicateWaypointsError = useMemo(() => nonEmptyWaypointsCount >= 2 && _.size(validatedWaypoints) !== nonEmptyWaypointsCount, [nonEmptyWaypointsCount, validatedWaypoints]); - const atLeastTwoDifferentWaypointsError = useMemo(() => _.size(validatedWaypoints) < 2, [validatedWaypoints]); + const nonEmptyWaypointsCount = useMemo(() => Object.keys(waypoints).filter((key) => !isEmpty(waypoints[key])).length, [waypoints]); + const duplicateWaypointsError = useMemo( + () => nonEmptyWaypointsCount >= 2 && Object.keys(validatedWaypoints).length !== nonEmptyWaypointsCount, + [nonEmptyWaypointsCount, validatedWaypoints], + ); + const atLeastTwoDifferentWaypointsError = useMemo(() => Object.keys(validatedWaypoints).length < 2, [validatedWaypoints]); const isEditing = action === CONST.IOU.ACTION.EDIT; const transactionWasSaved = useRef(false); const isCreatingNewRequest = !(backTo || isEditing); @@ -97,14 +93,14 @@ function IOURequestStepDistance({ if (isOffline || !shouldFetchRoute) { return; } - Transaction.getRoute(transactionID, validatedWaypoints, action === CONST.IOU.ACTION.CREATE); + TransactionAction.getRoute(transactionID, validatedWaypoints, action === CONST.IOU.ACTION.CREATE); }, [shouldFetchRoute, transactionID, validatedWaypoints, isOffline, action]); useEffect(() => { if (numberOfWaypoints <= numberOfPreviousWaypoints) { return; } - scrollViewRef.current.scrollToEnd({animated: true}); + scrollViewRef.current?.scrollToEnd({animated: true}); }, [numberOfPreviousWaypoints, numberOfWaypoints]); useEffect(() => { @@ -132,7 +128,7 @@ function IOURequestStepDistance({ if (transactionWasSaved.current) { return; } - TransactionEdit.restoreOriginalTransactionFromBackup(lodashGet(transaction, 'transactionID', ''), action === CONST.IOU.ACTION.CREATE); + TransactionEdit.restoreOriginalTransactionFromBackup(transaction?.transactionID ?? '', action === CONST.IOU.ACTION.CREATE); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -143,11 +139,16 @@ function IOURequestStepDistance({ /** * Takes the user to the page for editing a specific waypoint - * @param {Number} index of the waypoint to edit + * @param index of the waypoint to edit */ - const navigateToWaypointEditPage = (index) => { - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_WAYPOINT.getRoute(action, CONST.IOU.TYPE.REQUEST, transactionID, report.reportID, index, Navigation.getActiveRouteWithoutParams())); - }; + const navigateToWaypointEditPage = useCallback( + (index: number) => { + Navigation.navigate( + ROUTES.MONEY_REQUEST_STEP_WAYPOINT.getRoute(action, CONST.IOU.TYPE.REQUEST, transactionID, report?.reportID, index.toString(), Navigation.getActiveRouteWithoutParams()), + ); + }, + [action, transactionID, report?.reportID], + ); const navigateToNextStep = useCallback(() => { if (backTo) { @@ -158,7 +159,7 @@ function IOURequestStepDistance({ // If a reportID exists in the report object, it's because the user started this flow from using the + button in the composer // inside a report. In this case, the participants can be automatically assigned from the report and the user can skip the participants step and go straight // to the confirm step. - if (report.reportID) { + if (report?.reportID) { IOU.setMoneyRequestParticipantsFromReport(transactionID, report); Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID)); return; @@ -175,36 +176,40 @@ function IOURequestStepDistance({ return ErrorUtils.getLatestErrorField(transaction, 'route'); } if (duplicateWaypointsError) { - return {0: translate('iou.error.duplicateWaypointsErrorMessage')}; + return {duplicateWaypointsError: translate('iou.error.duplicateWaypointsErrorMessage')} as Errors; } if (atLeastTwoDifferentWaypointsError) { - return {0: 'iou.error.atLeastTwoDifferentWaypoints'}; + return {atLeastTwoDifferentWaypointsError: 'iou.error.atLeastTwoDifferentWaypoints'} as Errors; } + return {}; + }; + + type DataParams = { + data: string[]; }; const updateWaypoints = useCallback( - ({data}) => { - if (_.isEqual(waypointsList, data)) { + ({data}: DataParams) => { + if (isEqual(waypointsList, data)) { return; } - const newWaypoints = {}; + const newWaypoints: WaypointCollection = {}; let emptyWaypointIndex = -1; - _.each(data, (waypoint, index) => { - newWaypoints[`waypoint${index}`] = lodashGet(waypoints, waypoint, {}); + data.forEach((waypoint, index) => { + newWaypoints[`waypoint${index}`] = waypoints[waypoint] ?? {}; // Find waypoint that BECOMES empty after dragging - if (_.isEmpty(newWaypoints[`waypoint${index}`]) && !_.isEmpty(lodashGet(waypoints, `waypoint${index}`, {}))) { + if (isEmpty(newWaypoints[`waypoint${index}`]) && !isEmpty(waypoints[`waypoint${index}`] ?? {})) { emptyWaypointIndex = index; } }); setOptimisticWaypoints(newWaypoints); - // eslint-disable-next-line rulesdir/no-thenable-actions-in-views Promise.all([ - Transaction.removeWaypoint(transaction, emptyWaypointIndex.toString(), action === CONST.IOU.ACTION.CREATE), - Transaction.updateWaypoints(transactionID, newWaypoints, action === CONST.IOU.ACTION.CREATE), + TransactionAction.removeWaypoint(transaction, emptyWaypointIndex.toString(), action === CONST.IOU.ACTION.CREATE), + TransactionAction.updateWaypoints(transactionID, newWaypoints, action === CONST.IOU.ACTION.CREATE), ]).then(() => { - setOptimisticWaypoints(undefined); + setOptimisticWaypoints(null); }); }, [transactionID, transaction, waypoints, waypointsList, action], @@ -222,14 +227,14 @@ function IOURequestStepDistance({ if (isEditing) { // If nothing was changed, simply go to transaction thread // We compare only addresses because numbers are rounded while backup - const oldWaypoints = lodashGet(transactionBackup, 'comment.waypoints', {}); - const oldAddresses = _.mapObject(oldWaypoints, (waypoint) => _.pick(waypoint, 'address')); - const addresses = _.mapObject(waypoints, (waypoint) => _.pick(waypoint, 'address')); - if (_.isEqual(oldAddresses, addresses)) { + const oldWaypoints = transactionBackup?.comment.waypoints ?? {}; + const oldAddresses = Object.fromEntries(Object.entries(oldWaypoints).map(([key, waypoint]) => [key, 'address' in waypoint ? waypoint.address : {}])); + const addresses = Object.fromEntries(Object.entries(waypoints).map(([key, waypoint]) => [key, 'address' in waypoint ? waypoint.address : {}])); + if (isEqual(oldAddresses, addresses)) { Navigation.dismissModal(); return; } - IOU.updateMoneyRequestDistance(transaction.transactionID, report.reportID, waypoints); + IOU.updateMoneyRequestDistance({transactionID: transaction?.transactionID ?? '', transactionThreadReportID: report?.reportID ?? '', waypoints}); Navigation.dismissModal(); return; } @@ -246,10 +251,25 @@ function IOURequestStepDistance({ navigateToNextStep, transactionBackup, waypoints, - transaction.transactionID, - report.reportID, + transaction?.transactionID, + report?.reportID, ]); + const renderItem = useCallback( + ({item, drag, isActive, getIndex}: RenderItemParams) => ( + + ), + [isLoadingRoute, navigateToWaypointEditPage, waypoints], + ); + return ( item} shouldUsePortal onDragEnd={updateWaypoints} - scrollEventThrottle={variables.distanceScrollEventThrottle} ref={scrollViewRef} - renderItem={({item, drag, isActive, getIndex}) => ( - - )} + renderItem={renderItem} ListFooterComponent={ @@ -313,18 +321,16 @@ function IOURequestStepDistance({ } IOURequestStepDistance.displayName = 'IOURequestStepDistance'; -IOURequestStepDistance.propTypes = propTypes; -IOURequestStepDistance.defaultProps = defaultProps; -export default compose( - withWritableReportOrNotFound, - withFullTransactionOrNotFound, - withOnyx({ - transactionBackup: { - key: ({route}) => { - const transactionID = lodashGet(route, 'params.transactionID', 0); - return `${ONYXKEYS.COLLECTION.TRANSACTION_BACKUP}${transactionID}`; +export default withWritableReportOrNotFound( + withFullTransactionOrNotFound( + withOnyx({ + transactionBackup: { + key: ({route}) => { + const transactionID = route.params.transactionID ?? 0; + return `${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`; + }, }, - }, - }), -)(IOURequestStepDistance); + })(IOURequestStepDistance), + ), +); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index e084a3db7422..c1b360f89e48 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -3,7 +3,6 @@ import React, {useCallback, useRef, useState} from 'react'; import {ActivityIndicator, Alert, AppState, InteractionManager, View} from 'react-native'; import {Gesture, GestureDetector} from 'react-native-gesture-handler'; import {withOnyx} from 'react-native-onyx'; -import type {OnyxEntry} from 'react-native-onyx'; import {RESULTS} from 'react-native-permissions'; import Animated, {runOnJS, useAnimatedStyle, useSharedValue, withDelay, withSequence, withSpring, withTiming} from 'react-native-reanimated'; import type {Camera, PhotoFile, Point} from 'react-native-vision-camera'; @@ -26,23 +25,14 @@ import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; import StepScreenWrapper from '@pages/iou/request/step/StepScreenWrapper'; import withFullTransactionOrNotFound from '@pages/iou/request/step/withFullTransactionOrNotFound'; -import type {WithWritableReportOrNotFoundProps} from '@pages/iou/request/step/withWritableReportOrNotFound'; import withWritableReportOrNotFound from '@pages/iou/request/step/withWritableReportOrNotFound'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; 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 CameraPermission from './CameraPermission'; import NavigationAwareCamera from './NavigationAwareCamera'; -import type IOURequestStepOnyxProps from './types'; - -type IOURequestStepScanProps = IOURequestStepOnyxProps & - WithWritableReportOrNotFoundProps & { - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - transaction: OnyxEntry; - }; +import type {IOURequestStepOnyxProps, IOURequestStepScanProps} from './types'; function IOURequestStepScan({ report, diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index b9c4f866d493..995e52c67fc0 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -1,6 +1,5 @@ import React, {useCallback, useContext, useEffect, useReducer, useRef, useState} from 'react'; import {ActivityIndicator, PanResponder, PixelRatio, View} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; import type Webcam from 'react-webcam'; import Hand from '@assets/images/hand.svg'; import ReceiptUpload from '@assets/images/receipt-upload.svg'; @@ -26,23 +25,14 @@ import Navigation from '@libs/Navigation/Navigation'; import ReceiptDropUI from '@pages/iou/ReceiptDropUI'; import StepScreenDragAndDropWrapper from '@pages/iou/request/step/StepScreenDragAndDropWrapper'; import withFullTransactionOrNotFound from '@pages/iou/request/step/withFullTransactionOrNotFound'; -import type {WithWritableReportOrNotFoundProps} from '@pages/iou/request/step/withWritableReportOrNotFound'; import withWritableReportOrNotFound from '@pages/iou/request/step/withWritableReportOrNotFound'; import * as IOU from '@userActions/IOU'; import CONST from '@src/CONST'; import type {TranslationPaths} from '@src/languages/types'; import ROUTES from '@src/ROUTES'; -import type SCREENS from '@src/SCREENS'; -import type * as OnyxTypes from '@src/types/onyx'; import {isEmptyObject} from '@src/types/utils/EmptyObject'; import NavigationAwareCamera from './NavigationAwareCamera'; -import type IOURequestStepOnyxProps from './types'; - -type IOURequestStepScanProps = IOURequestStepOnyxProps & - WithWritableReportOrNotFoundProps & { - /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ - transaction: OnyxEntry; - }; +import type {IOURequestStepScanProps} from './types'; function IOURequestStepScan({ report, @@ -50,7 +40,7 @@ function IOURequestStepScan({ params: {action, iouType, reportID, transactionID, backTo}, }, transaction, -}: IOURequestStepScanProps) { +}: Omit) { const theme = useTheme(); const styles = useThemeStyles(); diff --git a/src/pages/iou/request/step/IOURequestStepScan/types.ts b/src/pages/iou/request/step/IOURequestStepScan/types.ts index adf3e5c81748..60af94aca12e 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/types.ts +++ b/src/pages/iou/request/step/IOURequestStepScan/types.ts @@ -1,8 +1,16 @@ import type {OnyxEntry} from 'react-native-onyx'; +import type {WithWritableReportOrNotFoundProps} from '@pages/iou/request/step/withWritableReportOrNotFound'; +import type SCREENS from '@src/SCREENS'; import type * as OnyxTypes from '@src/types/onyx'; type IOURequestStepOnyxProps = { user: OnyxEntry; }; -export default IOURequestStepOnyxProps; +type IOURequestStepScanProps = IOURequestStepOnyxProps & + WithWritableReportOrNotFoundProps & { + /** Holds data related to Money Request view state, rather than the underlying Money Request data. */ + transaction: OnyxEntry; + }; + +export type {IOURequestStepOnyxProps, IOURequestStepScanProps}; diff --git a/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx b/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx index e3aa1ed2431d..e1a01c9dde69 100644 --- a/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx +++ b/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx @@ -18,6 +18,9 @@ type WithFullTransactionOrNotFoundOnyxProps = { }; type MoneyRequestRouteName = + | typeof SCREENS.MONEY_REQUEST.CREATE + | typeof SCREENS.MONEY_REQUEST.STEP_DISTANCE + | typeof SCREENS.MONEY_REQUEST.STEP_AMOUNT | typeof SCREENS.MONEY_REQUEST.STEP_WAYPOINT | typeof SCREENS.MONEY_REQUEST.STEP_DESCRIPTION | typeof SCREENS.MONEY_REQUEST.STEP_TAX_AMOUNT diff --git a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx index 4cad980eb680..af182b51d9d6 100644 --- a/src/pages/iou/request/step/withWritableReportOrNotFound.tsx +++ b/src/pages/iou/request/step/withWritableReportOrNotFound.tsx @@ -23,6 +23,10 @@ type MoneyRequestRouteName = | typeof SCREENS.MONEY_REQUEST.STEP_CATEGORY | typeof SCREENS.MONEY_REQUEST.STEP_CONFIRMATION | typeof SCREENS.MONEY_REQUEST.STEP_TAX_RATE + | typeof SCREENS.MONEY_REQUEST.STEP_AMOUNT + | typeof SCREENS.MONEY_REQUEST.STEP_DISTANCE + | typeof SCREENS.MONEY_REQUEST.CREATE + | typeof SCREENS.MONEY_REQUEST.START | typeof SCREENS.MONEY_REQUEST.STEP_TAG | typeof SCREENS.MONEY_REQUEST.STEP_PARTICIPANTS | typeof SCREENS.MONEY_REQUEST.STEP_MERCHANT