Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CP Staging] Feat/36985 create new rate field followups #40711

Merged
5 changes: 1 addition & 4 deletions src/components/MoneyRequestConfirmationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ function MoneyRequestPreviewContent({
}

if (isFetchingWaypointsFromServer && !requestAmount) {
return translate('iou.routePending');
return translate('iou.fieldPending');
}

return CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency);
Expand Down
18 changes: 11 additions & 7 deletions src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import type {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
import type {IOUMessage} from '@src/types/onyx/OriginalMessage';
import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction';
import ReportActionItemImage from './ReportActionItemImage';

Expand Down Expand Up @@ -67,8 +68,8 @@ type MoneyRequestViewOnyxPropsWithoutTransaction = {
/** The actions from the parent report */
parentReportActions: OnyxEntry<OnyxTypes.ReportActions>;

/** The rates for the policy */
rates: Record<string, MileageRate>;
/** The distance rates from the policy */
distanceRates: Record<string, MileageRate>;
};

type MoneyRequestViewPropsWithoutTransaction = MoneyRequestViewOnyxPropsWithoutTransaction & {
Expand All @@ -95,16 +96,17 @@ function MoneyRequestView({
policy,
transactionViolations,
shouldShowAnimatedBackground,
rates,
distanceRates,
}: MoneyRequestViewProps) {
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {isOffline} = useNetwork();
const {isSmallScreenWidth} = useWindowDimensions();
const {translate, toLocaleDigit} = useLocalize();
const {canUseViolations, canUseP2PDistanceRequests} = usePermissions();
const parentReportAction = parentReportActions?.[report.parentReportActionID ?? ''] ?? null;
const isExpenseTracking = (parentReportAction?.originalMessage as IOUMessage)?.type === CONST.IOU.REPORT_ACTION_TYPE.TRACK;
const {canUseViolations, canUseP2PDistanceRequests} = usePermissions(isExpenseTracking ? CONST.IOU.TYPE.TRACK : undefined);
const moneyRequestReport = parentReport;
const {
created: transactionDate,
Expand Down Expand Up @@ -186,8 +188,9 @@ 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] ?? {};
neil-marcellini marked this conversation as resolved.
Show resolved Hide resolved
const {unit} = mileageRate;
const rate = (transaction?.comment?.customUnit?.defaultP2PRate as number) ?? mileageRate.rate;

const distance = DistanceRequestUtils.getDistanceFromMerchant(transactionMerchant, unit);
const rateToDisplay = DistanceRequestUtils.getRateForDisplay(unit, rate, currency, translate, toLocaleDigit, isOffline);
Expand Down Expand Up @@ -290,6 +293,7 @@ function MoneyRequestView({
onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE.getRoute(CONST.IOU.ACTION.EDIT, iouType, transaction?.transactionID ?? '', report.reportID))}
/>
</OfflineWithFeedback>
{/* TODO: correct the pending field action https://github.com/Expensify/App/issues/36988 (?) */}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the (?)? 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure if it's a proper issue to link

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, it should be this issue I think. Next time you could ask us directly or look at the P2P distance project board.
#36987

<OfflineWithFeedback pendingAction={getPendingFieldAction('waypoints')}>
<MenuItemWithTopDescription
description={translate('common.rate')}
Expand Down Expand Up @@ -561,7 +565,7 @@ export default withOnyx<MoneyRequestViewPropsWithoutTransaction, MoneyRequestVie
key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report ? report.parentReportID : '0'}`,
canEvict: false,
},
rates: {
distanceRates: {
key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`,
selector: DistanceRequestUtils.getMileageRates,
},
Expand Down
2 changes: 1 addition & 1 deletion src/components/ReportActionItem/ReportPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
2 changes: 1 addition & 1 deletion src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 1 addition & 1 deletion src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
47 changes: 22 additions & 25 deletions src/libs/DistanceRequestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,6 @@ type MileageRate = {
name?: string;
};

const policies: OnyxCollection<Policy> = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY,
callback: (policy, key) => {
if (!policy || !key || !policy.name) {
return;
}

policies[key] = policy;
},
});

