diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 99901dd261de..552b849e74a3 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -749,7 +749,6 @@ function MoneyRequestConfirmationList({ style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(action, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams()))} - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing disabled={didConfirm} // todo: handle edit for transaction while moving from track expense interactive={!isReadOnly && !isMovingTransactionFromTrackExpense} @@ -767,9 +766,7 @@ function MoneyRequestConfirmationList({ description={translate('common.distance')} style={[styles.moneyRequestMenuItem]} titleStyle={styles.flex1} - onPress={() => - Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.CREATE, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams())) - } + onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(action, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams()))} disabled={didConfirm} interactive={!isReadOnly} /> diff --git a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx index 8994d456904a..7f70a3e538a9 100644 --- a/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx +++ b/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx @@ -196,7 +196,7 @@ function MoneyRequestPreviewContent({ } if (isFetchingWaypointsFromServer && !requestAmount) { - return translate('iou.routePending'); + return translate('iou.fieldPending'); } return CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency); diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index c804ef33b35c..08bcc16cbbee 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -67,8 +67,8 @@ type MoneyRequestViewOnyxPropsWithoutTransaction = { /** The actions from the parent report */ parentReportActions: OnyxEntry; - /** The rates for the policy */ - rates: Record; + /** The distance rates from the policy */ + distanceRates: Record; }; type MoneyRequestViewPropsWithoutTransaction = MoneyRequestViewOnyxPropsWithoutTransaction & { @@ -95,7 +95,7 @@ function MoneyRequestView({ policy, transactionViolations, shouldShowAnimatedBackground, - rates, + distanceRates, }: MoneyRequestViewProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -103,8 +103,9 @@ function MoneyRequestView({ const {isOffline} = useNetwork(); const {isSmallScreenWidth} = useWindowDimensions(); const {translate, toLocaleDigit} = useLocalize(); - const {canUseViolations, canUseP2PDistanceRequests} = usePermissions(); const parentReportAction = parentReportActions?.[report.parentReportActionID ?? ''] ?? null; + const isTrackExpense = ReportUtils.isTrackExpenseReport(report); + const {canUseViolations, canUseP2PDistanceRequests} = usePermissions(isTrackExpense ? CONST.IOU.TYPE.TRACK : undefined); const moneyRequestReport = parentReport; const { created: transactionDate, @@ -150,7 +151,8 @@ function MoneyRequestView({ const canEditMerchant = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.MERCHANT); const canEditDate = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.DATE); const canEditReceipt = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.RECEIPT); - const canEditDistance = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.DISTANCE); + // TODO: remove the !isTrackExpense from this condition after this fix: https://github.com/Expensify/Expensify/issues/382786 + const canEditDistance = ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, CONST.EDIT_REQUEST_FIELD.DISTANCE) && !isTrackExpense; // A flag for verifying that the current report is a sub-report of a workspace chat // if the policy of the report is either Collect or Control, then this report must be tied to workspace chat @@ -158,7 +160,6 @@ function MoneyRequestView({ const policyTagLists = useMemo(() => PolicyUtils.getTagLists(policyTagList), [policyTagList]); - const isTrackExpense = ReportUtils.isTrackExpenseReport(report); const iouType = isTrackExpense ? CONST.IOU.TYPE.TRACK : CONST.IOU.TYPE.SUBMIT; // Flags for showing categories and tags @@ -186,10 +187,11 @@ function MoneyRequestView({ const currency = policy ? policy.outputCurrency : PolicyUtils.getPersonalPolicy()?.outputCurrency ?? CONST.CURRENCY.USD; - const mileageRate = TransactionUtils.isCustomUnitRateIDForP2P(transaction) ? DistanceRequestUtils.getRateForP2P(currency) : rates[rateID as string] ?? {}; - const {unit, rate} = mileageRate; + const mileageRate = TransactionUtils.isCustomUnitRateIDForP2P(transaction) ? DistanceRequestUtils.getRateForP2P(currency) : distanceRates[rateID as string] ?? {}; + const {unit} = mileageRate; + const rate = (transaction?.comment?.customUnit?.defaultP2PRate as number) ?? mileageRate.rate; - const distance = DistanceRequestUtils.getDistanceFromMerchant(transactionMerchant, unit); + const distance = DistanceRequestUtils.convertToDistanceInMeters((transaction?.comment?.customUnit?.quantity as number) ?? 0, unit); const rateToDisplay = DistanceRequestUtils.getRateForDisplay(unit, rate, currency, translate, toLocaleDigit, isOffline); const distanceToDisplay = DistanceRequestUtils.getDistanceForDisplay(hasRoute, distance, unit, rate, translate); @@ -283,13 +285,14 @@ function MoneyRequestView({ Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '', report.reportID))} /> + {/* TODO: correct the pending field action https://github.com/Expensify/App/issues/36987 */} `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`, canEvict: false, }, - rates: { + distanceRates: { key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`, selector: DistanceRequestUtils.getMileageRates, }, diff --git a/src/components/ReportActionItem/ReportPreview.tsx b/src/components/ReportActionItem/ReportPreview.tsx index d14d2df1bb43..5c78e1e2604e 100644 --- a/src/components/ReportActionItem/ReportPreview.tsx +++ b/src/components/ReportActionItem/ReportPreview.tsx @@ -165,7 +165,7 @@ function ReportPreview({ return translate('iou.receiptScanning'); } if (hasOnlyTransactionsWithPendingRoutes) { - return translate('iou.routePending'); + return translate('iou.fieldPending'); } // If iouReport is not available, get amount from the action message (Ex: "Domain20821's Workspace owes $33.00" or "paid ₫60" or "paid -₫60 elsewhere") diff --git a/src/languages/en.ts b/src/languages/en.ts index 8cc27ac358da..f5ef8279a878 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -630,7 +630,7 @@ export default { canceled: 'Canceled', posted: 'Posted', deleteReceipt: 'Delete receipt', - routePending: 'Pending...', + fieldPending: 'Pending...', defaultRate: 'Default rate', receiptScanning: 'Scan in progress…', receiptMissingDetails: 'Receipt missing details', diff --git a/src/languages/es.ts b/src/languages/es.ts index fc370d37a48c..cda0ef862fda 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -623,7 +623,7 @@ export default { canceled: 'Canceló', posted: 'Contabilizado', deleteReceipt: 'Eliminar recibo', - routePending: 'Pendiente...', + fieldPending: 'Pendiente...', defaultRate: 'Tasa predeterminada', receiptScanning: 'Escaneo en curso…', receiptMissingDetails: 'Recibo con campos vacíos', diff --git a/src/libs/DistanceRequestUtils.ts b/src/libs/DistanceRequestUtils.ts index 676c4493fe75..9cb48534214e 100644 --- a/src/libs/DistanceRequestUtils.ts +++ b/src/libs/DistanceRequestUtils.ts @@ -20,18 +20,6 @@ type MileageRate = { name?: string; }; -const policies: OnyxCollection = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY, - callback: (policy, key) => { - if (!policy || !key || !policy.name) { - return; - } - - policies[key] = policy; - }, -}); - let lastSelectedDistanceRates: OnyxEntry = {}; Onyx.connect({ key: ONYXKEYS.NVP_LAST_SELECTED_DISTANCE_RATES, @@ -116,7 +104,7 @@ function getRoundedDistanceInUnits(distanceInMeters: number, unit: Unit): string * @param currency The currency associated with the rate * @param translate Translate function * @param toLocaleDigit Function to convert to localized digit - * @returns A string that describes the distance traveled and the rate used for expense calculation + * @returns A string that displays the rate used for expense calculation */ function getRateForDisplay( unit: Unit | undefined, @@ -130,15 +118,15 @@ function getRateForDisplay( return translate('iou.defaultRate'); } if (!rate || !currency || !unit) { - return translate('iou.routePending'); + return translate('iou.fieldPending'); } const singularDistanceUnit = unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.mile') : translate('common.kilometer'); - const ratePerUnit = PolicyUtils.getUnitRateValue(toLocaleDigit, {rate}); + const formattedRate = PolicyUtils.getUnitRateValue(toLocaleDigit, {rate}); // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing const currencySymbol = CurrencyUtils.getCurrencySymbol(currency) || `${currency} `; - return `${currencySymbol}${ratePerUnit} / ${singularDistanceUnit}`; + return `${currencySymbol}${formattedRate} / ${singularDistanceUnit}`; } /** @@ -150,8 +138,8 @@ function getRateForDisplay( * @returns A string that describes the distance traveled */ function getDistanceForDisplay(hasRoute: boolean, distanceInMeters: number, unit: Unit | undefined, rate: number | undefined, translate: LocaleContextProps['translate']): string { - if (!hasRoute || !rate || !unit) { - return translate('iou.routePending'); + if (!hasRoute || !rate || !unit || !distanceInMeters) { + return translate('iou.fieldPending'); } const distanceInUnits = getRoundedDistanceInUnits(distanceInMeters, unit); @@ -182,7 +170,7 @@ function getDistanceMerchant( toLocaleDigit: LocaleContextProps['toLocaleDigit'], ): string { if (!hasRoute || !rate) { - return translate('iou.routePending'); + return translate('iou.fieldPending'); } const distanceInUnits = getDistanceForDisplay(hasRoute, distanceInMeters, unit, rate, translate); @@ -201,11 +189,7 @@ function getDistanceMerchant( function getMileageRates(policy: OnyxEntry): Record { const mileageRates: Record = {}; - if (!policy) { - return mileageRates; - } - - if (!policy?.customUnits) { + if (!policy || !policy?.customUnits) { return mileageRates; } @@ -227,6 +211,12 @@ function getMileageRates(policy: OnyxEntry): Record return mileageRates; } +/** + * Retrieves the rate and unit for a P2P distance expense for a given currency. + * + * @param currency + * @returns The rate and unit in RateAndUnit object. + */ function getRateForP2P(currency: string): RateAndUnit { return CONST.CURRENCY_TO_DEFAULT_MILEAGE_RATE[currency] ?? CONST.CURRENCY_TO_DEFAULT_MILEAGE_RATE.USD; } @@ -246,22 +236,17 @@ function getDistanceRequestAmount(distance: number, unit: Unit, rate: number): n } /** - * Extracts the distance from a merchant string. + * Converts the distance from kilometers or miles to meters. * - * @param merchant - The merchant string containing the distance. - * @returns The distance extracted from the merchant string. + * @param distance - The distance to be converted. + * @param unit - The unit of measurement for the distance. + * @returns The distance in meters. */ -function getDistanceFromMerchant(merchant: string | undefined, unit: Unit): number { - if (!merchant) { - return 0; - } - - const distance = Number(merchant.split(' ')[0]); - if (!distance) { - return 0; +function convertToDistanceInMeters(distance: number, unit: Unit): number { + if (unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS) { + return distance / METERS_TO_KM; } - // we need to convert the distance back to meters (it's saved in kilometers or miles in merchant) to pass it to getDistanceForDisplay - return unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS ? distance / METERS_TO_KM : distance / METERS_TO_MILES; + return distance / METERS_TO_MILES; } /** @@ -289,8 +274,8 @@ export default { getMileageRates, getDistanceForDisplay, getRateForP2P, - getDistanceFromMerchant, getCustomUnitRateID, + convertToDistanceInMeters, }; export type {MileageRate}; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index a1e63bc5f48f..92d95405eb4c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -2633,7 +2633,7 @@ function getTransactionReportName(reportAction: OnyxEntry item.isSelected)?.keyForList; function selectDistanceRate(customUnitRateID: string) { IOU.updateDistanceRequestRate(transactionID, customUnitRateID, policy?.id ?? '');