diff --git a/Mobile-Expensify b/Mobile-Expensify
index 2df28fc86ca4..50e07511c4e7 160000
--- a/Mobile-Expensify
+++ b/Mobile-Expensify
@@ -1 +1 @@
-Subproject commit 2df28fc86ca48169c9f91e09287bd3bb3364429c
+Subproject commit 50e07511c4e77644770026f38c2d70b2c1333b39
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 3a52425c6686..8a0ab638be0d 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -114,8 +114,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1009027304
- versionName "9.2.73-4"
+ versionCode 1009027305
+ versionName "9.2.73-5"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index b144b6d4433c..79015247ca43 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -44,7 +44,7 @@
CFBundleVersion
- 9.2.73.4
+ 9.2.73.5
FullStory
OrgId
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index eaabcc249233..0bea1fbed6b8 100644
--- a/ios/NotificationServiceExtension/Info.plist
+++ b/ios/NotificationServiceExtension/Info.plist
@@ -13,7 +13,7 @@
CFBundleShortVersionString
9.2.73
CFBundleVersion
- 9.2.73.4
+ 9.2.73.5
NSExtension
NSExtensionPointIdentifier
diff --git a/ios/ShareViewController/Info.plist b/ios/ShareViewController/Info.plist
index 7e2ecffeac5a..11c98015cf5a 100644
--- a/ios/ShareViewController/Info.plist
+++ b/ios/ShareViewController/Info.plist
@@ -13,7 +13,7 @@
CFBundleShortVersionString
9.2.73
CFBundleVersion
- 9.2.73.4
+ 9.2.73.5
NSExtension
NSExtensionAttributes
diff --git a/package-lock.json b/package-lock.json
index 132cd0e021a4..ad73e4c02bbd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "9.2.73-4",
+ "version": "9.2.73-5",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "9.2.73-4",
+ "version": "9.2.73-5",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index 9809bbdec059..bccde6c0d5d3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "9.2.73-4",
+ "version": "9.2.73-5",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index ce439c4ad1ec..912a981584e4 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -1079,6 +1079,12 @@ const ROUTES = {
// eslint-disable-next-line no-restricted-syntax -- Legacy route generation
getUrlWithBackToParam(`settings/${policyID}/category/${encodeURIComponent(categoryName)}/gl-code` as const, backTo),
},
+ MONEY_REQUEST_STEP_CURRENCY: {
+ route: ':action/:iouType/currency/:transactionID/:reportID/:pageIndex?',
+ getRoute: (action: IOUAction, iouType: IOUType, transactionID: string, reportID: string, pageIndex = '', currency = '', backTo = '') =>
+ // eslint-disable-next-line no-restricted-syntax -- Legacy route generation
+ getUrlWithBackToParam(`${action as string}/${iouType as string}/currency/${transactionID}/${reportID}/${pageIndex}?currency=${currency}`, backTo),
+ },
MONEY_REQUEST_STEP_DATE: {
route: ':action/:iouType/date/:transactionID/:reportID/:reportActionID?',
getRoute: (action: IOUAction, iouType: IOUType, transactionID: string | undefined, reportID: string | undefined, backTo = '', reportActionID?: string) => {
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 6c282f03554d..ce5eb617480e 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -289,6 +289,7 @@ const SCREENS = {
STEP_UPGRADE: 'Money_Request_Step_Upgrade',
STEP_AMOUNT: 'Money_Request_Step_Amount',
STEP_CATEGORY: 'Money_Request_Step_Category',
+ STEP_CURRENCY: 'Money_Request_Step_Currency',
STEP_DATE: 'Money_Request_Step_Date',
STEP_DESCRIPTION: 'Money_Request_Step_Description',
STEP_DISTANCE: 'Money_Request_Step_Distance',
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
index 26144c4bfd26..90df0bc2f3a6 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators/index.tsx
@@ -208,6 +208,7 @@ const MoneyRequestModalStackNavigator = createModalStackNavigator require('../../../../pages/iou/request/step/IOURequestStepTaxAmountPage').default,
[SCREENS.MONEY_REQUEST.STEP_TAX_RATE]: () => require('../../../../pages/iou/request/step/IOURequestStepTaxRatePage').default,
[SCREENS.MONEY_REQUEST.STEP_CATEGORY]: () => require('../../../../pages/iou/request/step/IOURequestStepCategory').default,
+ [SCREENS.MONEY_REQUEST.STEP_CURRENCY]: () => require('../../../../pages/iou/request/step/IOURequestStepCurrency').default,
[SCREENS.MONEY_REQUEST.STEP_DATE]: () => require('../../../../pages/iou/request/step/IOURequestStepDate').default,
[SCREENS.MONEY_REQUEST.STEP_DESCRIPTION]: () => require('../../../../pages/iou/request/step/IOURequestStepDescription').default,
[SCREENS.MONEY_REQUEST.STEP_DISTANCE]: () => require('../../../../pages/iou/request/step/IOURequestStepDistance').default,
diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts
index e823b8515d1c..a1678afff018 100644
--- a/src/libs/Navigation/linkingConfig/config.ts
+++ b/src/libs/Navigation/linkingConfig/config.ts
@@ -1416,6 +1416,7 @@ const config: LinkingOptions['config'] = {
[SCREENS.MONEY_REQUEST.STEP_CATEGORY]: ROUTES.MONEY_REQUEST_STEP_CATEGORY.route,
[SCREENS.MONEY_REQUEST.STEP_CONFIRMATION]: ROUTES.MONEY_REQUEST_STEP_CONFIRMATION.route,
[SCREENS.MONEY_REQUEST.STEP_CONFIRMATION_VERIFY_ACCOUNT]: ROUTES.MONEY_REQUEST_STEP_CONFIRMATION_VERIFY_ACCOUNT.route,
+ [SCREENS.MONEY_REQUEST.STEP_CURRENCY]: ROUTES.MONEY_REQUEST_STEP_CURRENCY.route,
[SCREENS.MONEY_REQUEST.STEP_DATE]: ROUTES.MONEY_REQUEST_STEP_DATE.route,
[SCREENS.MONEY_REQUEST.STEP_DESCRIPTION]: ROUTES.MONEY_REQUEST_STEP_DESCRIPTION.route,
[SCREENS.MONEY_REQUEST.STEP_DISTANCE]: ROUTES.MONEY_REQUEST_STEP_DISTANCE.route,
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index 40248daab723..9b7df56a59db 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -1571,6 +1571,7 @@ type MoneyRequestNavigatorParamList = {
reportID: string;
// eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md
backTo: Routes;
+ currency?: string;
};
[SCREENS.MONEY_REQUEST.STEP_TAG]: {
action: IOUAction;
@@ -1652,6 +1653,7 @@ type MoneyRequestNavigatorParamList = {
// eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md
backTo: never;
action: never;
+ currency: never;
pageIndex?: string;
backToReport?: string;
reportActionID?: string;
@@ -1670,6 +1672,7 @@ type MoneyRequestNavigatorParamList = {
backTo: Routes;
action: IOUAction;
pageIndex?: string;
+ currency?: string;
backToReport?: string;
reportActionID?: string;
};
@@ -1714,6 +1717,16 @@ type MoneyRequestNavigatorParamList = {
// eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md
backTo: Routes;
};
+ [SCREENS.MONEY_REQUEST.STEP_CURRENCY]: {
+ action: IOUAction;
+ iouType: IOUType;
+ transactionID: string;
+ reportID: string;
+ pageIndex?: string;
+ // eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md
+ backTo?: Routes;
+ currency?: string;
+ };
[SCREENS.MONEY_REQUEST.HOLD]: {
/** ID of the transaction the page was opened for */
transactionID: string;
@@ -1825,6 +1838,7 @@ type MoneyRequestNavigatorParamList = {
// eslint-disable-next-line no-restricted-syntax -- `backTo` usages in this file are legacy. Do not add new `backTo` params to screens. See contributingGuides/NAVIGATION.md
backTo: never;
action: never;
+ currency: never;
pageIndex?: string;
backToReport?: string;
reportActionID?: string;
diff --git a/src/pages/iou/request/DistanceRequestStartPage.tsx b/src/pages/iou/request/DistanceRequestStartPage.tsx
index 3fd94bb41edd..8d8fbf39513b 100644
--- a/src/pages/iou/request/DistanceRequestStartPage.tsx
+++ b/src/pages/iou/request/DistanceRequestStartPage.tsx
@@ -92,6 +92,26 @@ function DistanceRequestStartPage({
Navigation.closeRHPFlow();
};
+ // This useEffect is used to initialize the money request, so that currency will be reset to default currency on page reload.
+ useEffect(() => {
+ if (transaction?.amount !== 0) {
+ return;
+ }
+ initMoneyRequest({
+ reportID,
+ policy,
+ isFromGlobalCreate,
+ currentIouRequestType: transaction?.iouRequestType,
+ newIouRequestType: transaction?.iouRequestType,
+ report,
+ parentReport,
+ currentDate,
+ lastSelectedDistanceRates,
+ currentUserPersonalDetails,
+ });
+ // eslint-disable-next-line
+ }, []);
+
const resetIOUTypeIfChanged = useCallback(
(newIOUType: IOURequestType) => {
Keyboard.dismiss();
diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx
index 0dc475b48dc8..2f470eaaf943 100644
--- a/src/pages/iou/request/IOURequestStartPage.tsx
+++ b/src/pages/iou/request/IOURequestStartPage.tsx
@@ -137,6 +137,26 @@ function IOURequestStartPage({
Navigation.closeRHPFlow();
};
+ // This useEffect is used to initialize the money request, so that currency will be reset to default currency on page reload.
+ useEffect(() => {
+ if (transaction?.amount !== 0) {
+ return;
+ }
+ initMoneyRequest({
+ reportID,
+ policy,
+ isFromGlobalCreate,
+ currentIouRequestType: transaction?.iouRequestType,
+ newIouRequestType: transaction?.iouRequestType,
+ report,
+ parentReport,
+ currentDate,
+ lastSelectedDistanceRates,
+ currentUserPersonalDetails,
+ });
+ // eslint-disable-next-line
+ }, []);
+
const resetIOUTypeIfChanged = useCallback(
(newIOUType: IOURequestType) => {
Keyboard.dismiss();
diff --git a/src/pages/iou/request/step/IOURequestStepAmount.tsx b/src/pages/iou/request/step/IOURequestStepAmount.tsx
index 6a81d8599dfb..bbe392173a88 100644
--- a/src/pages/iou/request/step/IOURequestStepAmount.tsx
+++ b/src/pages/iou/request/step/IOURequestStepAmount.tsx
@@ -1,9 +1,10 @@
import {useFocusEffect} from '@react-navigation/native';
import reportsSelector from '@selectors/Attributes';
-import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import type {BaseTextInputRef} from '@components/TextInput/BaseTextInput/types';
-import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
+import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
+import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails';
import useDefaultExpensePolicy from '@hooks/useDefaultExpensePolicy';
import useDuplicateTransactionsAndViolations from '@hooks/useDuplicateTransactionsAndViolations';
import useLocalize from '@hooks/useLocalize';
@@ -13,7 +14,8 @@ import usePersonalPolicy from '@hooks/usePersonalPolicy';
import useReportIsArchived from '@hooks/useReportIsArchived';
import useShowNotFoundPageInIOUStep from '@hooks/useShowNotFoundPageInIOUStep';
import {setTransactionReport} from '@libs/actions/Transaction';
-import {convertToBackendAmount} from '@libs/CurrencyUtils';
+import {createDraftTransaction, removeDraftTransaction} from '@libs/actions/TransactionEdit';
+import {convertToBackendAmount, isValidCurrencyCode} from '@libs/CurrencyUtils';
import {navigateToParticipantPage} from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import {getParticipantsOption, getReportOption} from '@libs/OptionsListUtils';
@@ -43,7 +45,6 @@ import type {SelectedTabRequest} from '@src/types/onyx';
import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
import type Transaction from '@src/types/onyx/Transaction';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
-import IOURequestStepCurrencyModal from './IOURequestStepCurrencyModal';
import StepScreenWrapper from './StepScreenWrapper';
import withFullTransactionOrNotFound from './withFullTransactionOrNotFound';
import type {WithWritableReportOrNotFoundProps} from './withWritableReportOrNotFound';
@@ -54,26 +55,26 @@ type AmountParams = {
paymentMethod?: PaymentMethodType;
};
-type IOURequestStepAmountProps = WithWritableReportOrNotFoundProps & {
- /** The transaction object being modified in Onyx */
- transaction: OnyxEntry;
+type IOURequestStepAmountProps = WithCurrentUserPersonalDetailsProps &
+ WithWritableReportOrNotFoundProps & {
+ /** The transaction object being modified in Onyx */
+ transaction: OnyxEntry;
- /** Whether the user input should be kept or not */
- shouldKeepUserInput?: boolean;
-};
+ /** Whether the user input should be kept or not */
+ shouldKeepUserInput?: boolean;
+ };
function IOURequestStepAmount({
report,
route: {
- params: {iouType, reportID, transactionID = '-1', backTo, action, backToReport, reportActionID},
+ params: {iouType, reportID, transactionID = '-1', backTo, pageIndex, action, currency: selectedCurrency = '', backToReport, reportActionID},
},
transaction,
+ currentUserPersonalDetails,
shouldKeepUserInput = false,
}: IOURequestStepAmountProps) {
const {translate} = useLocalize();
const {isBetaEnabled} = usePermissions();
- const currentUserPersonalDetails = useCurrentUserPersonalDetails();
- const [isCurrencyPickerVisible, setIsCurrencyPickerVisible] = useState(false);
const textInput = useRef(null);
const focusTimeoutRef = useRef(null);
const isSaveButtonPressed = useRef(false);
@@ -102,7 +103,7 @@ function IOURequestStepAmount({
const disableOppositeConversion = isCreateAction || (isSubmitType && isSubmitAction);
const {amount: transactionAmount} = getTransactionDetails(currentTransaction, undefined, undefined, allowNegative, disableOppositeConversion) ?? {amount: 0};
const {currency: originalCurrency} = getTransactionDetails(isEditing && !isEmptyObject(draftTransaction) ? draftTransaction : transaction) ?? {currency: CONST.CURRENCY.USD};
- const [selectedCurrency, setSelectedCurrency] = useState(originalCurrency);
+ const currency = isValidCurrencyCode(selectedCurrency) ? selectedCurrency : originalCurrency;
// eslint-disable-next-line rulesdir/no-negated-variables
const shouldShowNotFoundPage = useShowNotFoundPageInIOUStep(action, iouType, reportActionID, report, transaction);
const shouldGenerateTransactionThreadReport = !isBetaEnabled(CONST.BETAS.NO_OPTIMISTIC_TRANSACTION_THREADS);
@@ -134,15 +135,32 @@ function IOURequestStepAmount({
}, []),
);
- // This useEffect is to update the selected currency when the we came back from confirmation page
useEffect(() => {
- setSelectedCurrency(originalCurrency);
- }, [originalCurrency]);
+ if (!isEditing) {
+ return;
+ }
+ // 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
+ createDraftTransaction(isEditingSplitBill && !isEmptyObject(splitDraftTransaction) ? splitDraftTransaction : transaction);
+
+ return () => {
+ if (isSaveButtonPressed.current) {
+ return;
+ }
+ removeDraftTransaction(transaction?.transactionID);
+ };
+ // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
+ }, []);
const navigateBack = () => {
Navigation.goBack(backTo);
};
+ const navigateToCurrencySelectionPage = () => {
+ Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(action, iouType, transactionID, reportID, pageIndex, currency, Navigation.getActiveRoute()));
+ };
+
const navigateToConfirmationPage = () => {
switch (iouType) {
case CONST.IOU.TYPE.REQUEST:
@@ -161,7 +179,7 @@ function IOURequestStepAmount({
const amountInSmallestCurrencyUnits = convertToBackendAmount(Number.parseFloat(amount));
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
- setMoneyRequestAmount(transactionID, amountInSmallestCurrencyUnits, selectedCurrency || CONST.CURRENCY.USD, shouldKeepUserInput);
+ setMoneyRequestAmount(transactionID, amountInSmallestCurrencyUnits, currency || CONST.CURRENCY.USD, shouldKeepUserInput);
if (backTo) {
Navigation.goBack(backTo);
@@ -185,10 +203,10 @@ function IOURequestStepAmount({
if (shouldSkipConfirmation) {
if (iouType === CONST.IOU.TYPE.PAY || iouType === CONST.IOU.TYPE.SEND) {
if (paymentMethod && paymentMethod === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) {
- sendMoneyWithWallet(report, backendAmount, selectedCurrency, '', currentUserAccountIDParam, participants.at(0) ?? {});
+ sendMoneyWithWallet(report, backendAmount, currency, '', currentUserAccountIDParam, participants.at(0) ?? {});
return;
}
- sendMoneyElsewhere(report, backendAmount, selectedCurrency, '', currentUserAccountIDParam, participants.at(0) ?? {});
+ sendMoneyElsewhere(report, backendAmount, currency, '', currentUserAccountIDParam, participants.at(0) ?? {});
return;
}
if (iouType === CONST.IOU.TYPE.SUBMIT || iouType === CONST.IOU.TYPE.REQUEST) {
@@ -201,7 +219,7 @@ function IOURequestStepAmount({
},
transactionParams: {
amount: backendAmount,
- currency: selectedCurrency,
+ currency,
created: transaction?.created ?? '',
merchant: CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT,
attendees: transaction?.comment?.attendees,
@@ -226,7 +244,7 @@ function IOURequestStepAmount({
},
transactionParams: {
amount: backendAmount,
- currency: selectedCurrency ?? CONST.CURRENCY.USD,
+ currency: currency ?? 'USD',
created: transaction?.created,
merchant: CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT,
},
@@ -237,7 +255,7 @@ function IOURequestStepAmount({
}
if (isSplitBill && !report.isOwnPolicyExpenseChat && report.participants) {
const participantAccountIDs = Object.keys(report.participants).map((accountID) => Number(accountID));
- setSplitShares(transaction, amountInSmallestCurrencyUnits, selectedCurrency || CONST.CURRENCY.USD, participantAccountIDs);
+ setSplitShares(transaction, amountInSmallestCurrencyUnits, currency || CONST.CURRENCY.USD, participantAccountIDs);
}
setMoneyRequestParticipantsFromReport(transactionID, report, currentUserPersonalDetails.accountID).then(() => {
navigateToConfirmationPage();
@@ -300,7 +318,7 @@ function IOURequestStepAmount({
// Edits to the amount from the splits page should reset the split shares.
if (transaction?.splitShares) {
- resetSplitShares(transaction, newAmount, selectedCurrency);
+ resetSplitShares(transaction, newAmount, currency);
}
if (!isEditing) {
@@ -310,20 +328,20 @@ function IOURequestStepAmount({
// If the value hasn't changed, don't request to save changes on the server and just close the modal
const transactionCurrency = getCurrency(currentTransaction);
- if (newAmount === getAmount(currentTransaction, false, false, allowNegative, disableOppositeConversion) && selectedCurrency === transactionCurrency) {
+ if (newAmount === getAmount(currentTransaction, false, false, allowNegative, disableOppositeConversion) && currency === transactionCurrency) {
navigateBack();
return;
}
// If currency has changed, then we get the default tax rate based on currency, otherwise we use the current tax rate selected in transaction, if we have it.
const transactionTaxCode = getTransactionDetails(currentTransaction)?.taxCode;
- const defaultTaxCode = getDefaultTaxCode(policy, currentTransaction, selectedCurrency) ?? '';
- const taxCode = (selectedCurrency !== transactionCurrency ? defaultTaxCode : transactionTaxCode) ?? defaultTaxCode;
+ const defaultTaxCode = getDefaultTaxCode(policy, currentTransaction, currency) ?? '';
+ const taxCode = (currency !== transactionCurrency ? defaultTaxCode : transactionTaxCode) ?? defaultTaxCode;
const taxPercentage = getTaxValue(policy, currentTransaction, taxCode) ?? '';
- const taxAmount = convertToBackendAmount(calculateTaxAmount(taxPercentage, newAmount, selectedCurrency ?? CONST.CURRENCY.USD));
+ const taxAmount = convertToBackendAmount(calculateTaxAmount(taxPercentage, newAmount, currency ?? CONST.CURRENCY.USD));
if (isSplitBill) {
- setDraftSplitTransaction(transactionID, splitDraftTransaction, {amount: newAmount, currency: selectedCurrency, taxCode, taxAmount});
+ setDraftSplitTransaction(transactionID, splitDraftTransaction, {amount: newAmount, currency, taxCode, taxAmount});
navigateBack();
return;
}
@@ -333,7 +351,7 @@ function IOURequestStepAmount({
transactionThreadReportID: reportID,
transactions: duplicateTransactions,
transactionViolations: duplicateTransactionViolations,
- currency: selectedCurrency,
+ currency,
amount: newAmount,
taxAmount,
policy,
@@ -346,18 +364,6 @@ function IOURequestStepAmount({
navigateBack();
};
- const hideCurrencyPicker = useCallback(() => {
- setIsCurrencyPickerVisible(false);
- }, []);
-
- const updateSelectedCurrency = useCallback((value: string) => {
- setSelectedCurrency(value);
- }, []);
-
- const showCurrencyPicker = useCallback(() => {
- setIsCurrencyPickerVisible(true);
- }, []);
-
return (
-
;
+
+function IOURequestStepCurrency({
+ route: {
+ params: {backTo, pageIndex, transactionID, action, currency: selectedCurrency = ''},
+ },
+}: IOURequestStepCurrencyProps) {
+ const {translate} = useLocalize();
+ const [draftTransaction] = useOnyx(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${transactionID}`, {canBeMissing: true});
+ const [recentlyUsedCurrencies] = useOnyx(ONYXKEYS.RECENTLY_USED_CURRENCIES, {canBeMissing: true});
+ const {currency: originalCurrency = ''} = getTransactionDetails(draftTransaction) ?? {};
+ const currency = isValidCurrencyCode(selectedCurrency) ? selectedCurrency : originalCurrency;
+
+ const navigateBack = (selectedCurrencyValue = '') => {
+ // If the currency selection was done from the confirmation step (eg. + > submit expense > manual > confirm > amount > currency)
+ // then the user needs taken back to the confirmation page instead of the initial amount page. This is because the route params
+ // are only able to handle one backTo param at a time and the user needs to go back to the amount page before going back
+ // to the confirmation page
+ if (pageIndex === CONST.IOU.PAGE_INDEX.CONFIRM) {
+ if (selectedCurrencyValue) {
+ Navigation.goBack(appendParam(backTo as string, 'currency', selectedCurrencyValue), {compareParams: false});
+ } else {
+ Navigation.goBack(backTo);
+ }
+ return;
+ }
+ Navigation.goBack(backTo);
+ };
+
+ const confirmCurrencySelection = (option: CurrencyListItem) => {
+ Keyboard.dismiss();
+ if (pageIndex !== CONST.IOU.PAGE_INDEX.CONFIRM) {
+ setMoneyRequestCurrency(transactionID, option.currencyCode, action === CONST.IOU.ACTION.EDIT);
+ }
+
+ Navigation.setNavigationActionToMicrotaskQueue(() => navigateBack(option.currencyCode));
+ };
+
+ return (
+ navigateBack()}
+ shouldShowWrapper
+ testID={IOURequestStepCurrency.displayName}
+ includeSafeAreaPaddingBottom
+ >
+ {({didScreenTransitionEnd}) => (
+ {
+ if (!didScreenTransitionEnd) {
+ return;
+ }
+ confirmCurrencySelection(option);
+ }}
+ initiallySelectedCurrencyCode={currency.toUpperCase()}
+ />
+ )}
+
+ );
+}
+
+IOURequestStepCurrency.displayName = 'IOURequestStepCurrency';
+
+/* eslint-disable rulesdir/no-negated-variables */
+const IOURequestStepCurrencyWithFullTransactionOrNotFound = withFullTransactionOrNotFound(IOURequestStepCurrency);
+
+export default IOURequestStepCurrencyWithFullTransactionOrNotFound;
diff --git a/src/pages/iou/request/step/IOURequestStepCurrencyModal.tsx b/src/pages/iou/request/step/IOURequestStepCurrencyModal.tsx
deleted file mode 100644
index 0c3c1a309080..000000000000
--- a/src/pages/iou/request/step/IOURequestStepCurrencyModal.tsx
+++ /dev/null
@@ -1,81 +0,0 @@
-import React from 'react';
-import CurrencySelectionList from '@components/CurrencySelectionList';
-import type {CurrencyListItem} from '@components/CurrencySelectionList/types';
-import HeaderWithBackButton from '@components/HeaderWithBackButton';
-import Modal from '@components/Modal';
-import ScreenWrapper from '@components/ScreenWrapper';
-import useLocalize from '@hooks/useLocalize';
-import useOnyx from '@hooks/useOnyx';
-import useThemeStyles from '@hooks/useThemeStyles';
-import Navigation from '@libs/Navigation/Navigation';
-import CONST from '@src/CONST';
-import ONYXKEYS from '@src/ONYXKEYS';
-
-type CurrencyPickerProps = {
- /** Whether the picker modal is visible */
- isPickerVisible: boolean;
-
- /** Function to hide the picker modal */
- hidePickerModal: () => void;
-
- /** Header text for the modal */
- headerText: string;
-
- /** Current value of the selected item */
- value?: string;
-
- /** Callback when the list item is selected */
- onInputChange?: (value: string, key?: string) => void;
-
- /** List of currencies to exclude from the list */
- excludeCurrencies?: string[];
-};
-
-function IOURequestStepCurrencyModal({isPickerVisible, hidePickerModal, headerText, value, excludeCurrencies, onInputChange = () => {}}: CurrencyPickerProps) {
- const {translate} = useLocalize();
- const [recentlyUsedCurrencies] = useOnyx(ONYXKEYS.RECENTLY_USED_CURRENCIES, {canBeMissing: true});
- const styles = useThemeStyles();
-
- const updateInput = (item: CurrencyListItem) => {
- onInputChange?.(item.currencyCode);
- hidePickerModal();
- };
-
- return (
-
-
-
-
-
-
- );
-}
-
-IOURequestStepCurrencyModal.displayName = 'IOURequestStepCurrencyModal';
-export default IOURequestStepCurrencyModal;
diff --git a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.tsx b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.tsx
index 1d0dab8c8dbc..c54346dc5113 100644
--- a/src/pages/iou/request/step/IOURequestStepTaxAmountPage.tsx
+++ b/src/pages/iou/request/step/IOURequestStepTaxAmountPage.tsx
@@ -8,7 +8,7 @@ import useOnyx from '@hooks/useOnyx';
import usePermissions from '@hooks/usePermissions';
import useRestartOnReceiptFailure from '@hooks/useRestartOnReceiptFailure';
import {setDraftSplitTransaction, setMoneyRequestCurrency, setMoneyRequestParticipantsFromReport, setMoneyRequestTaxAmount, updateMoneyRequestTaxAmount} from '@libs/actions/IOU';
-import {convertToBackendAmount} from '@libs/CurrencyUtils';
+import {convertToBackendAmount, isValidCurrencyCode} from '@libs/CurrencyUtils';
import Navigation from '@libs/Navigation/Navigation';
import {getTransactionDetails} from '@libs/ReportUtils';
import {calculateTaxAmount, getAmount, getDefaultTaxCode, getTaxValue, getTaxAmount as getTransactionTaxAmount} from '@libs/TransactionUtils';
@@ -46,7 +46,7 @@ function getTaxAmount(transaction: OnyxEntry, policy: OnyxEntry {
@@ -87,6 +87,23 @@ function IOURequestStepTaxAmountPage({
Navigation.goBack(backTo);
};
+ const navigateToCurrencySelectionPage = () => {
+ // If the expense being created is a distance expense, don't allow the user to choose the currency.
+ // Only USD is allowed for distance expenses.
+ // Remove query from the route and encode it.
+ Navigation.navigate(
+ ROUTES.MONEY_REQUEST_STEP_CURRENCY.getRoute(
+ CONST.IOU.ACTION.CREATE,
+ iouType,
+ transactionID,
+ reportID,
+ backTo ? 'confirm' : '',
+ currency,
+ Navigation.getActiveRouteWithoutParams(),
+ ),
+ );
+ };
+
const updateTaxAmount = (currentAmount: CurrentMoney) => {
const taxAmountInSmallestCurrencyUnits = convertToBackendAmount(Number.parseFloat(currentAmount.amount));
@@ -157,8 +174,7 @@ function IOURequestStepTaxAmountPage({
ref={(e) => {
textInput.current = e;
}}
- // onCurrencyButtonPress is intentionally left empty as currency selection is not allowed on this page
- onCurrencyButtonPress={() => {}}
+ onCurrencyButtonPress={navigateToCurrencySelectionPage}
onSubmitButtonPress={updateTaxAmount}
isCurrencyPressable={false}
chatReportID={reportID}
diff --git a/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx b/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx
index a2858b91b1f5..2c1c6d40c815 100644
--- a/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx
+++ b/src/pages/iou/request/step/withFullTransactionOrNotFound.tsx
@@ -3,7 +3,6 @@ import type {ComponentType} from 'react';
import React from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
-import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
import useOnyx from '@hooks/useOnyx';
import getComponentDisplayName from '@libs/getComponentDisplayName';
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
@@ -40,6 +39,7 @@ type MoneyRequestRouteName =
| typeof SCREENS.MONEY_REQUEST.STEP_CATEGORY
| typeof SCREENS.MONEY_REQUEST.STEP_TAX_RATE
| typeof SCREENS.MONEY_REQUEST.STEP_SCAN
+ | typeof SCREENS.MONEY_REQUEST.STEP_CURRENCY
| typeof SCREENS.MONEY_REQUEST.STEP_SEND_FROM
| typeof SCREENS.MONEY_REQUEST.STEP_REPORT
| typeof SCREENS.MONEY_REQUEST.STEP_COMPANY_INFO
@@ -56,7 +56,6 @@ type WithFullTransactionOrNotFoundProps
export default function >(
WrappedComponent: ComponentType,
- shouldShowLoadingIndicator = false,
): React.ComponentType> {
// eslint-disable-next-line rulesdir/no-negated-variables
function WithFullTransactionOrNotFound(props: Omit) {
@@ -82,10 +81,6 @@ export default function ;
}
-
- if (isLoadingTransaction && shouldShowLoadingIndicator) {
- return ;
- }
return (