Skip to content

Commit

Permalink
Merge pull request #38543 from koko57/feat/36985-create-new-rate-field
Browse files Browse the repository at this point in the history
Feat/36985 create new rate field
  • Loading branch information
neil-marcellini authored Apr 19, 2024
2 parents 4350e96 + a93e729 commit cba5f03
Show file tree
Hide file tree
Showing 22 changed files with 556 additions and 100 deletions.
5 changes: 3 additions & 2 deletions src/CONST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import * as KeyCommand from 'react-native-key-command';
import type {ValueOf} from 'type-fest';
import * as Url from './libs/Url';
import SCREENS from './SCREENS';
import type {Unit} from './types/onyx/Policy';

type RateAndUnit = {
unit: string;
unit: Unit;
rate: number;
};
type CurrencyDefaultMileageRate = Record<string, RateAndUnit>;
Expand Down Expand Up @@ -4351,6 +4352,6 @@ type Country = keyof typeof CONST.ALL_COUNTRIES;
type IOUType = ValueOf<typeof CONST.IOU.TYPE>;
type IOUAction = ValueOf<typeof CONST.IOU.ACTION>;

export type {Country, IOUAction, IOUType};
export type {Country, IOUAction, IOUType, RateAndUnit};

export default CONST;
5 changes: 5 additions & 0 deletions src/ROUTES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,11 @@ const ROUTES = {
getRoute: (action: IOUAction, iouType: IOUType, transactionID: string, reportID: string, backTo = '') =>
getUrlWithBackToParam(`${action as string}/${iouType as string}/distance/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_DISTANCE_RATE: {
route: ':action/:iouType/distanceRate/:transactionID/:reportID',
getRoute: (action: ValueOf<typeof CONST.IOU.ACTION>, iouType: ValueOf<typeof CONST.IOU.TYPE>, transactionID: string, reportID: string, backTo = '') =>
getUrlWithBackToParam(`${action}/${iouType}/distanceRate/${transactionID}/${reportID}`, backTo),
},
MONEY_REQUEST_STEP_MERCHANT: {
route: ':action/:iouType/merchant/:transactionID/:reportID',
getRoute: (action: IOUAction, iouType: IOUType, transactionID: string, reportID: string, backTo = '') =>
Expand Down
1 change: 1 addition & 0 deletions src/SCREENS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ const SCREENS = {
STEP_DATE: 'Money_Request_Step_Date',
STEP_DESCRIPTION: 'Money_Request_Step_Description',
STEP_DISTANCE: 'Money_Request_Step_Distance',
STEP_DISTANCE_RATE: 'Money_Request_Step_Rate',
STEP_MERCHANT: 'Money_Request_Step_Merchant',
STEP_PARTICIPANTS: 'Money_Request_Step_Participants',
STEP_SCAN: 'Money_Request_Step_Scan',
Expand Down
109 changes: 91 additions & 18 deletions src/components/MoneyRequestConfirmationList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import usePermissions from '@hooks/usePermissions';
import usePrevious from '@hooks/usePrevious';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as CurrencyUtils from '@libs/CurrencyUtils';
import DistanceRequestUtils from '@libs/DistanceRequestUtils';
import type {DefaultMileageRate} from '@libs/DistanceRequestUtils';
import type {MileageRate} from '@libs/DistanceRequestUtils';
import * as IOUUtils from '@libs/IOUUtils';
import Log from '@libs/Log';
import * as MoneyRequestUtils from '@libs/MoneyRequestUtils';
Expand Down Expand Up @@ -65,7 +66,13 @@ type MoneyRequestConfirmationListOnyxProps = {
session: OnyxEntry<OnyxTypes.Session>;

/** Unit and rate used for if the expense is a distance expense */
mileageRate: OnyxEntry<DefaultMileageRate>;
mileageRates: OnyxEntry<Record<string, MileageRate>>;

/** Mileage rate default for the policy */
defaultMileageRate: OnyxEntry<MileageRate>;

/** Last selected distance rates */
lastSelectedDistanceRates: OnyxEntry<Record<string, string>>;
};

type MoneyRequestConfirmationListProps = MoneyRequestConfirmationListOnyxProps & {
Expand Down Expand Up @@ -180,7 +187,7 @@ function MoneyRequestConfirmationList({
isScanRequest = false,
iouAmount,
policyCategories,
mileageRate,
mileageRates,
isDistanceRequest = false,
policy,
isPolicyExpenseChat = false,
Expand Down Expand Up @@ -208,28 +215,50 @@ function MoneyRequestConfirmationList({
onToggleBillable,
hasSmartScanFailed,
reportActionID,
defaultMileageRate,
lastSelectedDistanceRates,
action = CONST.IOU.ACTION.CREATE,
}: MoneyRequestConfirmationListProps) {
const theme = useTheme();
const styles = useThemeStyles();
const {translate, toLocaleDigit} = useLocalize();
const currentUserPersonalDetails = useCurrentUserPersonalDetails();
const {canUseViolations} = usePermissions();
const {canUseP2PDistanceRequests, canUseViolations} = usePermissions(iouType);
const {isOffline} = useNetwork();

const isTypeRequest = iouType === CONST.IOU.TYPE.REQUEST;
const isTypeSplit = iouType === CONST.IOU.TYPE.SPLIT;
const isTypeSend = iouType === CONST.IOU.TYPE.SEND;
const isTypeTrackExpense = iouType === CONST.IOU.TYPE.TRACK_EXPENSE;

const {unit, rate, currency} = mileageRate ?? {
unit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES,
rate: 0,
currency: CONST.CURRENCY.USD,
};
const distance = transaction?.routes?.route0.distance ?? 0;
const shouldCalculateDistanceAmount = isDistanceRequest && iouAmount === 0;
const taxRates = policy?.taxRates;
const transactionID = transaction?.transactionID ?? '';
const customUnitRateID = TransactionUtils.getRateID(transaction) ?? '';

useEffect(() => {
if (customUnitRateID || !canUseP2PDistanceRequests) {
return;
}
if (!customUnitRateID) {
const rateID = lastSelectedDistanceRates?.[policy?.id ?? ''] ?? defaultMileageRate?.customUnitRateID ?? '';
IOU.setCustomUnitRateID(transactionID, rateID);
}
}, [defaultMileageRate, customUnitRateID, lastSelectedDistanceRates, policy?.id, canUseP2PDistanceRequests, transactionID]);

const policyCurrency = policy?.outputCurrency ?? PolicyUtils.getPersonalPolicy()?.outputCurrency ?? CONST.CURRENCY.USD;

const mileageRate = TransactionUtils.isCustomUnitRateIDForP2P(transaction)
? DistanceRequestUtils.getRateForP2P(policyCurrency)
: mileageRates?.[customUnitRateID] ?? DistanceRequestUtils.getDefaultMileageRate(policy);

const {unit, rate} = mileageRate ?? {};

const prevRate = usePrevious(rate);
const shouldCalculateDistanceAmount = isDistanceRequest && (iouAmount === 0 || prevRate !== rate);

const currency = (mileageRate as MileageRate)?.currency ?? policyCurrency;

const distance = transaction?.routes?.route0?.distance ?? 0;
const taxRates = policy?.taxRates ?? null;

// A flag for showing the categories field
const shouldShowCategories = isPolicyExpenseChat && (!!iouCategory || OptionsListUtils.hasEnabledOptions(Object.values(policyCategories ?? {})));
Expand All @@ -255,12 +284,12 @@ function MoneyRequestConfirmationList({
// A flag for showing the billable field
const shouldShowBillable = policy?.disabledFields?.defaultBillable === false;
const isMovingTransactionFromTrackExpense = IOUUtils.isMovingTransactionFromTrackExpense(action);
const hasRoute = TransactionUtils.hasRoute(transaction);
const hasRoute = TransactionUtils.hasRoute(transaction, isDistanceRequest);
const isDistanceRequestWithPendingRoute = isDistanceRequest && (!hasRoute || !rate) && !isMovingTransactionFromTrackExpense;
const formattedAmount = isDistanceRequestWithPendingRoute
? ''
: CurrencyUtils.convertToDisplayString(
shouldCalculateDistanceAmount ? DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate ?? 0) : iouAmount,
shouldCalculateDistanceAmount ? DistanceRequestUtils.getDistanceRequestAmount(distance, unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, rate ?? 0) : iouAmount,
isDistanceRequest ? currency : iouCurrencyCode,
);
const formattedTaxAmount = CurrencyUtils.convertToDisplayString(transaction?.taxAmount, iouCurrencyCode);
Expand Down Expand Up @@ -329,7 +358,7 @@ function MoneyRequestConfirmationList({
return;
}

const amount = DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate ?? 0);
const amount = DistanceRequestUtils.getDistanceRequestAmount(distance, unit ?? CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, rate ?? 0);
IOU.setMoneyRequestAmount(transactionID, amount, currency ?? '');
}, [shouldCalculateDistanceAmount, distance, rate, unit, transactionID, currency]);

Expand Down Expand Up @@ -720,13 +749,50 @@ 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}
/>
),
shouldShow: isDistanceRequest,
isSupplementary: true,
shouldShow: isDistanceRequest && !canUseP2PDistanceRequests,
isSupplementary: false,
},
{
item: (
<MenuItemWithTopDescription
key={translate('common.distance')}
shouldShowRightIcon={!isReadOnly}
title={DistanceRequestUtils.getDistanceForDisplay(hasRoute, distance, unit, rate, translate)}
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()))
}
disabled={didConfirm}
interactive={!isReadOnly}
/>
),
shouldShow: isDistanceRequest && canUseP2PDistanceRequests,
isSupplementary: false,
},
{
item: (
<MenuItemWithTopDescription
key={translate('common.rate')}
shouldShowRightIcon={Boolean(rate) && !isReadOnly && isPolicyExpenseChat}
title={DistanceRequestUtils.getRateForDisplay(unit, rate, currency, translate, toLocaleDigit, isOffline)}
description={translate('common.rate')}
style={[styles.moneyRequestMenuItem]}
titleStyle={styles.flex1}
onPress={() => Navigation.navigate(ROUTES.MONEY_REQUEST_STEP_DISTANCE_RATE.getRoute(action, iouType, transactionID, reportID, Navigation.getActiveRouteWithoutParams()))}
disabled={didConfirm}
interactive={Boolean(rate) && !isReadOnly && isPolicyExpenseChat}
/>
),
shouldShow: isDistanceRequest && canUseP2PDistanceRequests,
isSupplementary: false,
},
{
item: (
Expand Down Expand Up @@ -986,11 +1052,18 @@ export default withOnyx<MoneyRequestConfirmationListProps, MoneyRequestConfirmat
policyTags: {
key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`,
},
mileageRate: {
defaultMileageRate: {
key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
selector: DistanceRequestUtils.getDefaultMileageRate,
},
mileageRates: {
key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
selector: DistanceRequestUtils.getMileageRates,
},
policy: {
key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
},
lastSelectedDistanceRates: {
key: ONYXKEYS.NVP_LAST_SELECTED_DISTANCE_RATES,
},
})(MoneyRequestConfirmationList);
Loading

0 comments on commit cba5f03

Please sign in to comment.