Skip to content

Commit

Permalink
Merge pull request #27816 from samh-nl/fix/issue-27107
Browse files Browse the repository at this point in the history
fix: use common function to display rate
  • Loading branch information
luacmartins authored Sep 25, 2023
2 parents 19f93db + 2fc4738 commit 5b33d50
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 53 deletions.
1 change: 1 addition & 0 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,7 @@ const CONST = {
DISTANCE_UNIT_KILOMETERS: 'km',
MILEAGE_IRS_RATE: 0.655,
DEFAULT_RATE: 'Default Rate',
RATE_DECIMALS: 3,
},

TERMS: {
Expand Down
6 changes: 3 additions & 3 deletions src/components/MoneyRequestConfirmationList.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ function MoneyRequestConfirmationList(props) {
// Destructure functions from props to pass it as a dependecy to useCallback/useMemo hooks.
// Prop functions pass props itself as a "this" value to the function which means they change every time props change.
const {onSendMoney, onConfirm, onSelectParticipant, transaction} = props;
const {translate} = useLocalize();
const {translate, toLocaleDigit} = useLocalize();

// A flag and a toggler for showing the rest of the form fields
const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false);
Expand Down Expand Up @@ -338,9 +338,9 @@ function MoneyRequestConfirmationList(props) {
if (!props.isDistanceRequest) {
return;
}
const distanceMerchant = DistanceRequestUtils.getDistanceMerchant(hasRoute, distance, unit, rate, currency, translate);
const distanceMerchant = DistanceRequestUtils.getDistanceMerchant(hasRoute, distance, unit, rate, currency, translate, toLocaleDigit);
IOU.setMoneyRequestMerchant(distanceMerchant);
}, [hasRoute, distance, unit, rate, currency, translate, props.isDistanceRequest]);
}, [hasRoute, distance, unit, rate, currency, translate, toLocaleDigit, props.isDistanceRequest]);

