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
25 changes: 14 additions & 11 deletions src/components/ReportActionItem/MoneyRequestView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,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 +95,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 isTrackExpense = ReportUtils.isTrackExpenseReport(report);
const {canUseViolations, canUseP2PDistanceRequests} = usePermissions(isTrackExpense ? CONST.IOU.TYPE.TRACK : undefined);
const moneyRequestReport = parentReport;
const {
created: transactionDate,
Expand Down Expand Up @@ -150,15 +151,15 @@ 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
const isPolicyExpenseChat = ReportUtils.isGroupPolicy(report);

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
Expand Down Expand Up @@ -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] ?? {};
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 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);

Expand Down Expand Up @@ -283,13 +285,14 @@ function MoneyRequestView({
<OfflineWithFeedback pendingAction={getPendingFieldAction('waypoints')}>
<MenuItemWithTopDescription
description={translate('common.distance')}
title={distanceToDisplay}
title={getPendingFieldAction('waypoints') ? translate('iou.fieldPending') : distanceToDisplay}
Copy link
Member

Choose a reason for hiding this comment

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

We don't need this now. #43569

interactive={canEditDistance}
shouldShowRightIcon={canEditDistance}
titleStyle={styles.flex1}
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/36987 */}
<OfflineWithFeedback pendingAction={getPendingFieldAction('waypoints')}>
<MenuItemWithTopDescription
description={translate('common.rate')}
Expand Down Expand Up @@ -561,7 +564,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
61 changes: 23 additions & 38 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 Down Expand Up @@ -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,
Expand All @@ -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}`;
}

/**
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -201,11 +189,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 +211,12 @@ 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.
*/
function getRateForP2P(currency: string): RateAndUnit {
return CONST.CURRENCY_TO_DEFAULT_MILEAGE_RATE[currency] ?? CONST.CURRENCY_TO_DEFAULT_MILEAGE_RATE.USD;
}
Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -289,8 +274,8 @@ export default {
getMileageRates,
getDistanceForDisplay,
getRateForP2P,
getDistanceFromMerchant,
getCustomUnitRateID,
convertToDistanceInMeters,
};

export type {MileageRate};
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
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function IOURequestStepDistanceRate({

const unit = (Object.values(rates)[0]?.unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.mile') : translate('common.kilometer')) as Unit;

const initiallyFocusedOption = rates[lastSelectedRateID]?.name ?? CONST.CUSTOM_UNITS.DEFAULT_RATE;
const initiallyFocusedOption = sections.find((item) => item.isSelected)?.keyForList;

function selectDistanceRate(customUnitRateID: string) {
IOU.updateDistanceRequestRate(transactionID, customUnitRateID, policy?.id ?? '');
Expand Down
Loading