let lastSelectedDistanceRates: OnyxEntry<LastSelectedDistanceRates> = {};
Onyx.connect({
key: ONYXKEYS.NVP_LAST_SELECTED_DISTANCE_RATES,
Expand All @@ -50,6 +38,12 @@ Onyx.connect({
const METERS_TO_KM = 0.001; // 1 kilometer is 1000 meters
const METERS_TO_MILES = 0.000621371; // There are approximately 0.000621371 miles in a meter

/** Validates that the merchant for a distance request transaction is in the expected format.
* <distance> <unit> @ <formatted rate with currency> / <unit>
* Example: 1.45 miles @ $0.67 / mi
*/
const distanceMerchantRegex = /^[0-9.]+ \w+ @ (-|-\()?(\p{Sc}|\p{L}|\w){1,3} ?[0-9.]+\)? \/ \w+$/u;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment explaining what this does. Something like this.

        // Validates that the merchant for a distance request transaction is in the expected format.
        // <distance> <unit> @ <formatted rate with currency> / <unit>
        // Example: 1.45 miles @ $0.67 / mi

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it'd be nice if we can move this to CONST.ts

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@getusha no longer necessary - we decided to remove this


/**
* Retrieves the default mileage rate based on a given policy.
*
Expand Down Expand Up @@ -116,7 +110,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,
Expand All @@ -130,15 +124,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}`;
}

/**
Expand All @@ -150,8 +144,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);
Expand Down Expand Up @@ -182,7 +176,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);
Expand All @@ -201,11 +195,7 @@ function getDistanceMerchant(
function getMileageRates(policy: OnyxEntry<Policy>): Record<string, MileageRate> {
const mileageRates: Record<string, MileageRate> = {};

if (!policy) {
return mileageRates;
}

if (!policy?.customUnits) {
if (!policy || !policy?.customUnits) {
return mileageRates;
}

Expand All @@ -227,6 +217,13 @@ function getMileageRates(policy: OnyxEntry<Policy>): Record<string, MileageRate>
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.
*/

neil-marcellini marked this conversation as resolved.
Show resolved Hide resolved
function getRateForP2P(currency: string): RateAndUnit {
return CONST.CURRENCY_TO_DEFAULT_MILEAGE_RATE[currency] ?? CONST.CURRENCY_TO_DEFAULT_MILEAGE_RATE.USD;
}
Expand All @@ -252,7 +249,7 @@ function getDistanceRequestAmount(distance: number, unit: Unit, rate: number): n
* @returns The distance extracted from the merchant string.
*/
function getDistanceFromMerchant(merchant: string | undefined, unit: Unit): number {
if (!merchant) {
if (!merchant || !distanceMerchantRegex.test(merchant ?? '')) {
return 0;
}

Expand Down
4 changes: 2 additions & 2 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2633,7 +2633,7 @@ function getTransactionReportName(reportAction: OnyxEntry<ReportAction | Optimis
}

if (TransactionUtils.isFetchingWaypointsFromServer(transaction)) {
return Localize.translateLocal('iou.routePending');
return Localize.translateLocal('iou.fieldPending');
}

if (TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction)) {
Expand Down Expand Up @@ -2746,7 +2746,7 @@ function getReportPreviewMessage(
}

if (!isEmptyObject(linkedTransaction) && TransactionUtils.isFetchingWaypointsFromServer(linkedTransaction) && !TransactionUtils.getAmount(linkedTransaction)) {
return Localize.translateLocal('iou.routePending');
return Localize.translateLocal('iou.fieldPending');
}

const originalMessage = iouReportAction?.originalMessage as IOUMessage | undefined;
Expand Down
4 changes: 2 additions & 2 deletions src/libs/actions/IOU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1857,7 +1857,7 @@ function getUpdateMoneyRequestParams(
...updatedTransaction,
amount: CONST.IOU.DEFAULT_AMOUNT,
modifiedAmount: CONST.IOU.DEFAULT_AMOUNT,
modifiedMerchant: Localize.translateLocal('iou.routePending'),
modifiedMerchant: Localize.translateLocal('iou.fieldPending'),
};

// Delete the draft transaction when editing waypoints when the server responds successfully and there are no errors
Expand Down Expand Up @@ -2139,7 +2139,7 @@ function getUpdateTrackExpenseParams(
...updatedTransaction,
amount: CONST.IOU.DEFAULT_AMOUNT,
modifiedAmount: CONST.IOU.DEFAULT_AMOUNT,
modifiedMerchant: Localize.translateLocal('iou.routePending'),
modifiedMerchant: Localize.translateLocal('iou.fieldPending'),
};

// Delete the draft transaction when editing waypoints when the server responds successfully and there are no errors
Expand Down
6 changes: 3 additions & 3 deletions src/pages/iou/request/step/IOURequestStepDistance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ function IOURequestStepDistance({
amount: 0,
comment: '',
currency: transaction?.currency ?? 'USD',
merchant: translate('iou.routePending'),
merchant: translate('iou.fieldPending'),
created: transaction?.created ?? '',
category: '',
tag: '',
Expand All @@ -242,7 +242,7 @@ function IOURequestStepDistance({
return;
}
IOU.setMoneyRequestPendingFields(transactionID, {waypoints: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD});
IOU.setMoneyRequestMerchant(transactionID, translate('iou.routePending'), false);
IOU.setMoneyRequestMerchant(transactionID, translate('iou.fieldPending'), false);
IOU.createDistanceRequest(
report,
participants[0],
Expand All @@ -252,7 +252,7 @@ function IOURequestStepDistance({
'',
0,
transaction?.currency ?? 'USD',
translate('iou.routePending'),
translate('iou.fieldPending'),
false,
TransactionUtils.getValidWaypoints(waypoints, true),
);
Expand Down
Loading