From e8bf7eee21f46d1151d28860fe67ed82f5e57eb3 Mon Sep 17 00:00:00 2001
From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com>
Date: Fri, 22 Dec 2023 23:09:39 +0100
Subject: [PATCH 1/6] Migrate ConfirmedRoute.js component to TypeScript

---
 .../{ConfirmedRoute.js => ConfirmedRoute.tsx} | 72 ++++++++-----------
 .../distanceMapViewPropTypes.js               |  2 +-
 2 files changed, 32 insertions(+), 42 deletions(-)
 rename src/components/{ConfirmedRoute.js => ConfirmedRoute.tsx} (64%)

diff --git a/src/components/ConfirmedRoute.js b/src/components/ConfirmedRoute.tsx
similarity index 64%
rename from src/components/ConfirmedRoute.js
rename to src/components/ConfirmedRoute.tsx
index 3abec6d0d1f4..069235282de9 100644
--- a/src/components/ConfirmedRoute.js
+++ b/src/components/ConfirmedRoute.tsx
@@ -1,9 +1,7 @@
-import lodashGet from 'lodash/get';
-import lodashIsNil from 'lodash/isNil';
-import PropTypes from 'prop-types';
 import React, {useCallback, useEffect} from 'react';
 import {withOnyx} from 'react-native-onyx';
-import _ from 'underscore';
+import {OnyxEntry} from 'react-native-onyx/lib/types';
+import {SvgProps} from 'react-native-svg';
 import useNetwork from '@hooks/useNetwork';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
@@ -11,53 +9,46 @@ import * as TransactionUtils from '@libs/TransactionUtils';
 import * as MapboxToken from '@userActions/MapboxToken';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
+import {MapboxAccessToken, Transaction} from '@src/types/onyx';
+import {WaypointCollection} from '@src/types/onyx/Transaction';
 import DistanceMapView from './DistanceMapView';
 import * as Expensicons from './Icon/Expensicons';
+import {WayPoint} from './MapView/MapViewTypes';
 import PendingMapView from './MapView/PendingMapView';