/**
* @param {Object} option
Expand Down
6 changes: 4 additions & 2 deletions src/libs/DistanceRequestUtils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import _ from 'underscore';
import CONST from '../CONST';
import * as CurrencyUtils from './CurrencyUtils';
import * as PolicyUtils from './PolicyUtils';

/**
* Retrieves the default mileage rate based on a given policy.
Expand Down Expand Up @@ -79,16 +80,17 @@ const getRoundedDistanceInUnits = (distanceInMeters, unit) => {
* @param {Number} rate Expensable amount allowed per unit
* @param {String} currency The currency associated with the rate
* @param {Function} translate Translate function
* @param {Function} toLocaleDigit Function to convert to localized digit
* @returns {String} A string that describes the distance traveled and the rate used for expense calculation
*/
const getDistanceMerchant = (hasRoute, distanceInMeters, unit, rate, currency, translate) => {
const getDistanceMerchant = (hasRoute, distanceInMeters, unit, rate, currency, translate, toLocaleDigit) => {
const distanceInUnits = hasRoute ? getRoundedDistanceInUnits(distanceInMeters, unit) : translate('common.tbd');

const distanceUnit = unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.miles') : translate('common.kilometers');
const singularDistanceUnit = unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.mile') : translate('common.kilometer');
const unitString = distanceInUnits === 1 ? singularDistanceUnit : distanceUnit;

const ratePerUnit = rate * 0.01;
const ratePerUnit = PolicyUtils.getUnitRateValue({rate}, toLocaleDigit);
const currencySymbol = CurrencyUtils.getCurrencySymbol(currency) || `${currency} `;

return `${distanceInUnits} ${unitString} @ ${currencySymbol}${ratePerUnit} / ${singularDistanceUnit}`;
Expand Down
38 changes: 38 additions & 0 deletions src/libs/PolicyUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,42 @@ function hasCustomUnitsError(policy) {
return !_.isEmpty(_.pick(lodashGet(policy, 'customUnits', {}), 'errors'));
}

/**
* @param {Number} value
* @param {Function} toLocaleDigit
* @returns {Number}
*/
function getNumericValue(value, toLocaleDigit) {
const numValue = parseFloat(value.toString().replace(toLocaleDigit('.'), '.'));
if (Number.isNaN(numValue)) {
return NaN;
}
return numValue.toFixed(CONST.CUSTOM_UNITS.RATE_DECIMALS);
}

/**
* @param {Number} value
* @param {Function} toLocaleDigit
* @returns {String}
*/
function getRateDisplayValue(value, toLocaleDigit) {
const numValue = getNumericValue(value, toLocaleDigit);
if (Number.isNaN(numValue)) {
return '';
}
return numValue.toString().replace('.', toLocaleDigit('.')).substring(0, value.length);
}

/**
* @param {Object} customUnitRate
* @param {Number} customUnitRate.rate
* @param {Function} toLocaleDigit
* @returns {String}
*/
function getUnitRateValue(customUnitRate, toLocaleDigit) {
return getRateDisplayValue(lodashGet(customUnitRate, 'rate', 0) / CONST.POLICY.CUSTOM_UNIT_RATE_BASE_OFFSET, toLocaleDigit);
}

/**
* Get the brick road indicator status for a policy. The policy has an error status if there is a policy member error, a custom unit error or a field error.
*
Expand Down Expand Up @@ -181,6 +217,8 @@ export {
hasPolicyError,
hasPolicyErrorFields,
hasCustomUnitsError,
getNumericValue,
getUnitRateValue,
getPolicyBrickRoadIndicatorStatus,
shouldShowPolicy,
isExpensifyTeam,
Expand Down
25 changes: 3 additions & 22 deletions src/pages/workspace/reimburse/WorkspaceRateAndUnitPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import withLocalize, {withLocalizePropTypes} from '../../../components/withLocal
import styles from '../../../styles/styles';
import compose from '../../../libs/compose';
import * as Policy from '../../../libs/actions/Policy';
import * as PolicyUtils from '../../../libs/PolicyUtils';
import CONST from '../../../CONST';
import Picker from '../../../components/Picker';
import TextInput from '../../../components/TextInput';
Expand Down Expand Up @@ -35,33 +36,13 @@ class WorkspaceRateAndUnitPage extends React.Component {
this.validate = this.validate.bind(this);
}

getUnitRateValue(customUnitRate) {
return this.getRateDisplayValue(lodashGet(customUnitRate, 'rate', 0) / CONST.POLICY.CUSTOM_UNIT_RATE_BASE_OFFSET);
}

getUnitItems() {
return [
{label: this.props.translate('common.kilometers'), value: CONST.CUSTOM_UNITS.DISTANCE_UNIT_KILOMETERS},
{label: this.props.translate('common.miles'), value: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES},
];
}

getRateDisplayValue(value) {
const numValue = this.getNumericValue(value);
if (Number.isNaN(numValue)) {
return '';
}
return numValue.toString().replace('.', this.props.toLocaleDigit('.')).substring(0, value.length);
}

getNumericValue(value) {
const numValue = parseFloat(value.toString().replace(',', '.'));
if (Number.isNaN(numValue)) {
return NaN;
}
return numValue.toFixed(3);
}

saveUnitAndRate(unit, rate) {
const distanceCustomUnit = _.find(lodashGet(this.props, 'policy.customUnits', {}), (u) => u.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
if (!distanceCustomUnit) {
Expand All @@ -70,7 +51,7 @@ class WorkspaceRateAndUnitPage extends React.Component {
const currentCustomUnitRate = _.find(lodashGet(distanceCustomUnit, 'rates', {}), (r) => r.name === CONST.CUSTOM_UNITS.DEFAULT_RATE);
const unitID = lodashGet(distanceCustomUnit, 'customUnitID', '');
const unitName = lodashGet(distanceCustomUnit, 'name', '');
const rateNumValue = this.getNumericValue(rate);
const rateNumValue = PolicyUtils.getNumericValue(rate, this.props.toLocaleDigit);

const newCustomUnit = {
customUnitID: unitID,
Expand Down Expand Up @@ -137,7 +118,7 @@ class WorkspaceRateAndUnitPage extends React.Component {
accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
inputID="rate"
containerStyles={[styles.mt4]}
defaultValue={this.getUnitRateValue(distanceCustomRate)}
defaultValue={PolicyUtils.getUnitRateValue(distanceCustomRate, this.props.toLocaleDigit)}
label={this.props.translate('workspace.reimburse.trackDistanceRate')}
accessibilityLabel={this.props.translate('workspace.reimburse.trackDistanceRate')}
placeholder={lodashGet(this.props, 'policy.outputCurrency', CONST.CURRENCY.USD)}
Expand Down
29 changes: 3 additions & 26 deletions src/pages/workspace/reimburse/WorkspaceReimburseView.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import CopyTextToClipboard from '../../../components/CopyTextToClipboard';
import * as Link from '../../../libs/actions/Link';
import compose from '../../../libs/compose';
import * as Policy from '../../../libs/actions/Policy';
import * as PolicyUtils from '../../../libs/PolicyUtils';
import CONST from '../../../CONST';
import ROUTES from '../../../ROUTES';
import ONYXKEYS from '../../../ONYXKEYS';
Expand Down Expand Up @@ -71,39 +72,15 @@ function WorkspaceReimburseView(props) {
const distanceCustomRate = _.find(lodashGet(distanceCustomUnit, 'rates', {}), (rate) => rate.name === CONST.CUSTOM_UNITS.DEFAULT_RATE);
const {translate, toLocaleDigit} = props;

const getNumericValue = useCallback(
(value) => {
const numValue = parseFloat(value.toString().replace(toLocaleDigit('.'), '.'));
if (Number.isNaN(numValue)) {
return NaN;
}
return numValue.toFixed(3);
},
[toLocaleDigit],
);

const getRateDisplayValue = useCallback(
(value) => {
const numValue = getNumericValue(value);
if (Number.isNaN(numValue)) {
return '';
}
return numValue.toString().replace('.', toLocaleDigit('.')).substring(0, value.length);
},
[getNumericValue, toLocaleDigit],
);

const getRateLabel = useCallback((customUnitRate) => getRateDisplayValue(lodashGet(customUnitRate, 'rate', 0) / CONST.POLICY.CUSTOM_UNIT_RATE_BASE_OFFSET), [getRateDisplayValue]);

const getUnitLabel = useCallback((value) => translate(`common.${value}`), [translate]);

const getCurrentRatePerUnitLabel = useCallback(() => {
const customUnitRate = _.find(lodashGet(distanceCustomUnit, 'rates', '{}'), (rate) => rate && rate.name === CONST.CUSTOM_UNITS.DEFAULT_RATE);
const currentUnit = getUnitLabel(lodashGet(distanceCustomUnit, 'attributes.unit', CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES));
const currentRate = getRateLabel(customUnitRate);
const currentRate = PolicyUtils.getUnitRateValue(customUnitRate, toLocaleDigit);
const perWord = translate('common.per');
return `${currentRate} ${perWord} ${currentUnit}`;
}, [translate, distanceCustomUnit, getUnitLabel, getRateLabel]);
}, [translate, distanceCustomUnit, toLocaleDigit, getUnitLabel]);

const fetchData = useCallback(() => {
// Instead of setting the reimbursement account loading within the optimistic data of the API command, use a separate action so that the Onyx value is updated right away.
Expand Down

0 comments on commit 5b33d50

Please sign in to comment.