Skip to content

Commit 91b6a3f

Browse files
authored
Merge pull request Expensify#93103 from Krishna2323/krishna/89835-confirmation-rate-selection-ux
feat: update confirmation and rate selection UX for date-aware mileage rates
2 parents 7020187 + c901141 commit 91b6a3f

25 files changed

Lines changed: 96 additions & 9 deletions

File tree

src/CONST/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7759,6 +7759,7 @@ const CONST = {
77597759
MULTI_SCAN_EDUCATIONAL_MODAL: 'multiScanEducationalModal',
77607760
GPS_TOOLTIP: 'gpsTooltip',
77617761
HAS_FILTER_NEGATION: 'hasFilterNegation',
7762+
MILEAGE_RATE_AUTO_UPDATED: 'mileageRateAutoUpdated',
77627763
},
77637764
CHANGE_POLICY_TRAINING_MODAL: 'changePolicyModal',
77647765
AGENTS_RULES_BANNER: 'agentsRulesBanner',

src/components/MoneyRequestConfirmationList.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ function MoneyRequestConfirmationList({
256256
const previousTransactionCurrency = usePrevious(transaction?.currency);
257257
const customUnitRateID = getRateID(transaction);
258258

259+
const shouldShowRateAutoUpdatedTooltip = isDistanceRequest && !!transaction?.comment?.customUnit?.rateAutoUpdated;
260+
259261
const subRates = transaction?.comment?.customUnit?.subRates ?? [];
260262
const prevSubRates = usePrevious(subRates);
261263

@@ -545,7 +547,7 @@ function MoneyRequestConfirmationList({
545547
isPolicyExpenseChat={isPolicyExpenseChat}
546548
expenseMode={{isDistance: isDistanceRequest, isTime: isTimeRequest, isInvoice: isTypeInvoice, isPerDiem: isPerDiemRequest}}
547549
distanceFlags={{isManualDistanceRequest, isOdometerDistanceRequest, isGPSDistanceRequest}}
548-
distanceData={{distance, hasRoute, unit, rate, distanceRateName: mileageRate.name, distanceRateCurrency: currency}}
550+
distanceData={{distance, hasRoute, unit, rate, distanceRateName: mileageRate.name, distanceRateCurrency: currency, shouldShowRateAutoUpdatedTooltip}}
549551
amountDisplay={{amount: amountToBeUsed, formattedAmount, formattedAmountPerAttendee}}
550552
requiredFlags={{isCategoryRequired, isMerchantRequired, isDescriptionRequired}}
551553
visibilityFlags={{

src/components/MoneyRequestConfirmationList/DistanceRequestController.tsx

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,29 @@ function DistanceRequestController({
177177
return;
178178
}
179179

180-
setCustomUnitRateID(transactionID, lastSelectedRate, transaction, policy);
181-
}, [customUnitRateID, transactionID, lastSelectedRate, isDistanceRequest, isPolicyExpenseChat, isMovingTransactionFromTrackExpense, transaction, policy, selectedParticipants]);
180+
let rateToUse = lastSelectedRate;
181+
const expenseDate = transaction?.created;
182+
if (expenseDate) {
183+
const mileageRates = DistanceRequestUtils.getMileageRates(policy);
184+
const lastRate = lastSelectedRate ? mileageRates[lastSelectedRate] : undefined;
185+
if (!lastRate || !DistanceRequestUtils.isRateEligibleForDate(lastRate, expenseDate)) {
186+
const bestRate = DistanceRequestUtils.getBestEligibleRate(mileageRates, expenseDate);
187+
rateToUse = bestRate?.customUnitRateID ?? defaultMileageRateCustomUnitRateID ?? lastSelectedRate;
188+
}
189+
}
190+
setCustomUnitRateID(transactionID, rateToUse, transaction, policy);
191+
}, [
192+
customUnitRateID,
193+
transactionID,
194+
lastSelectedRate,
195+
isDistanceRequest,
196+
isPolicyExpenseChat,
197+
isMovingTransactionFromTrackExpense,
198+
transaction,
199+
policy,
200+
selectedParticipants,
201+
defaultMileageRateCustomUnitRateID,
202+
]);
182203

183204
useEffect(() => {
184205
if (!isDistanceRequest || !transactionID || isReadOnly) {

src/components/MoneyRequestConfirmationList/sections/RateField.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import React from 'react';
22
import type {OnyxEntry} from 'react-native-onyx';
33
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
4+
import {useProductTrainingContext} from '@components/ProductTrainingContext';
45
import {useCurrencyListActions} from '@hooks/useCurrencyList';
56
import useLocalize from '@hooks/useLocalize';
67
import useNetwork from '@hooks/useNetwork';
78
import useThemeStyles from '@hooks/useThemeStyles';
89
import DistanceRequestUtils from '@libs/DistanceRequestUtils';
910
import Navigation from '@libs/Navigation/Navigation';
11+
import variables from '@styles/variables';
1012
import CONST from '@src/CONST';
1113
import type {IOUAction, IOUType} from '@src/CONST';
1214
import ROUTES from '@src/ROUTES';
@@ -30,6 +32,7 @@ type RateFieldProps = {
3032
formError: string;
3133
shouldNavigateToUpgradePath: boolean;
3234
shouldSelectPolicy: boolean;
35+
shouldShowRateAutoUpdatedTooltip?: boolean;
3336
};
3437

3538
function RateField({
@@ -49,6 +52,7 @@ function RateField({
4952
formError,
5053
shouldNavigateToUpgradePath,
5154
shouldSelectPolicy,
55+
shouldShowRateAutoUpdatedTooltip,
5256
}: RateFieldProps) {
5357
const styles = useThemeStyles();
5458
const {translate, toLocaleDigit} = useLocalize();
@@ -59,6 +63,11 @@ function RateField({
5963
const isTrackExpense = iouType === CONST.IOU.TYPE.TRACK;
6064
const isRateInteractive = !!rate && !isReadOnly && iouType !== CONST.IOU.TYPE.SPLIT;
6165

66+
const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip, hideProductTrainingTooltip} = useProductTrainingContext(
67+
CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.MILEAGE_RATE_AUTO_UPDATED,
68+
!!shouldShowRateAutoUpdatedTooltip,
69+
);
70+
6271
return (
6372
<MenuItemWithTopDescription
6473
shouldShowRightIcon={isRateInteractive}
@@ -99,6 +108,14 @@ function RateField({
99108
disabled={didConfirm}
100109
interactive={isRateInteractive}
101110
sentryLabel={CONST.SENTRY_LABEL.REQUEST_CONFIRMATION_LIST.RATE_FIELD}
111+
shouldRenderTooltip={shouldShowProductTrainingTooltip}
112+
renderTooltipContent={renderProductTrainingTooltip}
113+
tooltipWrapperStyle={styles.productTrainingTooltipWrapper}
114+
tooltipAnchorAlignment={{horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM}}
115+
tooltipShiftHorizontal={variables.mileageRateTooltipShiftHorizontal}
116+
tooltipShiftVertical={variables.mileageRateTooltipShiftVertical}
117+
onEducationTooltipPress={hideProductTrainingTooltip}
118+
shouldHideOnScroll
102119
/>
103120
);
104121
}

src/components/MoneyRequestConfirmationListFooter/fieldGroupTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type DistanceData = {
1616
rate: number | undefined;
1717
distanceRateName: string | undefined;
1818
distanceRateCurrency: string;
19+
shouldShowRateAutoUpdatedTooltip?: boolean;
1920
};
2021

2122
/** Distance-mode discriminators (manual / odometer / GPS) */

src/components/MoneyRequestConfirmationListFooter/fieldGroups/TransactionDetailsFields.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ function TransactionDetailsFields({
166166
formError={errorState.formError}
167167
shouldNavigateToUpgradePath={shouldNavigateToUpgradePath}
168168
shouldSelectPolicy={shouldSelectPolicy}
169+
shouldShowRateAutoUpdatedTooltip={distanceData.shouldShowRateAutoUpdatedTooltip}
169170
/>
170171
)}
171172

src/components/ProductTrainingContext/TOOLTIPS.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {dismissProductTraining} from '@libs/actions/Welcome';
33
import CONST from '@src/CONST';
44
import type {TranslationPaths} from '@src/languages/types';
55

6-
const {CONCIERGE_LHN_GBR, RENAME_SAVED_SEARCH, OUTSTANDING_FILTER, ACCOUNT_SWITCHER, SCAN_TEST_DRIVE_CONFIRMATION, GPS_TOOLTIP, HAS_FILTER_NEGATION} = CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;
6+
const {CONCIERGE_LHN_GBR, RENAME_SAVED_SEARCH, OUTSTANDING_FILTER, ACCOUNT_SWITCHER, SCAN_TEST_DRIVE_CONFIRMATION, GPS_TOOLTIP, HAS_FILTER_NEGATION, MILEAGE_RATE_AUTO_UPDATED} =
7+
CONST.PRODUCT_TRAINING_TOOLTIP_NAMES;
78

89
type ProductTrainingTooltipName = Exclude<ValueOf<typeof CONST.PRODUCT_TRAINING_TOOLTIP_NAMES>, typeof CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.MULTI_SCAN_EDUCATIONAL_MODAL>;
910

@@ -75,6 +76,13 @@ const TOOLTIPS: Record<ProductTrainingTooltipName, TooltipData> = {
7576
priority: 1000,
7677
shouldShow: () => true,
7778
},
79+
[MILEAGE_RATE_AUTO_UPDATED]: {
80+
content: 'productTrainingTooltip.mileageRateAutoUpdated',
81+
onHideTooltip: (isDismissedUsingCloseButton = false) => dismissProductTraining(MILEAGE_RATE_AUTO_UPDATED, isDismissedUsingCloseButton),
82+
name: MILEAGE_RATE_AUTO_UPDATED,
83+
priority: 800,
84+
shouldShow: () => true,
85+
},
7886
};
7987

8088
export default TOOLTIPS;

src/components/ProductTrainingContext/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ function ProductTrainingContextProvider({children}: ChildrenProps) {
143143
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_DRIVE_CONFIRMATION &&
144144
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GPS_TOOLTIP &&
145145
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.HAS_FILTER_NEGATION &&
146+
tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.MILEAGE_RATE_AUTO_UPDATED &&
146147
isModalVisible
147148
) {
148149
return false;

src/languages/de.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9547,6 +9547,7 @@ Fügen Sie weitere Ausgabelimits hinzu, um den Cashflow Ihres Unternehmens zu sc
95479547
scanTestDriveTooltip: '<tooltip>Sende diese Quittung, um\n<strong>die Probefahrt abzuschließen!</strong></tooltip>',
95489548
gpsTooltip: '<tooltip>GPS-Tracking läuft! Wenn du fertig bist, stoppe die Aufzeichnung unten.</tooltip>',
95499549
hasFilterNegation: '<tooltip>Suchen Sie nach Ausgaben ohne Belege mit <strong>-has:receipt</strong>.</tooltip>',
9550+
mileageRateAutoUpdated: '<tooltip>Wir haben den Kurs basierend auf Ihrem Reisedatum aktualisiert.</tooltip>',
95509551
},
95519552
discardChangesConfirmation: {
95529553
title: 'Änderungen verwerfen?',

src/languages/en.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9604,6 +9604,7 @@ const translations = {
96049604
scanTestDriveTooltip: '<tooltip>Send this receipt to\n<strong>complete the test drive!</strong></tooltip>',
96059605
gpsTooltip: "<tooltip>GPS tracking in progress! When you're done, stop tracking below.</tooltip>",
96069606
hasFilterNegation: '<tooltip>Search for expenses without receipts using <strong>-has:receipt</strong>.</tooltip>',
9607+
mileageRateAutoUpdated: '<tooltip>We updated the rate based on your travel date.</tooltip>',
96079608
},
96089609
discardChangesConfirmation: {
96099610
title: 'Discard changes?',

0 commit comments

Comments
 (0)