-import transactionPropTypes from './transactionPropTypes';
-
-const propTypes = {
-    /** Transaction that stores the distance request data */
-    transaction: transactionPropTypes,
 
+type ConfirmedRoutePropsOnyxProps = {
     /** Data about Mapbox token for calling Mapbox API */
-    mapboxAccessToken: PropTypes.shape({
-        /** Temporary token for Mapbox API */
-        token: PropTypes.string,
-
-        /** Time when the token will expire in ISO 8601 */
-        expiration: PropTypes.string,
-    }),
+    mapboxAccessToken: OnyxEntry<MapboxAccessToken>;
 };
 
-const defaultProps = {
-    transaction: {},
-    mapboxAccessToken: {
-        token: '',
-    },
+type ConfirmedRouteProps = {
+    /** Transaction that stores the distance request data */
+    transaction: Transaction;
+    /** Data about Mapbox token for calling Mapbox API */
+    mapboxAccessToken: MapboxAccessToken;
 };
 
-function ConfirmedRoute({mapboxAccessToken, transaction}) {
+function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
     const {isOffline} = useNetwork();
-    const {route0: route} = transaction.routes || {};
-    const waypoints = lodashGet(transaction, 'comment.waypoints', {});
-    const coordinates = lodashGet(route, 'geometry.coordinates', []);
+    const route = transaction.routes?.route0 ?? {geometry: {coordinates: []}};
+    const waypoints = transaction.comment?.waypoints ?? {};
+    const coordinates = route.geometry?.coordinates ?? [];
     const theme = useTheme();
     const styles = useThemeStyles();
 
     const getWaypointMarkers = useCallback(
-        (waypointsData) => {
-            const numberOfWaypoints = _.size(waypointsData);
+        (waypointsData: WaypointCollection): Array<WayPoint | undefined> => {
+            const numberOfWaypoints = Object.keys(waypointsData).length;
             const lastWaypointIndex = numberOfWaypoints - 1;
 
-            return _.filter(
-                _.map(waypointsData, (waypoint, key) => {
-                    if (!waypoint || lodashIsNil(waypoint.lat) || lodashIsNil(waypoint.lng)) {
+            return Object.entries(waypointsData)
+                .map(([key, waypoint]) => {
+                    if (!waypoint?.lat || !waypoint?.lng) {
                         return;
                     }
 
                     const index = TransactionUtils.getWaypointIndex(key);
-                    let MarkerComponent;
+                    let MarkerComponent: React.FC<SvgProps>;
                     if (index === 0) {
                         MarkerComponent = Expensicons.DotIndicatorUnfilled;
                     } else if (index === lastWaypointIndex) {
@@ -68,7 +59,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}) {
 
                     return {
                         id: `${waypoint.lng},${waypoint.lat},${index}`,
-                        coordinate: [waypoint.lng, waypoint.lat],
+                        coordinate: [waypoint.lng, waypoint.lat] as [number, number],
                         markerComponent: () => (
                             <MarkerComponent
                                 width={CONST.MAP_MARKER_SIZE}
@@ -77,9 +68,8 @@ function ConfirmedRoute({mapboxAccessToken, transaction}) {
                             />
                         ),
                     };
-                }),
-                (waypoint) => waypoint,
-            );
+                })
+                .filter((waypoint) => !!waypoint);
         },
         [theme],
     );
@@ -88,19 +78,21 @@ function ConfirmedRoute({mapboxAccessToken, transaction}) {
 
     useEffect(() => {
         MapboxToken.init();
-        return MapboxToken.stop;
+        return () => {
+            MapboxToken.stop();
+        };
     }, []);
 
     return (
         <>
-            {!isOffline && Boolean(mapboxAccessToken.token) ? (
+            {!isOffline && mapboxAccessToken.token ? (
                 <DistanceMapView
                     accessToken={mapboxAccessToken.token}
                     mapPadding={CONST.MAP_PADDING}
                     pitchEnabled={false}
                     initialState={{
                         zoom: CONST.MAPBOX.DEFAULT_ZOOM,
-                        location: lodashGet(waypointMarkers, [0, 'coordinate'], CONST.MAPBOX.DEFAULT_COORDINATE),
+                        location: (waypointMarkers[0]?.coordinate ?? CONST.MAPBOX.DEFAULT_COORDINATE) as number[],
                     }}
                     directionCoordinates={coordinates}
                     style={[styles.mapView, styles.br4]}
@@ -114,12 +106,10 @@ function ConfirmedRoute({mapboxAccessToken, transaction}) {
     );
 }
 
-export default withOnyx({
+export default withOnyx<ConfirmedRouteProps, ConfirmedRoutePropsOnyxProps>({
     mapboxAccessToken: {
         key: ONYXKEYS.MAPBOX_ACCESS_TOKEN,
     },
 })(ConfirmedRoute);
 
 ConfirmedRoute.displayName = 'ConfirmedRoute';
-ConfirmedRoute.propTypes = propTypes;
-ConfirmedRoute.defaultProps = defaultProps;
diff --git a/src/components/DistanceMapView/distanceMapViewPropTypes.js b/src/components/DistanceMapView/distanceMapViewPropTypes.js
index 05068cbc9b34..d2904b2048ff 100644
--- a/src/components/DistanceMapView/distanceMapViewPropTypes.js
+++ b/src/components/DistanceMapView/distanceMapViewPropTypes.js
@@ -27,7 +27,7 @@ const propTypes = {
         PropTypes.shape({
             id: PropTypes.string,
             coordinate: PropTypes.arrayOf(PropTypes.number),
-            markerComponent: PropTypes.oneOfType([PropTypes.element, PropTypes.func]),
+            markerComponent: PropTypes.elementType,
         }),
     ),
 

From 5d67fb4da5eef503ea099ee3b0a456d7f0c43c65 Mon Sep 17 00:00:00 2001
From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com>
Date: Fri, 22 Dec 2023 23:54:36 +0100
Subject: [PATCH 2/6] use ConfirmedRoutePropsOnyxProps in ConfirmedRouteProps

---
 src/components/ConfirmedRoute.tsx | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx
index a7152f0cc0c0..80486cf4f350 100644
--- a/src/components/ConfirmedRoute.tsx
+++ b/src/components/ConfirmedRoute.tsx
@@ -23,11 +23,9 @@ type ConfirmedRoutePropsOnyxProps = {
     mapboxAccessToken: OnyxEntry<MapboxAccessToken>;
 };
 
-type ConfirmedRouteProps = {
+type ConfirmedRouteProps = ConfirmedRoutePropsOnyxProps & {
     /** Transaction that stores the distance request data */
     transaction: Transaction;
-    /** Data about Mapbox token for calling Mapbox API */
-    mapboxAccessToken: MapboxAccessToken;
 };
 
 function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
@@ -88,7 +86,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
 
     return (
         <>
-            {!isOffline && mapboxAccessToken.token ? (
+            {!isOffline && mapboxAccessToken?.token ? (
                 <DistanceMapView
                     accessToken={mapboxAccessToken.token}
                     mapPadding={CONST.MAP_PADDING}

From 99ae663954da107d89243bdc4fd7e7ef2ed9ec5c Mon Sep 17 00:00:00 2001
From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com>
Date: Sat, 23 Dec 2023 00:23:10 +0100
Subject: [PATCH 3/6] correct conditional rendering

---
 src/components/ConfirmedRoute.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx
index 80486cf4f350..77f8560479e3 100644
--- a/src/components/ConfirmedRoute.tsx
+++ b/src/components/ConfirmedRoute.tsx
@@ -86,9 +86,9 @@ function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
 
     return (
         <>
-            {!isOffline && mapboxAccessToken?.token ? (
+            {!isOffline && Boolean(mapboxAccessToken?.token) ? (
                 <DistanceMapView
-                    accessToken={mapboxAccessToken.token}
+                    accessToken={mapboxAccessToken?.token ?? ''}
                     mapPadding={CONST.MAP_PADDING}
                     pitchEnabled={false}
                     initialState={{

From 3ab03e170f2b4e3ff0e19f72e4b609d86bec772d Mon Sep 17 00:00:00 2001
From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com>
Date: Fri, 29 Dec 2023 16:48:34 +0100
Subject: [PATCH 4/6] Address review comments

---
 src/components/ConfirmedRoute.tsx | 30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx
index 77f8560479e3..82ba490b135a 100644
--- a/src/components/ConfirmedRoute.tsx
+++ b/src/components/ConfirmedRoute.tsx
@@ -1,8 +1,6 @@
-import React, {useCallback, useEffect} from 'react';
-import {ImageSourcePropType} from 'react-native';
+import React, {ReactNode, useCallback, useEffect} from 'react';
 import {withOnyx} from 'react-native-onyx';
 import {OnyxEntry} from 'react-native-onyx/lib/types';
-import {SvgProps} from 'react-native-svg';
 import useNetwork from '@hooks/useNetwork';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
@@ -12,12 +10,18 @@ import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
 import {MapboxAccessToken, Transaction} from '@src/types/onyx';
 import {WaypointCollection} from '@src/types/onyx/Transaction';
+import IconAsset from '@src/types/utils/IconAsset';
 import DistanceMapView from './DistanceMapView';
 import * as Expensicons from './Icon/Expensicons';
 import ImageSVG from './ImageSVG';
-import {WayPoint} from './MapView/MapViewTypes';
 import PendingMapView from './MapView/PendingMapView';
 
+type WayPoint = {
+    id: string;
+    coordinate: [number, number];
+    markerComponent: () => ReactNode;
+};
+
 type ConfirmedRoutePropsOnyxProps = {
     /** Data about Mapbox token for calling Mapbox API */
     mapboxAccessToken: OnyxEntry<MapboxAccessToken>;
@@ -30,14 +34,14 @@ type ConfirmedRouteProps = ConfirmedRoutePropsOnyxProps & {
 
 function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
     const {isOffline} = useNetwork();
-    const route = transaction.routes?.route0 ?? {geometry: {coordinates: []}};
+    const {route0: route} = transaction.routes ?? {};
     const waypoints = transaction.comment?.waypoints ?? {};
     const coordinates = route.geometry?.coordinates ?? [];
     const theme = useTheme();
     const styles = useThemeStyles();
 
     const getWaypointMarkers = useCallback(
-        (waypointsData: WaypointCollection): Array<WayPoint | undefined> => {
+        (waypointsData: WaypointCollection): WayPoint[] => {
             const numberOfWaypoints = Object.keys(waypointsData).length;
             const lastWaypointIndex = numberOfWaypoints - 1;
 
@@ -48,7 +52,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
                     }
 
                     const index = TransactionUtils.getWaypointIndex(key);
-                    let MarkerComponent: React.FC<SvgProps> | ImageSourcePropType;
+                    let MarkerComponent: IconAsset;
                     if (index === 0) {
                         MarkerComponent = Expensicons.DotIndicatorUnfilled;
                     } else if (index === lastWaypointIndex) {
@@ -59,8 +63,8 @@ function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
 
                     return {
                         id: `${waypoint.lng},${waypoint.lat},${index}`,
-                        coordinate: [waypoint.lng, waypoint.lat] as [number, number],
-                        markerComponent: () => (
+                        coordinate: [waypoint.lng, waypoint.lat] as const,
+                        markerComponent: (): ReactNode => (
                             <ImageSVG
                                 src={MarkerComponent}
                                 width={CONST.MAP_MARKER_SIZE}
@@ -70,7 +74,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
                         ),
                     };
                 })
-                .filter((waypoint) => !!waypoint);
+                .filter((waypoint): waypoint is WayPoint => !!waypoint);
         },
         [theme],
     );
@@ -79,9 +83,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
 
     useEffect(() => {
         MapboxToken.init();
-        return () => {
-            MapboxToken.stop();
-        };
+        return MapboxToken.stop;
     }, []);
 
     return (
@@ -93,7 +95,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
                     pitchEnabled={false}
                     initialState={{
                         zoom: CONST.MAPBOX.DEFAULT_ZOOM,
-                        location: (waypointMarkers[0]?.coordinate ?? CONST.MAPBOX.DEFAULT_COORDINATE) as number[],
+                        location: waypointMarkers?.[0]?.coordinate ?? (CONST.MAPBOX.DEFAULT_COORDINATE as [number, number]),
                     }}
                     directionCoordinates={coordinates}
                     style={[styles.mapView, styles.br4]}

From 4d49c6562a1d96ba084546d0ec16d8cdab27187b Mon Sep 17 00:00:00 2001
From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com>
Date: Sun, 7 Jan 2024 21:25:10 +0100
Subject: [PATCH 5/6] Fix lint errors

---
 src/components/ConfirmedRoute.tsx | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx
index 82ba490b135a..e4fbfe540cfe 100644
--- a/src/components/ConfirmedRoute.tsx
+++ b/src/components/ConfirmedRoute.tsx
@@ -1,6 +1,6 @@
 import React, {ReactNode, useCallback, useEffect} from 'react';
 import {withOnyx} from 'react-native-onyx';
-import {OnyxEntry} from 'react-native-onyx/lib/types';
+import type {OnyxEntry} from 'react-native-onyx/lib/types';
 import useNetwork from '@hooks/useNetwork';
 import useTheme from '@hooks/useTheme';
 import useThemeStyles from '@hooks/useThemeStyles';
@@ -8,9 +8,9 @@ import * as TransactionUtils from '@libs/TransactionUtils';
 import * as MapboxToken from '@userActions/MapboxToken';
 import CONST from '@src/CONST';
 import ONYXKEYS from '@src/ONYXKEYS';
-import {MapboxAccessToken, Transaction} from '@src/types/onyx';
-import {WaypointCollection} from '@src/types/onyx/Transaction';
-import IconAsset from '@src/types/utils/IconAsset';
+import type {MapboxAccessToken, Transaction} from '@src/types/onyx';
+import type {WaypointCollection} from '@src/types/onyx/Transaction';
+import type IconAsset from '@src/types/utils/IconAsset';
 import DistanceMapView from './DistanceMapView';
 import * as Expensicons from './Icon/Expensicons';
 import ImageSVG from './ImageSVG';
@@ -97,7 +97,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
                         zoom: CONST.MAPBOX.DEFAULT_ZOOM,
                         location: waypointMarkers?.[0]?.coordinate ?? (CONST.MAPBOX.DEFAULT_COORDINATE as [number, number]),
                     }}
-                    directionCoordinates={coordinates}
+                    directionCoordinates={coordinates as [number, number][]}
                     style={[styles.mapView, styles.br4]}
                     waypoints={waypointMarkers}
                     styleURL={CONST.MAPBOX.STYLE_URL}

From ee491d042c12c6747c41cac67623e3d115676189 Mon Sep 17 00:00:00 2001
From: rayane-djouah <77965000+rayane-djouah@users.noreply.github.com>
Date: Sun, 7 Jan 2024 21:33:22 +0100
Subject: [PATCH 6/6] Fix lint errors

---
 src/components/ConfirmedRoute.tsx | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx
index e4fbfe540cfe..05d6557a72e3 100644
--- a/src/components/ConfirmedRoute.tsx
+++ b/src/components/ConfirmedRoute.tsx
@@ -1,4 +1,5 @@
-import React, {ReactNode, useCallback, useEffect} from 'react';
+import React, {useCallback, useEffect} from 'react';
+import type {ReactNode} from 'react';
 import {withOnyx} from 'react-native-onyx';
 import type {OnyxEntry} from 'react-native-onyx/lib/types';
 import useNetwork from '@hooks/useNetwork';
@@ -97,7 +98,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}: ConfirmedRouteProps) {
                         zoom: CONST.MAPBOX.DEFAULT_ZOOM,
                         location: waypointMarkers?.[0]?.coordinate ?? (CONST.MAPBOX.DEFAULT_COORDINATE as [number, number]),
                     }}
-                    directionCoordinates={coordinates as [number, number][]}
+                    directionCoordinates={coordinates as Array<[number, number]>}
                     style={[styles.mapView, styles.br4]}
                     waypoints={waypointMarkers}
                     styleURL={CONST.MAPBOX.STYLE_URL}