Skip to content

Commit e781005

Browse files
committed
Code cleanup
1 parent 3405ace commit e781005

5 files changed

Lines changed: 117 additions & 94 deletions

File tree

src/libs/GPSDraftDetailsUtils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,8 @@ async function stopGpsTrip(isOffline: boolean, skipLastPointAddressFetching = fa
139139
setEndAddress({value: formattedCoordinates, type: 'coordinates'});
140140
}
141141

142-
export {getGPSRoutes, getGPSWaypoints, stopGpsTrip, getGPSConvertedDistance, getGPSCoordinates, addressFromGpsPoint, coordinatesToString, calculateGPSDistance};
142+
function isTripCaptured(gpsDraftDetails: GpsDraftDetails | undefined): boolean {
143+
return !gpsDraftDetails?.isTracking && (gpsDraftDetails?.gpsPoints?.length ?? 0) > 0;
144+
}
145+
146+
export {getGPSRoutes, getGPSWaypoints, stopGpsTrip, getGPSConvertedDistance, getGPSCoordinates, addressFromGpsPoint, coordinatesToString, calculateGPSDistance, isTripCaptured};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react';
2+
import {useProductTrainingContext} from '@components/ProductTrainingContext';
3+
import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
4+
import useOnyx from '@hooks/useOnyx';
5+
import useThemeStyles from '@hooks/useThemeStyles';
6+
import useWindowDimensions from '@hooks/useWindowDimensions';
7+
import CONST from '@src/CONST';
8+
import ONYXKEYS from '@src/ONYXKEYS';
9+
import {isTrackingSelector} from '@src/selectors/GPSDraftDetails';
10+
11+
const GPS_TOOLTIP_HORIZONTAL_PADDING = 40;
12+
13+
function GPSTooltip({children}: React.PropsWithChildren) {
14+
const [isTracking = false] = useOnyx(ONYXKEYS.GPS_DRAFT_DETAILS, {selector: isTrackingSelector});
15+
16+
const styles = useThemeStyles();
17+
const {windowWidth} = useWindowDimensions();
18+
19+
const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip} = useProductTrainingContext(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GPS_TOOLTIP, !!isTracking);
20+
21+
return (
22+
<EducationalTooltip
23+
wrapperStyle={styles.productTrainingTooltipWrapper}
24+
shiftVertical={-12}
25+
maxWidth={windowWidth - GPS_TOOLTIP_HORIZONTAL_PADDING}
26+
renderTooltipContent={renderProductTrainingTooltip}
27+
shouldRender={shouldShowProductTrainingTooltip}
28+
>
29+
{children}
30+
</EducationalTooltip>
31+
);
32+
}
33+
34+
export default GPSTooltip;

src/pages/iou/request/step/IOURequestStepDistanceGPS/GPSButtons/index.tsx

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@ import useNetwork from '@hooks/useNetwork';
1010
import useOnyx from '@hooks/useOnyx';
1111
import useThemeStyles from '@hooks/useThemeStyles';
1212
import {initGpsDraft, resetGPSDraftDetails} from '@libs/actions/GPSDraftDetails';
13-
import {stopGpsTrip as stopGpsTripUtil} from '@libs/GPSDraftDetailsUtils';
13+
import {isTripCaptured as isTripCapturedUtil, stopGpsTrip as stopGpsTripUtil} from '@libs/GPSDraftDetailsUtils';
1414
import BackgroundLocationPermissionsFlow from '@pages/iou/request/step/IOURequestStepDistanceGPS/BackgroundLocationPermissionsFlow';
1515
import {BACKGROUND_LOCATION_TASK_OPTIONS, BACKGROUND_LOCATION_TRACKING_TASK_NAME} from '@pages/iou/request/step/IOURequestStepDistanceGPS/const';
1616
import {startGpsTripNotification} from '@pages/iou/request/step/IOURequestStepDistanceGPS/GPSNotifications';
1717
import CONST from '@src/CONST';
1818
import ONYXKEYS from '@src/ONYXKEYS';
1919
import type {Unit} from '@src/types/onyx/Policy';
20+
import GPSTooltip from './GPSTooltip';
2021
import openSettings from './openSettings';
2122

2223
type ButtonsProps = {
@@ -53,7 +54,7 @@ function GPSButtons({navigateToNextStep, setShouldShowStartError, setShouldShowP
5354
const styles = useThemeStyles();
5455
const {translate} = useLocalize();
5556

56-
const isTripCaptured = !gpsDraftDetails?.isTracking && (gpsDraftDetails?.gpsPoints?.length ?? 0) > 0;
57+
const isTripCaptured = isTripCapturedUtil(gpsDraftDetails);
5758

5859
const checkSettingsAndPermissions = async () => {
5960
setShouldShowStartError(false);
@@ -125,17 +126,21 @@ function GPSButtons({navigateToNextStep, setShouldShowStartError, setShouldShowP
125126
/>
126127
</View>
127128
) : (
128-
<Button
129-
onPress={gpsDraftDetails?.isTracking ? () => setShowStopConfirmation(true) : checkSettingsAndPermissions}
130-
success={!gpsDraftDetails?.isTracking}
131-
danger={gpsDraftDetails?.isTracking}
132-
allowBubble
133-
pressOnEnter
134-
large
135-
style={[styles.w100, styles.flexShrink0]}
136-
text={gpsDraftDetails?.isTracking ? translate('gps.stop') : translate('gps.start')}
137-
sentryLabel={CONST.SENTRY_LABEL.IOU_REQUEST_STEP.GPS_START_STOP_BUTTON}
138-
/>
129+
<GPSTooltip>
130+
<View>
131+
<Button
132+
onPress={gpsDraftDetails?.isTracking ? () => setShowStopConfirmation(true) : checkSettingsAndPermissions}
133+
success={!gpsDraftDetails?.isTracking}
134+
danger={gpsDraftDetails?.isTracking}
135+
allowBubble
136+
pressOnEnter
137+
large
138+
style={[styles.w100, styles.flexShrink0]}
139+
text={gpsDraftDetails?.isTracking ? translate('gps.stop') : translate('gps.start')}
140+
sentryLabel={CONST.SENTRY_LABEL.IOU_REQUEST_STEP.GPS_START_STOP_BUTTON}
141+
/>
142+
</View>
143+
</GPSTooltip>
139144
)}
140145

141146
<BackgroundLocationPermissionsFlow
Lines changed: 39 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
import React from 'react';
22
import {View} from 'react-native';
33
import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
4-
import {useProductTrainingContext} from '@components/ProductTrainingContext';
54
import ScrollView from '@components/ScrollView';
65
import Text from '@components/Text';
7-
import EducationalTooltip from '@components/Tooltip/EducationalTooltip';
86
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
97
import useLocalize from '@hooks/useLocalize';
108
import useOnyx from '@hooks/useOnyx';
119
import useStyleUtils from '@hooks/useStyleUtils';
1210
import useThemeStyles from '@hooks/useThemeStyles';
13-
import useWindowDimensions from '@hooks/useWindowDimensions';
1411
import DistanceRequestUtils from '@libs/DistanceRequestUtils';
1512
import variables from '@styles/variables';
16-
import CONST from '@src/CONST';
13+
import {isTripCaptured as isTripCapturedUtil} from '@src/libs/GPSDraftDetailsUtils';
1714
import ONYXKEYS from '@src/ONYXKEYS';
18-
import {isTrackingSelector} from '@src/selectors/GPSDraftDetails';
1915
import type {Unit} from '@src/types/onyx/Policy';
2016

2117
type WaypointsProps = {
@@ -34,29 +30,42 @@ function Waypoints({unit, isInLandscapeMode}: WaypointsProps) {
3430

3531
const icons = useMemoizedLazyExpensifyIcons(['Location', 'Crosshair', 'DotIndicatorUnfilled']);
3632

37-
const tripInProgressOrStopped = (gpsDraftDetails?.gpsPoints?.length ?? 0) > 0 || gpsDraftDetails?.isTracking;
33+
// eslint-disable-next-line rulesdir/no-negated-variables
34+
const tripNotInitialized = (gpsDraftDetails?.gpsPoints?.length ?? 0) === 0 && !gpsDraftDetails?.isTracking;
3835

39-
if (!tripInProgressOrStopped) {
36+
if (tripNotInitialized) {
4037
return null;
4138
}
4239

43-
const isTripCaptured = !gpsDraftDetails?.isTracking && (gpsDraftDetails?.gpsPoints?.length ?? 0) > 0;
40+
const isTripCaptured = isTripCapturedUtil(gpsDraftDetails);
4441

4542
const shouldShowLoadingEndAddress = isTripCaptured && !gpsDraftDetails?.endAddress?.value;
46-
const shouldShowLoadingStartAddress = gpsDraftDetails?.isTracking && !gpsDraftDetails?.startAddress?.value;
43+
const shouldShowLoadingStartAddress = !gpsDraftDetails?.startAddress?.value;
4744

4845
const distance = DistanceRequestUtils.convertDistanceUnit(gpsDraftDetails?.distanceInMeters ?? 0, unit).toFixed(1);
4946

5047
const Wrapper = isInLandscapeMode ? ScrollView : View;
5148

49+
const getEndAddressTitle = () => {
50+
if (isTripCaptured) {
51+
return gpsDraftDetails?.endAddress?.value;
52+
}
53+
54+
if (shouldShowLoadingEndAddress) {
55+
return '...';
56+
}
57+
58+
return translate('gps.trackingDistance');
59+
};
60+
5261
return (
5362
<Wrapper style={[styles.pt2, styles.pb4]}>
5463
<MenuItemWithTopDescription
5564
interactive={false}
5665
description={translate('common.distance')}
5766
titleComponent={
5867
<Text style={[styles.iouAmountTextInput, styles.textXLarge, styles.colorMuted, styles.ml3]}>
59-
<Text style={[styles.iouAmountTextInput, styles.textXLarge, !tripInProgressOrStopped && styles.colorMuted]}>{distance}</Text>
68+
<Text style={[styles.iouAmountTextInput, styles.textXLarge]}>{distance}</Text>
6069
{` ${unit}`}
6170
</Text>
6271
}
@@ -65,58 +74,28 @@ function Waypoints({unit, isInLandscapeMode}: WaypointsProps) {
6574
shouldIconUseAutoWidthStyle
6675
descriptionTextStyle={StyleUtils.getFontSizeStyle(variables.fontSizeLabel)}
6776
/>
68-
{(!!gpsDraftDetails?.isTracking || !!gpsDraftDetails?.startAddress?.value) && (
69-
<GPSTooltip>
70-
<View>
71-
<MenuItemWithTopDescription
72-
interactive={false}
73-
description={translate('gps.start')}
74-
shouldShowLoadingSpinnerIcon={shouldShowLoadingStartAddress}
75-
title={shouldShowLoadingStartAddress ? '...' : gpsDraftDetails?.startAddress?.value}
76-
icon={icons.DotIndicatorUnfilled}
77-
style={styles.pv3}
78-
shouldIconUseAutoWidthStyle
79-
/>
80-
</View>
81-
</GPSTooltip>
82-
)}
83-
{isTripCaptured || gpsDraftDetails?.isTracking ? (
84-
<MenuItemWithTopDescription
85-
interactive={false}
86-
description={translate('gps.stop')}
87-
shouldShowLoadingSpinnerIcon={shouldShowLoadingEndAddress}
88-
// eslint-disable-next-line no-nested-ternary
89-
title={gpsDraftDetails?.isTracking ? translate('gps.trackingDistance') : shouldShowLoadingEndAddress ? '...' : gpsDraftDetails?.endAddress?.value}
90-
icon={icons.Location}
91-
style={styles.pv3}
92-
shouldIconUseAutoWidthStyle
93-
/>
94-
) : null}
77+
78+
<MenuItemWithTopDescription
79+
interactive={false}
80+
description={translate('gps.start')}
81+
shouldShowLoadingSpinnerIcon={shouldShowLoadingStartAddress}
82+
title={shouldShowLoadingStartAddress ? '...' : gpsDraftDetails?.startAddress?.value}
83+
icon={icons.DotIndicatorUnfilled}
84+
style={styles.pv3}
85+
shouldIconUseAutoWidthStyle
86+
/>
87+
88+
<MenuItemWithTopDescription
89+
interactive={false}
90+
description={translate('gps.stop')}
91+
shouldShowLoadingSpinnerIcon={shouldShowLoadingEndAddress}
92+
title={getEndAddressTitle()}
93+
icon={icons.Location}
94+
style={styles.pv3}
95+
shouldIconUseAutoWidthStyle
96+
/>
9597
</Wrapper>
9698
);
9799
}
98100

99101
export default Waypoints;
100-
101-
const GPS_TOOLTIP_HORIZONTAL_PADDING = 40;
102-
103-
function GPSTooltip({children}: React.PropsWithChildren) {
104-
const [isTracking = false] = useOnyx(ONYXKEYS.GPS_DRAFT_DETAILS, {selector: isTrackingSelector});
105-
106-
const styles = useThemeStyles();
107-
const {windowWidth} = useWindowDimensions();
108-
109-
const {renderProductTrainingTooltip, shouldShowProductTrainingTooltip} = useProductTrainingContext(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.GPS_TOOLTIP, !!isTracking);
110-
111-
return (
112-
<EducationalTooltip
113-
wrapperStyle={styles.productTrainingTooltipWrapper}
114-
shiftVertical={-12}
115-
maxWidth={windowWidth - GPS_TOOLTIP_HORIZONTAL_PADDING}
116-
renderTooltipContent={renderProductTrainingTooltip}
117-
shouldRender={shouldShowProductTrainingTooltip}
118-
>
119-
{children}
120-
</EducationalTooltip>
121-
);
122-
}

src/pages/iou/request/step/IOURequestStepDistanceGPS/index.native.tsx

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {setGPSTransactionDraftData} from '@libs/actions/IOU';
2626
import {handleMoneyRequestStepDistanceNavigation} from '@libs/actions/IOU/MoneyRequest';
2727
import {init as initMapboxToken, stop as stopMapboxToken} from '@libs/actions/MapboxToken';
2828
import DistanceRequestUtils from '@libs/DistanceRequestUtils';
29-
import {getGPSConvertedDistance, getGPSCoordinates, getGPSWaypoints} from '@libs/GPSDraftDetailsUtils';
29+
import {getGPSConvertedDistance, getGPSCoordinates, getGPSWaypoints, isTripCaptured as isTripCapturedUtil} from '@libs/GPSDraftDetailsUtils';
3030
import Navigation from '@libs/Navigation/Navigation';
3131
import {isPolicyExpenseChat as isPolicyExpenseChatUtils} from '@libs/ReportUtils';
3232
import shouldUseDefaultExpensePolicyUtil from '@libs/shouldUseDefaultExpensePolicy';
@@ -56,9 +56,11 @@ function IOURequestStepDistanceGPS({
5656

5757
const {translate} = useLocalize();
5858
const {isBetaEnabled} = usePermissions();
59-
const expensifyIcons = useMemoizedLazyExpensifyIcons(['DotIndicatorUnfilled', 'Location']);
59+
const {DotIndicatorUnfilled, Location} = useMemoizedLazyExpensifyIcons(['DotIndicatorUnfilled', 'Location']);
6060
const isInLandscapeMode = useIsInLandscapeMode();
6161

62+
const mapRef = useRef<MapViewHandle>(null);
63+
6264
const [lastSelectedDistanceRates] = useOnyx(ONYXKEYS.NVP_LAST_SELECTED_DISTANCE_RATES);
6365
const isArchived = useReportIsArchived(report?.reportID);
6466
const [gpsDraftDetails] = useOnyx(ONYXKEYS.GPS_DRAFT_DETAILS);
@@ -165,7 +167,19 @@ function IOURequestStepDistanceGPS({
165167
return stopMapboxToken;
166168
}, []);
167169

168-
const mapRef = useRef<MapViewHandle>(null);
170+
// Fly to the latest point on location updates when the trip is ongoing
171+
useEffect(() => {
172+
if (!gpsDraftDetails?.isTracking) {
173+
return;
174+
}
175+
const latestPoint = gpsDraftDetails.gpsPoints?.at(-1);
176+
if (!latestPoint) {
177+
return;
178+
}
179+
mapRef.current?.flyTo([latestPoint.long, latestPoint.lat], CONST.MAPBOX.DEFAULT_ZOOM, 1000);
180+
}, [gpsDraftDetails?.gpsPoints, gpsDraftDetails?.isTracking]);
181+
182+
const isTripCaptured = isTripCapturedUtil(gpsDraftDetails);
169183

170184
const getMarkerComponent = (icon: IconAsset): ReactNode => (
171185
<ImageSVG
@@ -176,30 +190,25 @@ function IOURequestStepDistanceGPS({
176190
/>
177191
);
178192

179-
const directionCoordinates: Array<[number, number]> = (gpsDraftDetails?.gpsPoints ?? []).map(({lat, long}) => [long, lat]);
180-
const isTripCaptured = !gpsDraftDetails?.isTracking && (gpsDraftDetails?.gpsPoints?.length ?? 0) > 0;
181-
182193
const getWaypointMarkers = (): WayPoint[] => {
183194
const points = gpsDraftDetails?.gpsPoints ?? [];
184195
const firstPoint = points.at(0);
185196
const lastPoint = points.at(-1);
186197
const markers: WayPoint[] = [];
187198

188199
if (firstPoint) {
189-
const StartIcon = expensifyIcons.DotIndicatorUnfilled;
190200
markers.push({
191201
id: 'gps-start',
192202
coordinate: [firstPoint.long, firstPoint.lat],
193-
markerComponent: (): ReactNode => getMarkerComponent(StartIcon),
203+
markerComponent: (): ReactNode => getMarkerComponent(DotIndicatorUnfilled),
194204
});
195205
}
196206

197207
if (lastPoint && lastPoint !== firstPoint && isTripCaptured) {
198-
const EndIcon = expensifyIcons.Location;
199208
markers.push({
200209
id: 'gps-end',
201210
coordinate: [lastPoint.long, lastPoint.lat],
202-
markerComponent: (): ReactNode => getMarkerComponent(EndIcon),
211+
markerComponent: (): ReactNode => getMarkerComponent(Location),
203212
});
204213
}
205214

@@ -208,17 +217,9 @@ function IOURequestStepDistanceGPS({
208217

209218
const waypointMarkers = getWaypointMarkers();
210219

211-
useEffect(() => {
212-
if (!gpsDraftDetails?.isTracking) {
213-
return;
214-
}
215-
const latestPoint = gpsDraftDetails.gpsPoints?.at(-1);
216-
if (!latestPoint) {
217-
return;
218-
}
219-
mapRef.current?.flyTo([latestPoint.long, latestPoint.lat], CONST.MAPBOX.DEFAULT_ZOOM, 1000);
220-
}, [gpsDraftDetails?.gpsPoints, gpsDraftDetails?.isTracking]);
220+
const directionCoordinates: Array<[number, number]> = (gpsDraftDetails?.gpsPoints ?? []).map(({lat, long}) => [long, lat]);
221221

222+
// Show the full route after stopping the trip
222223
const showFullRouteAfterStopping = () => {
223224
if (directionCoordinates.length < 2) {
224225
return;

0 commit comments

Comments
 (0)