From eb48d4087d346eb52649769746cd5733077be065 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Mon, 11 May 2026 13:39:42 +0200 Subject: [PATCH 01/18] Update map markers and route styles --- assets/images/map-current-location.svg | 1 + assets/images/map-start-waypoint.svg | 1 + assets/images/map-stop-waypoint.svg | 1 + assets/images/map-waypoint.svg | 1 + src/CONST/index.ts | 8 +++- src/components/ConfirmedRoute.tsx | 22 +++++---- .../DistanceRequest/DistanceRequestFooter.tsx | 24 +++++----- .../Icon/chunks/expensify-icons.chunk.ts | 8 ++++ src/components/MapView/Direction.tsx | 10 +++++ src/components/MapView/Direction.website.tsx | 16 +++++++ src/components/MapView/MapView.tsx | 45 ++++++------------- .../MapView/MapViewImpl.website.tsx | 9 +++- src/libs/getMapMarkerSize.ts | 10 +++++ .../useGPSWaypointMarkers.tsx | 23 +++++----- src/styles/index.ts | 17 +++++-- 15 files changed, 128 insertions(+), 68 deletions(-) create mode 100644 assets/images/map-current-location.svg create mode 100644 assets/images/map-start-waypoint.svg create mode 100644 assets/images/map-stop-waypoint.svg create mode 100644 assets/images/map-waypoint.svg create mode 100644 src/libs/getMapMarkerSize.ts diff --git a/assets/images/map-current-location.svg b/assets/images/map-current-location.svg new file mode 100644 index 000000000000..4627502dea32 --- /dev/null +++ b/assets/images/map-current-location.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/map-start-waypoint.svg b/assets/images/map-start-waypoint.svg new file mode 100644 index 000000000000..9c5ef76f7899 --- /dev/null +++ b/assets/images/map-start-waypoint.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/map-stop-waypoint.svg b/assets/images/map-stop-waypoint.svg new file mode 100644 index 000000000000..0ce414eab6dd --- /dev/null +++ b/assets/images/map-stop-waypoint.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/map-waypoint.svg b/assets/images/map-waypoint.svg new file mode 100644 index 000000000000..aaca27851f03 --- /dev/null +++ b/assets/images/map-waypoint.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/CONST/index.ts b/src/CONST/index.ts index fe769a750b90..bd5eda1b33c2 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -4858,7 +4858,12 @@ const CONST = { PINK: 'Pink', }, - MAP_MARKER_SIZE: 20, + MAP_MARKER_SIZES: { + CURRENT_LOCATION: {width: 48, height: 48}, + START_WAYPOINT: {width: 48, height: 48}, + STOP_WAYPOINT: {width: 48, height: 53}, + WAYPOINT: {width: 40, height: 40}, + }, QUICK_REACTIONS: [ { @@ -9768,6 +9773,7 @@ const CONST = { USER_LOCATION: 'user-location', ROUTE_SOURCE: 'route-source', ROUTE_FILL: 'route-fill', + ROUTE_BORDER: 'route-border', }, PARTNER_ID: { diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx index cd01342c56a5..861f46e40ffa 100644 --- a/src/components/ConfirmedRoute.tsx +++ b/src/components/ConfirmedRoute.tsx @@ -8,6 +8,7 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import getArrayDepth from '@libs/getArrayDepth'; +import {getMapMarkerSize} from '@libs/getMapMarkerSize'; import {getWaypointIndex} from '@libs/TransactionUtils'; import {init as initMapboxToken, stop as stopMapboxToken} from '@userActions/MapboxToken'; import CONST from '@src/CONST'; @@ -45,16 +46,15 @@ function ConfirmedRoute({transaction, isSmallerIcon, shouldHaveBorderRadius = tr const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const expensifyIcons = useMemoizedLazyExpensifyIcons(['DotIndicator', 'DotIndicatorUnfilled', 'Location']); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); const [mapboxAccessToken] = useOnyx(ONYXKEYS.MAPBOX_ACCESS_TOKEN); - const getMarkerComponent = (icon: IconAsset): ReactNode => ( + const getMarkerComponent = (icon: IconAsset, width: number, height: number): ReactNode => ( ); @@ -67,18 +67,22 @@ function ConfirmedRoute({transaction, isSmallerIcon, shouldHaveBorderRadius = tr const index = getWaypointIndex(key); let MarkerComponent: IconAsset; + let markerSize: {width: number; height: number}; if (index === 0) { - MarkerComponent = expensifyIcons.DotIndicatorUnfilled; + MarkerComponent = expensifyIcons.MapStartWaypoint; + markerSize = getMapMarkerSize('START_WAYPOINT'); } else if (index === lastWaypointIndex) { - MarkerComponent = expensifyIcons.Location; + MarkerComponent = expensifyIcons.MapStopWaypoint; + markerSize = getMapMarkerSize('STOP_WAYPOINT'); } else { - MarkerComponent = expensifyIcons.DotIndicator; + MarkerComponent = expensifyIcons.MapWaypoint; + markerSize = getMapMarkerSize('WAYPOINT'); } waypointMarkers.push({ id: `${waypoint.lng},${waypoint.lat},${index}`, coordinate: [waypoint.lng, waypoint.lat] as const, - markerComponent: (): ReactNode => getMarkerComponent(MarkerComponent), + markerComponent: (): ReactNode => getMarkerComponent(MarkerComponent, markerSize.width, markerSize.height), }); } diff --git a/src/components/DistanceRequest/DistanceRequestFooter.tsx b/src/components/DistanceRequest/DistanceRequestFooter.tsx index 5f57737a8026..e97f78cb9d85 100644 --- a/src/components/DistanceRequest/DistanceRequestFooter.tsx +++ b/src/components/DistanceRequest/DistanceRequestFooter.tsx @@ -11,9 +11,9 @@ import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; -import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; +import {getMapMarkerSize} from '@libs/getMapMarkerSize'; import {getDistanceInMeters, getWaypointIndex, isCustomUnitRateIDForP2P} from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -42,10 +42,9 @@ type DistanceRequestFooterProps = { }; function DistanceRequestFooter({waypoints, transaction, navigateToWaypointEditPage, policy, mapContainerStyle}: DistanceRequestFooterProps) { - const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); - const expensifyIcons = useMemoizedLazyExpensifyIcons(['DotIndicator', 'DotIndicatorUnfilled', 'Location', 'Plus']); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['Plus', 'MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); const [personalPolicyID] = useOnyx(ONYXKEYS.PERSONAL_POLICY_ID); const activePolicy = usePolicy(activePolicyID); @@ -60,12 +59,11 @@ function DistanceRequestFooter({waypoints, transaction, navigateToWaypointEditPa const mileageRate = isCustomUnitRateIDForP2P(transaction) ? DistanceRequestUtils.getRateForP2P(policyCurrency, transaction) : defaultMileageRate; const {unit} = mileageRate ?? {}; - const getMarkerComponent = (icon: IconAsset): ReactNode => ( + const getMarkerComponent = (icon: IconAsset, width: number, height: number): ReactNode => ( ); @@ -77,18 +75,22 @@ function DistanceRequestFooter({waypoints, transaction, navigateToWaypointEditPa const index = getWaypointIndex(key); let MarkerComponent: IconAsset; + let markerSize: {width: number; height: number}; if (index === 0) { - MarkerComponent = expensifyIcons.DotIndicatorUnfilled; + MarkerComponent = expensifyIcons.MapStartWaypoint; + markerSize = getMapMarkerSize('START_WAYPOINT'); } else if (index === lastWaypointIndex) { - MarkerComponent = expensifyIcons.Location; + MarkerComponent = expensifyIcons.MapStopWaypoint; + markerSize = getMapMarkerSize('STOP_WAYPOINT'); } else { - MarkerComponent = expensifyIcons.DotIndicator; + MarkerComponent = expensifyIcons.MapWaypoint; + markerSize = getMapMarkerSize('WAYPOINT'); } waypointMarkers.push({ id: `${waypoint.lng},${waypoint.lat},${index}`, coordinate: [waypoint.lng, waypoint.lat] as const, - markerComponent: (): ReactNode => getMarkerComponent(MarkerComponent), + markerComponent: (): ReactNode => getMarkerComponent(MarkerComponent, markerSize.width, markerSize.height), }); } diff --git a/src/components/Icon/chunks/expensify-icons.chunk.ts b/src/components/Icon/chunks/expensify-icons.chunk.ts index 441af58e797c..0c50228e7097 100644 --- a/src/components/Icon/chunks/expensify-icons.chunk.ts +++ b/src/components/Icon/chunks/expensify-icons.chunk.ts @@ -161,6 +161,10 @@ import MagnifyingGlassSpyMouthClosed from '@assets/images/magnifying-glass-spy-m import MagnifyingGlass from '@assets/images/magnifying-glass.svg'; import Mail from '@assets/images/mail.svg'; import MakeAdmin from '@assets/images/make-admin.svg'; +import MapCurrentLocation from '@assets/images/map-current-location.svg'; +import MapStartWaypoint from '@assets/images/map-start-waypoint.svg'; +import MapStopWaypoint from '@assets/images/map-stop-waypoint.svg'; +import MapWaypoint from '@assets/images/map-waypoint.svg'; import Map from '@assets/images/map.svg'; import Megaphone from '@assets/images/megaphone.svg'; import Menu from '@assets/images/menu.svg'; @@ -390,6 +394,10 @@ const Expensicons = { Mail, MakeAdmin, Map, + MapCurrentLocation, + MapStartWaypoint, + MapStopWaypoint, + MapWaypoint, Menu, Meter, Megaphone, diff --git a/src/components/MapView/Direction.tsx b/src/components/MapView/Direction.tsx index e24635e81115..646109d0314f 100644 --- a/src/components/MapView/Direction.tsx +++ b/src/components/MapView/Direction.tsx @@ -36,6 +36,11 @@ function Direction({coordinates, belowLayerID}: DirectionProps) { id={`${CONST.MAP_VIEW_LAYERS.ROUTE_FILL}-segment-${index}`} style={styles.mapDirection} /> + ))} @@ -63,6 +68,11 @@ function Direction({coordinates, belowLayerID}: DirectionProps) { id={CONST.MAP_VIEW_LAYERS.ROUTE_FILL} style={styles.mapDirection} /> + ); } diff --git a/src/components/MapView/Direction.website.tsx b/src/components/MapView/Direction.website.tsx index 54b0ac041738..45a13a60dfd2 100644 --- a/src/components/MapView/Direction.website.tsx +++ b/src/components/MapView/Direction.website.tsx @@ -14,6 +14,8 @@ function Direction({coordinates}: DirectionProps) { const styles = useThemeStyles(); const layerLayoutStyle: Record = styles.mapDirectionLayer.layout; const layerPointStyle: Record = styles.mapDirectionLayer.paint; + const layerBorderLayoutStyle: Record = styles.mapDirectionLayerBorder.layout; + const layerBorderPointStyle: Record = styles.mapDirectionLayerBorder.paint; if (!utils.isSingleSegmentRoute(coordinates)) { const validSegments = coordinates.filter((segment) => segment.length >= 2); @@ -39,6 +41,13 @@ function Direction({coordinates}: DirectionProps) { }, }} > + + (null); const [isIdle, setIsIdle] = useState(false); const initialLocation = useMemo(() => initialState && {longitude: initialState.location[0], latitude: initialState.location[1]}, [initialState]); @@ -279,31 +279,17 @@ function MapView({ bounds={initBounds} /> {interactive && ( - - - + )} {waypoints?.map(({coordinate, markerComponent, id}) => { const MarkerComponent = markerComponent; @@ -315,23 +301,20 @@ function MapView({ id={id} key={id} coordinate={coordinate} + allowOverlap > ); })} - {!!directionCoordinatesProp && ( - - )} + {!!directionCoordinatesProp && } {!!distanceSymbolCoordinate && !!distanceInMeters && !!distanceUnit && ( (null); const initialLocation = useMemo(() => ({longitude: initialState.location[0], latitude: initialState.location[1]}), [initialState]); @@ -274,7 +275,11 @@ function MapViewImpl({ longitude={currentPosition?.longitude ?? 0} latitude={currentPosition?.latitude ?? 0} > - + )} {!!distanceSymbolCoordinate && !!distanceInMeters && !!distanceUnit && ( diff --git a/src/libs/getMapMarkerSize.ts b/src/libs/getMapMarkerSize.ts new file mode 100644 index 000000000000..0aa5f0dff67f --- /dev/null +++ b/src/libs/getMapMarkerSize.ts @@ -0,0 +1,10 @@ +import CONST from '@src/CONST'; + +type MapMarkerType = keyof typeof CONST.MAP_MARKER_SIZES; + +function getMapMarkerSize(markerType: MapMarkerType): {width: number; height: number} { + return CONST.MAP_MARKER_SIZES[markerType]; +} + +export {getMapMarkerSize}; +export type {MapMarkerType}; diff --git a/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx b/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx index 6d919e09b1a6..7c63e435bdff 100644 --- a/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx +++ b/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx @@ -4,26 +4,24 @@ import ImageSVG from '@components/ImageSVG'; import type {WayPoint} from '@components/MapView/MapViewTypes'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useOnyx from '@hooks/useOnyx'; -import useTheme from '@hooks/useTheme'; +import {getMapMarkerSize} from '@libs/getMapMarkerSize'; import {getGPSWaypoints, isTripStopped as isTripStoppedUtil} from '@libs/GPSDraftDetailsUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type IconAsset from '@src/types/utils/IconAsset'; function useGPSWaypointMarkers(): WayPoint[] { - const theme = useTheme(); - const {DotIndicatorUnfilled, Location, DotIndicator} = useMemoizedLazyExpensifyIcons(['DotIndicatorUnfilled', 'Location', 'DotIndicator']); + const {MapStartWaypoint, MapStopWaypoint, MapWaypoint} = useMemoizedLazyExpensifyIcons(['MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); const [gpsDraftDetails] = useOnyx(ONYXKEYS.GPS_DRAFT_DETAILS); const isTripStopped = isTripStoppedUtil(gpsDraftDetails); - const getMarkerComponent = (icon: IconAsset): ReactNode => ( + const getMarkerComponent = (icon: IconAsset, width: number, height: number): ReactNode => ( ); @@ -39,18 +37,21 @@ function useGPSWaypointMarkers(): WayPoint[] { return []; } - let icon = DotIndicator; + let icon = MapWaypoint; + let markerSize = getMapMarkerSize('WAYPOINT'); if (isStart) { - icon = DotIndicatorUnfilled; + icon = MapStartWaypoint; + markerSize = getMapMarkerSize('START_WAYPOINT'); } else if (isEnd) { - icon = Location; + icon = MapStopWaypoint; + markerSize = getMapMarkerSize('STOP_WAYPOINT'); } return [ { id: key, coordinate: [waypoint.lng, waypoint.lat], - markerComponent: (): ReactNode => getMarkerComponent(icon), + markerComponent: (): ReactNode => getMarkerComponent(icon, markerSize.width, markerSize.height), }, ]; }); diff --git a/src/styles/index.ts b/src/styles/index.ts index acabe0c39d15..10ec977d7402 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -6544,14 +6544,25 @@ const plainStyles = (theme: ThemeColors) => }, }) satisfies CustomPickerStyle, mapDirection: { - lineColor: theme.success, - lineWidth: 7, + lineColor: colors.green400, + lineWidth: 6, + lineCap: 'round', + }, + + mapDirectionBorder: { + lineColor: colors.green600, + lineWidth: 8, lineCap: 'round', }, mapDirectionLayer: { layout: {'line-join': 'round', 'line-cap': 'round'}, - paint: {'line-color': theme.success, 'line-width': 7}, + paint: {'line-color': colors.green400, 'line-width': 6}, + }, + + mapDirectionLayerBorder: { + layout: {'line-join': 'round', 'line-cap': 'round'}, + paint: {'line-color': colors.green600, 'line-width': 8}, }, searchTopBarZIndexStyle: { zIndex: variables.searchTopBarZIndex, From 1cf7444487a03fa2ae20d986e389985157d5b474 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Mon, 11 May 2026 13:52:09 +0200 Subject: [PATCH 02/18] Remove useTheme() that is not used --- src/components/ConfirmedRoute.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx index 861f46e40ffa..1a10b32243f9 100644 --- a/src/components/ConfirmedRoute.tsx +++ b/src/components/ConfirmedRoute.tsx @@ -5,7 +5,6 @@ import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; -import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import getArrayDepth from '@libs/getArrayDepth'; import {getMapMarkerSize} from '@libs/getMapMarkerSize'; @@ -43,7 +42,6 @@ function ConfirmedRoute({transaction, isSmallerIcon, shouldHaveBorderRadius = tr const {route0: route} = transaction?.routes ?? {}; const waypoints = transaction?.comment?.waypoints ?? {}; const coordinates = route?.geometry?.coordinates ?? []; - const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const expensifyIcons = useMemoizedLazyExpensifyIcons(['MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); From 1b8e5d6739bede84bcc042a77a1f1f2af1b23c9b Mon Sep 17 00:00:00 2001 From: GCyganek Date: Mon, 11 May 2026 14:32:22 +0200 Subject: [PATCH 03/18] Fix ESlint --- .../step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx b/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx index 7c63e435bdff..b192884e0cf0 100644 --- a/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx +++ b/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx @@ -6,7 +6,6 @@ import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useOnyx from '@hooks/useOnyx'; import {getMapMarkerSize} from '@libs/getMapMarkerSize'; import {getGPSWaypoints, isTripStopped as isTripStoppedUtil} from '@libs/GPSDraftDetailsUtils'; -import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type IconAsset from '@src/types/utils/IconAsset'; From e0254ee8dc3f4afc9b13251535d2d5024c1c4dea Mon Sep 17 00:00:00 2001 From: GCyganek Date: Thu, 14 May 2026 13:29:28 +0200 Subject: [PATCH 04/18] Use React components to support drop shadow for map icons --- .../Icon/chunks/expensify-icons.chunk.ts | 7 ++- .../MapView/Icons/MapCurrentLocation.tsx | 47 +++++++++++++++++ .../MapView/Icons/MapStartWaypoint.tsx | 47 +++++++++++++++++ .../MapView/Icons/MapStopWaypoint.tsx | 51 +++++++++++++++++++ src/components/MapView/Icons/MapWaypoint.tsx | 42 +++++++++++++++ 5 files changed, 190 insertions(+), 4 deletions(-) create mode 100644 src/components/MapView/Icons/MapCurrentLocation.tsx create mode 100644 src/components/MapView/Icons/MapStartWaypoint.tsx create mode 100644 src/components/MapView/Icons/MapStopWaypoint.tsx create mode 100644 src/components/MapView/Icons/MapWaypoint.tsx diff --git a/src/components/Icon/chunks/expensify-icons.chunk.ts b/src/components/Icon/chunks/expensify-icons.chunk.ts index 0c50228e7097..b15d58ab79ce 100644 --- a/src/components/Icon/chunks/expensify-icons.chunk.ts +++ b/src/components/Icon/chunks/expensify-icons.chunk.ts @@ -161,10 +161,6 @@ import MagnifyingGlassSpyMouthClosed from '@assets/images/magnifying-glass-spy-m import MagnifyingGlass from '@assets/images/magnifying-glass.svg'; import Mail from '@assets/images/mail.svg'; import MakeAdmin from '@assets/images/make-admin.svg'; -import MapCurrentLocation from '@assets/images/map-current-location.svg'; -import MapStartWaypoint from '@assets/images/map-start-waypoint.svg'; -import MapStopWaypoint from '@assets/images/map-stop-waypoint.svg'; -import MapWaypoint from '@assets/images/map-waypoint.svg'; import Map from '@assets/images/map.svg'; import Megaphone from '@assets/images/megaphone.svg'; import Menu from '@assets/images/menu.svg'; @@ -265,6 +261,9 @@ import Workflows from '@assets/images/workflows.svg'; import Workspace from '@assets/images/workspace-default-avatar.svg'; import Clear from '@assets/images/x-circle.svg'; import Zoom from '@assets/images/zoom.svg'; +import MapStartWaypoint from '@components/MapView/Icons/MapStartWaypoint'; +import MapStopWaypoint from '@components/MapView/Icons/MapStopWaypoint'; +import MapWaypoint from '@components/MapView/Icons/MapWaypoint'; const Expensicons = { ReceiptBody, diff --git a/src/components/MapView/Icons/MapCurrentLocation.tsx b/src/components/MapView/Icons/MapCurrentLocation.tsx new file mode 100644 index 000000000000..86819a3f6075 --- /dev/null +++ b/src/components/MapView/Icons/MapCurrentLocation.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import {Defs, FeDropShadow, Filter, G, Path, Svg} from 'react-native-svg'; +import type {SvgProps} from 'react-native-svg'; + +function MapCurrentLocation({width = 48, height = 48}: SvgProps) { + return ( + + + + + + + + + + + + ); +} + +export default MapCurrentLocation; diff --git a/src/components/MapView/Icons/MapStartWaypoint.tsx b/src/components/MapView/Icons/MapStartWaypoint.tsx new file mode 100644 index 000000000000..76e7eb178f14 --- /dev/null +++ b/src/components/MapView/Icons/MapStartWaypoint.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import {Defs, FeDropShadow, Filter, G, Path, Svg} from 'react-native-svg'; +import type {SvgProps} from 'react-native-svg'; + +function MapStartWaypoint({width = 48, height = 48}: SvgProps) { + return ( + + + + + + + + + + + + ); +} + +export default MapStartWaypoint; diff --git a/src/components/MapView/Icons/MapStopWaypoint.tsx b/src/components/MapView/Icons/MapStopWaypoint.tsx new file mode 100644 index 000000000000..ffd56955d10d --- /dev/null +++ b/src/components/MapView/Icons/MapStopWaypoint.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import {Defs, FeDropShadow, Filter, G, Path, Svg} from 'react-native-svg'; +import type {SvgProps} from 'react-native-svg'; + +function MapStopWaypoint({width = 48, height = 53}: SvgProps) { + return ( + + + + + + + + + + + + + ); +} + +export default MapStopWaypoint; diff --git a/src/components/MapView/Icons/MapWaypoint.tsx b/src/components/MapView/Icons/MapWaypoint.tsx new file mode 100644 index 000000000000..d03121e3b200 --- /dev/null +++ b/src/components/MapView/Icons/MapWaypoint.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import {Circle, Defs, FeDropShadow, Filter, Svg} from 'react-native-svg'; +import type {SvgProps} from 'react-native-svg'; + +function MapWaypoint({width = 40, height = 40}: SvgProps) { + return ( + + + + + + + + + ); +} + +export default MapWaypoint; From cedd7a4f8ff3545464c7d38851a3d198f8d4d0d1 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Thu, 14 May 2026 13:39:33 +0200 Subject: [PATCH 05/18] MapCurrentLocation import --- src/components/Icon/chunks/expensify-icons.chunk.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/Icon/chunks/expensify-icons.chunk.ts b/src/components/Icon/chunks/expensify-icons.chunk.ts index b15d58ab79ce..ae7fb21eb108 100644 --- a/src/components/Icon/chunks/expensify-icons.chunk.ts +++ b/src/components/Icon/chunks/expensify-icons.chunk.ts @@ -261,6 +261,7 @@ import Workflows from '@assets/images/workflows.svg'; import Workspace from '@assets/images/workspace-default-avatar.svg'; import Clear from '@assets/images/x-circle.svg'; import Zoom from '@assets/images/zoom.svg'; +import MapCurrentLocation from '@components/MapView/Icons/MapCurrentLocation'; import MapStartWaypoint from '@components/MapView/Icons/MapStartWaypoint'; import MapStopWaypoint from '@components/MapView/Icons/MapStopWaypoint'; import MapWaypoint from '@components/MapView/Icons/MapWaypoint'; From bbc71da6baa63c81fd239edb03ca604ce1421b45 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Thu, 14 May 2026 13:46:35 +0200 Subject: [PATCH 06/18] Add comment and delete svgs --- assets/images/map-current-location.svg | 1 - assets/images/map-start-waypoint.svg | 1 - assets/images/map-stop-waypoint.svg | 1 - assets/images/map-waypoint.svg | 1 - src/components/Icon/chunks/expensify-icons.chunk.ts | 1 + 5 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 assets/images/map-current-location.svg delete mode 100644 assets/images/map-start-waypoint.svg delete mode 100644 assets/images/map-stop-waypoint.svg delete mode 100644 assets/images/map-waypoint.svg diff --git a/assets/images/map-current-location.svg b/assets/images/map-current-location.svg deleted file mode 100644 index 4627502dea32..000000000000 --- a/assets/images/map-current-location.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/images/map-start-waypoint.svg b/assets/images/map-start-waypoint.svg deleted file mode 100644 index 9c5ef76f7899..000000000000 --- a/assets/images/map-start-waypoint.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/images/map-stop-waypoint.svg b/assets/images/map-stop-waypoint.svg deleted file mode 100644 index 0ce414eab6dd..000000000000 --- a/assets/images/map-stop-waypoint.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/images/map-waypoint.svg b/assets/images/map-waypoint.svg deleted file mode 100644 index aaca27851f03..000000000000 --- a/assets/images/map-waypoint.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/Icon/chunks/expensify-icons.chunk.ts b/src/components/Icon/chunks/expensify-icons.chunk.ts index ae7fb21eb108..3a0d16dcdd27 100644 --- a/src/components/Icon/chunks/expensify-icons.chunk.ts +++ b/src/components/Icon/chunks/expensify-icons.chunk.ts @@ -261,6 +261,7 @@ import Workflows from '@assets/images/workflows.svg'; import Workspace from '@assets/images/workspace-default-avatar.svg'; import Clear from '@assets/images/x-circle.svg'; import Zoom from '@assets/images/zoom.svg'; +// These icons are React components because they have drop shadow that is handled by @svgr/babel-plugin-transform-react-native-svg import MapCurrentLocation from '@components/MapView/Icons/MapCurrentLocation'; import MapStartWaypoint from '@components/MapView/Icons/MapStartWaypoint'; import MapStopWaypoint from '@components/MapView/Icons/MapStopWaypoint'; From 0e37fbf9fe7b5f6560b6f172032700b571afed2a Mon Sep 17 00:00:00 2001 From: GCyganek Date: Thu, 14 May 2026 14:20:06 +0200 Subject: [PATCH 07/18] Restore original floodOpacity --- src/components/MapView/Icons/MapCurrentLocation.tsx | 2 +- src/components/MapView/Icons/MapStartWaypoint.tsx | 2 +- src/components/MapView/Icons/MapStopWaypoint.tsx | 2 +- src/components/MapView/Icons/MapWaypoint.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/MapView/Icons/MapCurrentLocation.tsx b/src/components/MapView/Icons/MapCurrentLocation.tsx index 86819a3f6075..58333c344909 100644 --- a/src/components/MapView/Icons/MapCurrentLocation.tsx +++ b/src/components/MapView/Icons/MapCurrentLocation.tsx @@ -24,7 +24,7 @@ function MapCurrentLocation({width = 48, height = 48}: SvgProps) { dy={4} stdDeviation={6} floodColor="#021204" - floodOpacity={0.8} + floodOpacity={0.06} /> diff --git a/src/components/MapView/Icons/MapStartWaypoint.tsx b/src/components/MapView/Icons/MapStartWaypoint.tsx index 76e7eb178f14..742d19238397 100644 --- a/src/components/MapView/Icons/MapStartWaypoint.tsx +++ b/src/components/MapView/Icons/MapStartWaypoint.tsx @@ -24,7 +24,7 @@ function MapStartWaypoint({width = 48, height = 48}: SvgProps) { dy={4} stdDeviation={6} floodColor="#021204" - floodOpacity={0.8} + floodOpacity={0.06} /> diff --git a/src/components/MapView/Icons/MapStopWaypoint.tsx b/src/components/MapView/Icons/MapStopWaypoint.tsx index ffd56955d10d..fc5e56f650e6 100644 --- a/src/components/MapView/Icons/MapStopWaypoint.tsx +++ b/src/components/MapView/Icons/MapStopWaypoint.tsx @@ -24,7 +24,7 @@ function MapStopWaypoint({width = 48, height = 53}: SvgProps) { dy={4} stdDeviation={6} floodColor="#021204" - floodOpacity={0.8} + floodOpacity={0.06} /> diff --git a/src/components/MapView/Icons/MapWaypoint.tsx b/src/components/MapView/Icons/MapWaypoint.tsx index d03121e3b200..add145b503b0 100644 --- a/src/components/MapView/Icons/MapWaypoint.tsx +++ b/src/components/MapView/Icons/MapWaypoint.tsx @@ -24,7 +24,7 @@ function MapWaypoint({width = 40, height = 40}: SvgProps) { dy={4} stdDeviation={6} floodColor="#021204" - floodOpacity={0.8} + floodOpacity={0.06} /> From 6d5c114658ed76997f73625e837ed91f658cffc3 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Thu, 14 May 2026 16:13:41 +0200 Subject: [PATCH 08/18] useMapMarkers --- src/components/ConfirmedRoute.tsx | 30 +++---------- .../DistanceRequest/DistanceRequestFooter.tsx | 30 ++++--------- src/hooks/useMapMarkers.tsx | 43 +++++++++++++++++++ src/libs/getMapMarkerSize.ts | 10 ----- .../useGPSWaypointMarkers.tsx | 28 +++--------- 5 files changed, 65 insertions(+), 76 deletions(-) create mode 100644 src/hooks/useMapMarkers.tsx delete mode 100644 src/libs/getMapMarkerSize.ts diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx index 1a10b32243f9..8710d809725f 100644 --- a/src/components/ConfirmedRoute.tsx +++ b/src/components/ConfirmedRoute.tsx @@ -1,21 +1,19 @@ import React, {useEffect} from 'react'; import type {ReactNode} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; -import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; +import useMapMarkers from '@hooks/useMapMarkers'; +import type {MapMarkerType} from '@hooks/useMapMarkers'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import getArrayDepth from '@libs/getArrayDepth'; -import {getMapMarkerSize} from '@libs/getMapMarkerSize'; import {getWaypointIndex} from '@libs/TransactionUtils'; import {init as initMapboxToken, stop as stopMapboxToken} from '@userActions/MapboxToken'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Transaction} from '@src/types/onyx'; -import type IconAsset from '@src/types/utils/IconAsset'; import DistanceMapView from './DistanceMapView'; -import ImageSVG from './ImageSVG'; import type {WayPoint} from './MapView/MapViewTypes'; import PendingMapView from './MapView/PendingMapView'; @@ -44,18 +42,10 @@ function ConfirmedRoute({transaction, isSmallerIcon, shouldHaveBorderRadius = tr const coordinates = route?.geometry?.coordinates ?? []; const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); - const expensifyIcons = useMemoizedLazyExpensifyIcons(['MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); + const getMapMarkerIconComponent = useMapMarkers(); const [mapboxAccessToken] = useOnyx(ONYXKEYS.MAPBOX_ACCESS_TOKEN); - const getMarkerComponent = (icon: IconAsset, width: number, height: number): ReactNode => ( - - ); - const lastWaypointIndex = Object.keys(waypoints).length - 1; const waypointMarkers: WayPoint[] = []; for (const [key, waypoint] of Object.entries(waypoints)) { @@ -64,23 +54,17 @@ function ConfirmedRoute({transaction, isSmallerIcon, shouldHaveBorderRadius = tr } const index = getWaypointIndex(key); - let MarkerComponent: IconAsset; - let markerSize: {width: number; height: number}; + let markerType: MapMarkerType = 'WAYPOINT'; if (index === 0) { - MarkerComponent = expensifyIcons.MapStartWaypoint; - markerSize = getMapMarkerSize('START_WAYPOINT'); + markerType = 'START_WAYPOINT'; } else if (index === lastWaypointIndex) { - MarkerComponent = expensifyIcons.MapStopWaypoint; - markerSize = getMapMarkerSize('STOP_WAYPOINT'); - } else { - MarkerComponent = expensifyIcons.MapWaypoint; - markerSize = getMapMarkerSize('WAYPOINT'); + markerType = 'STOP_WAYPOINT'; } waypointMarkers.push({ id: `${waypoint.lng},${waypoint.lat},${index}`, coordinate: [waypoint.lng, waypoint.lat] as const, - markerComponent: (): ReactNode => getMarkerComponent(MarkerComponent, markerSize.width, markerSize.height), + markerComponent: (): ReactNode => getMapMarkerIconComponent(markerType), }); } diff --git a/src/components/DistanceRequest/DistanceRequestFooter.tsx b/src/components/DistanceRequest/DistanceRequestFooter.tsx index e97f78cb9d85..04982e65f1d3 100644 --- a/src/components/DistanceRequest/DistanceRequestFooter.tsx +++ b/src/components/DistanceRequest/DistanceRequestFooter.tsx @@ -5,22 +5,21 @@ import type {StyleProp, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import Button from '@components/Button'; import DistanceMapView from '@components/DistanceMapView'; -import ImageSVG from '@components/ImageSVG'; import type {WayPoint} from '@components/MapView/MapViewTypes'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; +import useMapMarkers from '@hooks/useMapMarkers'; +import type {MapMarkerType} from '@hooks/useMapMarkers'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; import DistanceRequestUtils from '@libs/DistanceRequestUtils'; -import {getMapMarkerSize} from '@libs/getMapMarkerSize'; import {getDistanceInMeters, getWaypointIndex, isCustomUnitRateIDForP2P} from '@libs/TransactionUtils'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy} from '@src/types/onyx'; import type {WaypointCollection} from '@src/types/onyx/Transaction'; import type Transaction from '@src/types/onyx/Transaction'; -import type IconAsset from '@src/types/utils/IconAsset'; const MAX_WAYPOINTS = 25; @@ -44,7 +43,8 @@ type DistanceRequestFooterProps = { function DistanceRequestFooter({waypoints, transaction, navigateToWaypointEditPage, policy, mapContainerStyle}: DistanceRequestFooterProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const expensifyIcons = useMemoizedLazyExpensifyIcons(['Plus', 'MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['Plus']); + const getMapMarkerIconComponent = useMapMarkers(); const [activePolicyID] = useOnyx(ONYXKEYS.NVP_ACTIVE_POLICY_ID); const [personalPolicyID] = useOnyx(ONYXKEYS.PERSONAL_POLICY_ID); const activePolicy = usePolicy(activePolicyID); @@ -59,14 +59,6 @@ function DistanceRequestFooter({waypoints, transaction, navigateToWaypointEditPa const mileageRate = isCustomUnitRateIDForP2P(transaction) ? DistanceRequestUtils.getRateForP2P(policyCurrency, transaction) : defaultMileageRate; const {unit} = mileageRate ?? {}; - const getMarkerComponent = (icon: IconAsset, width: number, height: number): ReactNode => ( - - ); - const waypointMarkers: WayPoint[] = []; for (const [key, waypoint] of Object.entries(waypoints ?? {})) { if (!waypoint?.lat || !waypoint?.lng) { @@ -74,23 +66,17 @@ function DistanceRequestFooter({waypoints, transaction, navigateToWaypointEditPa } const index = getWaypointIndex(key); - let MarkerComponent: IconAsset; - let markerSize: {width: number; height: number}; + let markerType: MapMarkerType = 'WAYPOINT'; if (index === 0) { - MarkerComponent = expensifyIcons.MapStartWaypoint; - markerSize = getMapMarkerSize('START_WAYPOINT'); + markerType = 'START_WAYPOINT'; } else if (index === lastWaypointIndex) { - MarkerComponent = expensifyIcons.MapStopWaypoint; - markerSize = getMapMarkerSize('STOP_WAYPOINT'); - } else { - MarkerComponent = expensifyIcons.MapWaypoint; - markerSize = getMapMarkerSize('WAYPOINT'); + markerType = 'STOP_WAYPOINT'; } waypointMarkers.push({ id: `${waypoint.lng},${waypoint.lat},${index}`, coordinate: [waypoint.lng, waypoint.lat] as const, - markerComponent: (): ReactNode => getMarkerComponent(MarkerComponent, markerSize.width, markerSize.height), + markerComponent: (): ReactNode => getMapMarkerIconComponent(markerType), }); } diff --git a/src/hooks/useMapMarkers.tsx b/src/hooks/useMapMarkers.tsx new file mode 100644 index 000000000000..bde5c65c84de --- /dev/null +++ b/src/hooks/useMapMarkers.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import type {ReactNode} from 'react'; +import ImageSVG from '@components/ImageSVG'; +import CONST from '@src/CONST'; +import type IconAsset from '@src/types/utils/IconAsset'; +import {useMemoizedLazyExpensifyIcons} from './useLazyAsset'; + +type MapMarkerType = Exclude; + +function getMapMarkerSize(markerType: MapMarkerType): {width: number; height: number} { + return CONST.MAP_MARKER_SIZES[markerType]; +} + +function useMapMarkers() { + const expensifyIcons = useMemoizedLazyExpensifyIcons(['MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); + + const getMapMarkerIconAsset = (markerType: MapMarkerType): IconAsset => { + switch (markerType) { + case 'START_WAYPOINT': + return expensifyIcons.MapStartWaypoint; + case 'STOP_WAYPOINT': + return expensifyIcons.MapStopWaypoint; + default: + return expensifyIcons.MapWaypoint; + } + }; + + const getMapMarkerIconComponent = (markerType: MapMarkerType): ReactNode => { + const size = getMapMarkerSize(markerType); + return ( + + ); + }; + + return getMapMarkerIconComponent; +} + +export type {MapMarkerType}; +export default useMapMarkers; diff --git a/src/libs/getMapMarkerSize.ts b/src/libs/getMapMarkerSize.ts deleted file mode 100644 index 0aa5f0dff67f..000000000000 --- a/src/libs/getMapMarkerSize.ts +++ /dev/null @@ -1,10 +0,0 @@ -import CONST from '@src/CONST'; - -type MapMarkerType = keyof typeof CONST.MAP_MARKER_SIZES; - -function getMapMarkerSize(markerType: MapMarkerType): {width: number; height: number} { - return CONST.MAP_MARKER_SIZES[markerType]; -} - -export {getMapMarkerSize}; -export type {MapMarkerType}; diff --git a/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx b/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx index b192884e0cf0..fcca01565a87 100644 --- a/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx +++ b/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx @@ -1,29 +1,18 @@ -import React from 'react'; import type {ReactNode} from 'react'; -import ImageSVG from '@components/ImageSVG'; import type {WayPoint} from '@components/MapView/MapViewTypes'; -import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; +import type {MapMarkerType} from '@hooks/useMapMarkers'; +import useMapMarkers from '@hooks/useMapMarkers'; import useOnyx from '@hooks/useOnyx'; -import {getMapMarkerSize} from '@libs/getMapMarkerSize'; import {getGPSWaypoints, isTripStopped as isTripStoppedUtil} from '@libs/GPSDraftDetailsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; -import type IconAsset from '@src/types/utils/IconAsset'; function useGPSWaypointMarkers(): WayPoint[] { - const {MapStartWaypoint, MapStopWaypoint, MapWaypoint} = useMemoizedLazyExpensifyIcons(['MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); + const getMapMarkerIconComponent = useMapMarkers(); const [gpsDraftDetails] = useOnyx(ONYXKEYS.GPS_DRAFT_DETAILS); const isTripStopped = isTripStoppedUtil(gpsDraftDetails); - const getMarkerComponent = (icon: IconAsset, width: number, height: number): ReactNode => ( - - ); - const gpsWaypoints = getGPSWaypoints(gpsDraftDetails); const waypointEntries = Object.entries(gpsWaypoints); const lastIndex = waypointEntries.length - 1; @@ -36,21 +25,18 @@ function useGPSWaypointMarkers(): WayPoint[] { return []; } - let icon = MapWaypoint; - let markerSize = getMapMarkerSize('WAYPOINT'); + let markerType: MapMarkerType = 'WAYPOINT'; if (isStart) { - icon = MapStartWaypoint; - markerSize = getMapMarkerSize('START_WAYPOINT'); + markerType = 'START_WAYPOINT'; } else if (isEnd) { - icon = MapStopWaypoint; - markerSize = getMapMarkerSize('STOP_WAYPOINT'); + markerType = 'STOP_WAYPOINT'; } return [ { id: key, coordinate: [waypoint.lng, waypoint.lat], - markerComponent: (): ReactNode => getMarkerComponent(icon, markerSize.width, markerSize.height), + markerComponent: (): ReactNode => getMapMarkerIconComponent(markerType), }, ]; }); From 222382e614711aaec30ff5e06d22ec750b74a47d Mon Sep 17 00:00:00 2001 From: GCyganek Date: Thu, 14 May 2026 17:38:40 +0200 Subject: [PATCH 09/18] Use .svg on web and .tsx for RN --- assets/images/map-current-location.svg | 1 + assets/images/map-start-waypoint.svg | 1 + assets/images/map-stop-waypoint.svg | 1 + assets/images/map-waypoint.svg | 1 + .../Icon/chunks/expensify-icons.chunk.ts | 18 +++++--- ...tLocation.tsx => RNMapCurrentLocation.tsx} | 4 +- ...artWaypoint.tsx => RNMapStartWaypoint.tsx} | 4 +- ...StopWaypoint.tsx => RNMapStopWaypoint.tsx} | 4 +- .../{MapWaypoint.tsx => RNMapWaypoint.tsx} | 4 +- src/components/MapView/MapView.tsx | 4 +- src/hooks/useMapMarkers.tsx | 43 ------------------- src/hooks/useMapMarkers/getMapMarkerSize.ts | 8 ++++ src/hooks/useMapMarkers/index.tsx | 26 +++++++++++ src/hooks/useMapMarkers/types.ts | 6 +++ .../useMapMarkerIconAsset/index.native.ts | 22 ++++++++++ .../useMapMarkerIconAsset/index.ts | 22 ++++++++++ 16 files changed, 111 insertions(+), 58 deletions(-) create mode 100644 assets/images/map-current-location.svg create mode 100644 assets/images/map-start-waypoint.svg create mode 100644 assets/images/map-stop-waypoint.svg create mode 100644 assets/images/map-waypoint.svg rename src/components/MapView/Icons/{MapCurrentLocation.tsx => RNMapCurrentLocation.tsx} (93%) rename src/components/MapView/Icons/{MapStartWaypoint.tsx => RNMapStartWaypoint.tsx} (93%) rename src/components/MapView/Icons/{MapStopWaypoint.tsx => RNMapStopWaypoint.tsx} (95%) rename src/components/MapView/Icons/{MapWaypoint.tsx => RNMapWaypoint.tsx} (92%) delete mode 100644 src/hooks/useMapMarkers.tsx create mode 100644 src/hooks/useMapMarkers/getMapMarkerSize.ts create mode 100644 src/hooks/useMapMarkers/index.tsx create mode 100644 src/hooks/useMapMarkers/types.ts create mode 100644 src/hooks/useMapMarkers/useMapMarkerIconAsset/index.native.ts create mode 100644 src/hooks/useMapMarkers/useMapMarkerIconAsset/index.ts diff --git a/assets/images/map-current-location.svg b/assets/images/map-current-location.svg new file mode 100644 index 000000000000..4627502dea32 --- /dev/null +++ b/assets/images/map-current-location.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/map-start-waypoint.svg b/assets/images/map-start-waypoint.svg new file mode 100644 index 000000000000..9c5ef76f7899 --- /dev/null +++ b/assets/images/map-start-waypoint.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/map-stop-waypoint.svg b/assets/images/map-stop-waypoint.svg new file mode 100644 index 000000000000..0ce414eab6dd --- /dev/null +++ b/assets/images/map-stop-waypoint.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images/map-waypoint.svg b/assets/images/map-waypoint.svg new file mode 100644 index 000000000000..aaca27851f03 --- /dev/null +++ b/assets/images/map-waypoint.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/Icon/chunks/expensify-icons.chunk.ts b/src/components/Icon/chunks/expensify-icons.chunk.ts index 3685d7473014..7cf1cf03b7cc 100644 --- a/src/components/Icon/chunks/expensify-icons.chunk.ts +++ b/src/components/Icon/chunks/expensify-icons.chunk.ts @@ -162,6 +162,10 @@ import MagnifyingGlassSpyMouthClosed from '@assets/images/magnifying-glass-spy-m import MagnifyingGlass from '@assets/images/magnifying-glass.svg'; import Mail from '@assets/images/mail.svg'; import MakeAdmin from '@assets/images/make-admin.svg'; +import MapCurrentLocation from '@assets/images/map-current-location.svg'; +import MapStartWaypoint from '@assets/images/map-start-waypoint.svg'; +import MapStopWaypoint from '@assets/images/map-stop-waypoint.svg'; +import MapWaypoint from '@assets/images/map-waypoint.svg'; import Map from '@assets/images/map.svg'; import Megaphone from '@assets/images/megaphone.svg'; import Menu from '@assets/images/menu.svg'; @@ -262,11 +266,11 @@ import Workflows from '@assets/images/workflows.svg'; import Workspace from '@assets/images/workspace-default-avatar.svg'; import Clear from '@assets/images/x-circle.svg'; import Zoom from '@assets/images/zoom.svg'; -// These icons are React components because they have drop shadow that is handled by @svgr/babel-plugin-transform-react-native-svg -import MapCurrentLocation from '@components/MapView/Icons/MapCurrentLocation'; -import MapStartWaypoint from '@components/MapView/Icons/MapStartWaypoint'; -import MapStopWaypoint from '@components/MapView/Icons/MapStopWaypoint'; -import MapWaypoint from '@components/MapView/Icons/MapWaypoint'; +// These icons are used on mobile and are React components because they have drop shadow that is handled by @svgr/babel-plugin-transform-react-native-svg +import RNMapCurrentLocation from '@components/MapView/Icons/RNMapCurrentLocation'; +import RNMapStartWaypoint from '@components/MapView/Icons/RNMapStartWaypoint'; +import RNMapStopWaypoint from '@components/MapView/Icons/RNMapStopWaypoint'; +import RNMapWaypoint from '@components/MapView/Icons/RNMapWaypoint'; const Expensicons = { ReceiptBody, @@ -401,6 +405,10 @@ const Expensicons = { MapStartWaypoint, MapStopWaypoint, MapWaypoint, + RNMapCurrentLocation, + RNMapStartWaypoint, + RNMapStopWaypoint, + RNMapWaypoint, Menu, Meter, Megaphone, diff --git a/src/components/MapView/Icons/MapCurrentLocation.tsx b/src/components/MapView/Icons/RNMapCurrentLocation.tsx similarity index 93% rename from src/components/MapView/Icons/MapCurrentLocation.tsx rename to src/components/MapView/Icons/RNMapCurrentLocation.tsx index 58333c344909..ee238621376c 100644 --- a/src/components/MapView/Icons/MapCurrentLocation.tsx +++ b/src/components/MapView/Icons/RNMapCurrentLocation.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {Defs, FeDropShadow, Filter, G, Path, Svg} from 'react-native-svg'; import type {SvgProps} from 'react-native-svg'; -function MapCurrentLocation({width = 48, height = 48}: SvgProps) { +function RNMapCurrentLocation({width = 48, height = 48}: SvgProps) { return ( (null); const [isIdle, setIsIdle] = useState(false); const initialLocation = useMemo(() => initialState && {longitude: initialState.location[0], latitude: initialState.location[1]}, [initialState]); @@ -285,7 +285,7 @@ function MapView({ allowOverlap > diff --git a/src/hooks/useMapMarkers.tsx b/src/hooks/useMapMarkers.tsx deleted file mode 100644 index bde5c65c84de..000000000000 --- a/src/hooks/useMapMarkers.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react'; -import type {ReactNode} from 'react'; -import ImageSVG from '@components/ImageSVG'; -import CONST from '@src/CONST'; -import type IconAsset from '@src/types/utils/IconAsset'; -import {useMemoizedLazyExpensifyIcons} from './useLazyAsset'; - -type MapMarkerType = Exclude; - -function getMapMarkerSize(markerType: MapMarkerType): {width: number; height: number} { - return CONST.MAP_MARKER_SIZES[markerType]; -} - -function useMapMarkers() { - const expensifyIcons = useMemoizedLazyExpensifyIcons(['MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); - - const getMapMarkerIconAsset = (markerType: MapMarkerType): IconAsset => { - switch (markerType) { - case 'START_WAYPOINT': - return expensifyIcons.MapStartWaypoint; - case 'STOP_WAYPOINT': - return expensifyIcons.MapStopWaypoint; - default: - return expensifyIcons.MapWaypoint; - } - }; - - const getMapMarkerIconComponent = (markerType: MapMarkerType): ReactNode => { - const size = getMapMarkerSize(markerType); - return ( - - ); - }; - - return getMapMarkerIconComponent; -} - -export type {MapMarkerType}; -export default useMapMarkers; diff --git a/src/hooks/useMapMarkers/getMapMarkerSize.ts b/src/hooks/useMapMarkers/getMapMarkerSize.ts new file mode 100644 index 000000000000..2d1a28eeed60 --- /dev/null +++ b/src/hooks/useMapMarkers/getMapMarkerSize.ts @@ -0,0 +1,8 @@ +import CONST from '@src/CONST'; +import type {MapMarkerType} from './types'; + +function getMapMarkerSize(markerType: MapMarkerType): {width: number; height: number} { + return CONST.MAP_MARKER_SIZES[markerType]; +} + +export default getMapMarkerSize; diff --git a/src/hooks/useMapMarkers/index.tsx b/src/hooks/useMapMarkers/index.tsx new file mode 100644 index 000000000000..dfeafb287504 --- /dev/null +++ b/src/hooks/useMapMarkers/index.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import type {ReactNode} from 'react'; +import ImageSVG from '@components/ImageSVG'; +// eslint-disable-next-line import/extensions +import getMapMarkerSize from './getMapMarkerSize.ts'; +import type {MapMarkerType} from './types'; +import useMapMarkerIconAsset from './useMapMarkerIconAsset'; + +function useMapMarkers() { + const getMapMarkerIconAsset = useMapMarkerIconAsset(); + + const getMapMarkerIconComponent = (markerType: MapMarkerType): ReactNode => { + const size = getMapMarkerSize(markerType); + return ( + + ); + }; + + return getMapMarkerIconComponent; +} + +export default useMapMarkers; diff --git a/src/hooks/useMapMarkers/types.ts b/src/hooks/useMapMarkers/types.ts new file mode 100644 index 000000000000..b81f2e01f687 --- /dev/null +++ b/src/hooks/useMapMarkers/types.ts @@ -0,0 +1,6 @@ +import type CONST from '@src/CONST'; + +type MapMarkerType = Exclude; + +// eslint-disable-next-line import/prefer-default-export +export type {MapMarkerType}; diff --git a/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.native.ts b/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.native.ts new file mode 100644 index 000000000000..5d003b392714 --- /dev/null +++ b/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.native.ts @@ -0,0 +1,22 @@ +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; +import type {MapMarkerType} from '@hooks/useMapMarkers/types'; +import type IconAsset from '@src/types/utils/IconAsset'; + +function useMapMarkerIconAsset() { + const expensifyIcons = useMemoizedLazyExpensifyIcons(['RNMapStartWaypoint', 'RNMapStopWaypoint', 'RNMapWaypoint']); + + const getMapMarkerIconAsset = (markerType: MapMarkerType): IconAsset => { + switch (markerType) { + case 'START_WAYPOINT': + return expensifyIcons.RNMapStartWaypoint; + case 'STOP_WAYPOINT': + return expensifyIcons.RNMapStopWaypoint; + default: + return expensifyIcons.RNMapWaypoint; + } + }; + + return getMapMarkerIconAsset; +} + +export default useMapMarkerIconAsset; diff --git a/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.ts b/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.ts new file mode 100644 index 000000000000..b1260fc54c7a --- /dev/null +++ b/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.ts @@ -0,0 +1,22 @@ +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; +import type {MapMarkerType} from '@hooks/useMapMarkers/types'; +import type IconAsset from '@src/types/utils/IconAsset'; + +function useMapMarkerIconAsset() { + const expensifyIcons = useMemoizedLazyExpensifyIcons(['MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); + + const getMapMarkerIconAsset = (markerType: MapMarkerType): IconAsset => { + switch (markerType) { + case 'START_WAYPOINT': + return expensifyIcons.MapStartWaypoint; + case 'STOP_WAYPOINT': + return expensifyIcons.MapStopWaypoint; + default: + return expensifyIcons.MapWaypoint; + } + }; + + return getMapMarkerIconAsset; +} + +export default useMapMarkerIconAsset; From f048d987bdcd3a90b9363ee2ea5fffae5549cd0a Mon Sep 17 00:00:00 2001 From: GCyganek Date: Thu, 14 May 2026 17:43:21 +0200 Subject: [PATCH 10/18] Fix imports --- src/components/ConfirmedRoute.tsx | 2 +- src/components/DistanceRequest/DistanceRequestFooter.tsx | 2 +- src/hooks/useMapMarkers/index.tsx | 3 +-- .../step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx index 8710d809725f..8cdef5dc6228 100644 --- a/src/components/ConfirmedRoute.tsx +++ b/src/components/ConfirmedRoute.tsx @@ -2,7 +2,7 @@ import React, {useEffect} from 'react'; import type {ReactNode} from 'react'; import type {OnyxEntry} from 'react-native-onyx'; import useMapMarkers from '@hooks/useMapMarkers'; -import type {MapMarkerType} from '@hooks/useMapMarkers'; +import type {MapMarkerType} from '@hooks/useMapMarkers/types'; import useNetwork from '@hooks/useNetwork'; import useOnyx from '@hooks/useOnyx'; import useStyleUtils from '@hooks/useStyleUtils'; diff --git a/src/components/DistanceRequest/DistanceRequestFooter.tsx b/src/components/DistanceRequest/DistanceRequestFooter.tsx index 04982e65f1d3..8df61789fc90 100644 --- a/src/components/DistanceRequest/DistanceRequestFooter.tsx +++ b/src/components/DistanceRequest/DistanceRequestFooter.tsx @@ -9,7 +9,7 @@ import type {WayPoint} from '@components/MapView/MapViewTypes'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useMapMarkers from '@hooks/useMapMarkers'; -import type {MapMarkerType} from '@hooks/useMapMarkers'; +import type {MapMarkerType} from '@hooks/useMapMarkers/types'; import useOnyx from '@hooks/useOnyx'; import usePolicy from '@hooks/usePolicy'; import useThemeStyles from '@hooks/useThemeStyles'; diff --git a/src/hooks/useMapMarkers/index.tsx b/src/hooks/useMapMarkers/index.tsx index dfeafb287504..78bf447f507d 100644 --- a/src/hooks/useMapMarkers/index.tsx +++ b/src/hooks/useMapMarkers/index.tsx @@ -1,8 +1,7 @@ import React from 'react'; import type {ReactNode} from 'react'; import ImageSVG from '@components/ImageSVG'; -// eslint-disable-next-line import/extensions -import getMapMarkerSize from './getMapMarkerSize.ts'; +import getMapMarkerSize from './getMapMarkerSize'; import type {MapMarkerType} from './types'; import useMapMarkerIconAsset from './useMapMarkerIconAsset'; diff --git a/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx b/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx index fcca01565a87..f116937bfb1f 100644 --- a/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx +++ b/src/pages/iou/request/step/IOURequestStepDistanceGPS/useGPSWaypointMarkers.tsx @@ -1,7 +1,7 @@ import type {ReactNode} from 'react'; import type {WayPoint} from '@components/MapView/MapViewTypes'; -import type {MapMarkerType} from '@hooks/useMapMarkers'; import useMapMarkers from '@hooks/useMapMarkers'; +import type {MapMarkerType} from '@hooks/useMapMarkers/types'; import useOnyx from '@hooks/useOnyx'; import {getGPSWaypoints, isTripStopped as isTripStoppedUtil} from '@libs/GPSDraftDetailsUtils'; import ONYXKEYS from '@src/ONYXKEYS'; From f84b3ef7e63dc1fabea68ad33631299348985714 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Thu, 14 May 2026 17:46:02 +0200 Subject: [PATCH 11/18] Fix comment --- src/components/Icon/chunks/expensify-icons.chunk.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Icon/chunks/expensify-icons.chunk.ts b/src/components/Icon/chunks/expensify-icons.chunk.ts index 7cf1cf03b7cc..cf514adcecb2 100644 --- a/src/components/Icon/chunks/expensify-icons.chunk.ts +++ b/src/components/Icon/chunks/expensify-icons.chunk.ts @@ -266,7 +266,8 @@ import Workflows from '@assets/images/workflows.svg'; import Workspace from '@assets/images/workspace-default-avatar.svg'; import Clear from '@assets/images/x-circle.svg'; import Zoom from '@assets/images/zoom.svg'; -// These icons are used on mobile and are React components because they have drop shadow that is handled by @svgr/babel-plugin-transform-react-native-svg +// These icons are used on mobile and are React components because they have +// drop shadow that is NOT handled by babel-plugin-transform-react-native-svg import RNMapCurrentLocation from '@components/MapView/Icons/RNMapCurrentLocation'; import RNMapStartWaypoint from '@components/MapView/Icons/RNMapStartWaypoint'; import RNMapStopWaypoint from '@components/MapView/Icons/RNMapStopWaypoint'; From 21b7bd5ace02bd2c1d1cc4a327810a795085baeb Mon Sep 17 00:00:00 2001 From: GCyganek Date: Thu, 14 May 2026 17:58:24 +0200 Subject: [PATCH 12/18] Use .tsx on all devices, fix problem with duplicated ids on web --- assets/images/map-current-location.svg | 1 - assets/images/map-start-waypoint.svg | 1 - assets/images/map-stop-waypoint.svg | 1 - assets/images/map-waypoint.svg | 1 - .../Icon/chunks/expensify-icons.chunk.ts | 18 +++++---------- ...entLocation.tsx => MapCurrentLocation.tsx} | 11 +++++----- ...StartWaypoint.tsx => MapStartWaypoint.tsx} | 11 +++++----- ...apStopWaypoint.tsx => MapStopWaypoint.tsx} | 11 +++++----- .../{RNMapWaypoint.tsx => MapWaypoint.tsx} | 11 +++++----- src/components/MapView/MapView.tsx | 4 ++-- src/hooks/useMapMarkers/index.tsx | 16 ++++++++++++-- .../useMapMarkerIconAsset/index.native.ts | 22 ------------------- .../useMapMarkerIconAsset/index.ts | 22 ------------------- 13 files changed, 45 insertions(+), 85 deletions(-) delete mode 100644 assets/images/map-current-location.svg delete mode 100644 assets/images/map-start-waypoint.svg delete mode 100644 assets/images/map-stop-waypoint.svg delete mode 100644 assets/images/map-waypoint.svg rename src/components/MapView/Icons/{RNMapCurrentLocation.tsx => MapCurrentLocation.tsx} (83%) rename src/components/MapView/Icons/{RNMapStartWaypoint.tsx => MapStartWaypoint.tsx} (84%) rename src/components/MapView/Icons/{RNMapStopWaypoint.tsx => MapStopWaypoint.tsx} (89%) rename src/components/MapView/Icons/{RNMapWaypoint.tsx => MapWaypoint.tsx} (80%) delete mode 100644 src/hooks/useMapMarkers/useMapMarkerIconAsset/index.native.ts delete mode 100644 src/hooks/useMapMarkers/useMapMarkerIconAsset/index.ts diff --git a/assets/images/map-current-location.svg b/assets/images/map-current-location.svg deleted file mode 100644 index 4627502dea32..000000000000 --- a/assets/images/map-current-location.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/images/map-start-waypoint.svg b/assets/images/map-start-waypoint.svg deleted file mode 100644 index 9c5ef76f7899..000000000000 --- a/assets/images/map-start-waypoint.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/images/map-stop-waypoint.svg b/assets/images/map-stop-waypoint.svg deleted file mode 100644 index 0ce414eab6dd..000000000000 --- a/assets/images/map-stop-waypoint.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/assets/images/map-waypoint.svg b/assets/images/map-waypoint.svg deleted file mode 100644 index aaca27851f03..000000000000 --- a/assets/images/map-waypoint.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/Icon/chunks/expensify-icons.chunk.ts b/src/components/Icon/chunks/expensify-icons.chunk.ts index cf514adcecb2..ba2018d5b65c 100644 --- a/src/components/Icon/chunks/expensify-icons.chunk.ts +++ b/src/components/Icon/chunks/expensify-icons.chunk.ts @@ -162,10 +162,6 @@ import MagnifyingGlassSpyMouthClosed from '@assets/images/magnifying-glass-spy-m import MagnifyingGlass from '@assets/images/magnifying-glass.svg'; import Mail from '@assets/images/mail.svg'; import MakeAdmin from '@assets/images/make-admin.svg'; -import MapCurrentLocation from '@assets/images/map-current-location.svg'; -import MapStartWaypoint from '@assets/images/map-start-waypoint.svg'; -import MapStopWaypoint from '@assets/images/map-stop-waypoint.svg'; -import MapWaypoint from '@assets/images/map-waypoint.svg'; import Map from '@assets/images/map.svg'; import Megaphone from '@assets/images/megaphone.svg'; import Menu from '@assets/images/menu.svg'; @@ -266,12 +262,12 @@ import Workflows from '@assets/images/workflows.svg'; import Workspace from '@assets/images/workspace-default-avatar.svg'; import Clear from '@assets/images/x-circle.svg'; import Zoom from '@assets/images/zoom.svg'; -// These icons are used on mobile and are React components because they have +// These icons are React components because they have // drop shadow that is NOT handled by babel-plugin-transform-react-native-svg -import RNMapCurrentLocation from '@components/MapView/Icons/RNMapCurrentLocation'; -import RNMapStartWaypoint from '@components/MapView/Icons/RNMapStartWaypoint'; -import RNMapStopWaypoint from '@components/MapView/Icons/RNMapStopWaypoint'; -import RNMapWaypoint from '@components/MapView/Icons/RNMapWaypoint'; +import MapCurrentLocation from '@components/MapView/Icons/MapCurrentLocation'; +import MapStartWaypoint from '@components/MapView/Icons/MapStartWaypoint'; +import MapStopWaypoint from '@components/MapView/Icons/MapStopWaypoint'; +import MapWaypoint from '@components/MapView/Icons/MapWaypoint'; const Expensicons = { ReceiptBody, @@ -406,10 +402,6 @@ const Expensicons = { MapStartWaypoint, MapStopWaypoint, MapWaypoint, - RNMapCurrentLocation, - RNMapStartWaypoint, - RNMapStopWaypoint, - RNMapWaypoint, Menu, Meter, Megaphone, diff --git a/src/components/MapView/Icons/RNMapCurrentLocation.tsx b/src/components/MapView/Icons/MapCurrentLocation.tsx similarity index 83% rename from src/components/MapView/Icons/RNMapCurrentLocation.tsx rename to src/components/MapView/Icons/MapCurrentLocation.tsx index ee238621376c..281aa20a39e3 100644 --- a/src/components/MapView/Icons/RNMapCurrentLocation.tsx +++ b/src/components/MapView/Icons/MapCurrentLocation.tsx @@ -1,8 +1,9 @@ -import React from 'react'; +import React, {useId} from 'react'; import {Defs, FeDropShadow, Filter, G, Path, Svg} from 'react-native-svg'; import type {SvgProps} from 'react-native-svg'; -function RNMapCurrentLocation({width = 48, height = 48}: SvgProps) { +function MapCurrentLocation({width = 48, height = 48}: SvgProps) { + const filterId = useId(); return ( - + - + - + ); } -export default RNMapWaypoint; +export default MapWaypoint; diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx index c93d299193ed..59089540dd5e 100644 --- a/src/components/MapView/MapView.tsx +++ b/src/components/MapView/MapView.tsx @@ -50,7 +50,7 @@ function MapView({ const {translate} = useLocalize(); const styles = useThemeStyles(); const theme = useTheme(); - const expensifyIcons = useMemoizedLazyExpensifyIcons(['Crosshair', 'RNMapCurrentLocation']); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['Crosshair', 'MapCurrentLocation']); const cameraRef = useRef(null); const [isIdle, setIsIdle] = useState(false); const initialLocation = useMemo(() => initialState && {longitude: initialState.location[0], latitude: initialState.location[1]}, [initialState]); @@ -285,7 +285,7 @@ function MapView({ allowOverlap > diff --git a/src/hooks/useMapMarkers/index.tsx b/src/hooks/useMapMarkers/index.tsx index 78bf447f507d..ae76187bdb84 100644 --- a/src/hooks/useMapMarkers/index.tsx +++ b/src/hooks/useMapMarkers/index.tsx @@ -1,12 +1,24 @@ import React from 'react'; import type {ReactNode} from 'react'; import ImageSVG from '@components/ImageSVG'; +import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; +import type IconAsset from '@src/types/utils/IconAsset'; import getMapMarkerSize from './getMapMarkerSize'; import type {MapMarkerType} from './types'; -import useMapMarkerIconAsset from './useMapMarkerIconAsset'; function useMapMarkers() { - const getMapMarkerIconAsset = useMapMarkerIconAsset(); + const expensifyIcons = useMemoizedLazyExpensifyIcons(['MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); + + const getMapMarkerIconAsset = (markerType: MapMarkerType): IconAsset => { + switch (markerType) { + case 'START_WAYPOINT': + return expensifyIcons.MapStartWaypoint; + case 'STOP_WAYPOINT': + return expensifyIcons.MapStopWaypoint; + default: + return expensifyIcons.MapWaypoint; + } + }; const getMapMarkerIconComponent = (markerType: MapMarkerType): ReactNode => { const size = getMapMarkerSize(markerType); diff --git a/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.native.ts b/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.native.ts deleted file mode 100644 index 5d003b392714..000000000000 --- a/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.native.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; -import type {MapMarkerType} from '@hooks/useMapMarkers/types'; -import type IconAsset from '@src/types/utils/IconAsset'; - -function useMapMarkerIconAsset() { - const expensifyIcons = useMemoizedLazyExpensifyIcons(['RNMapStartWaypoint', 'RNMapStopWaypoint', 'RNMapWaypoint']); - - const getMapMarkerIconAsset = (markerType: MapMarkerType): IconAsset => { - switch (markerType) { - case 'START_WAYPOINT': - return expensifyIcons.RNMapStartWaypoint; - case 'STOP_WAYPOINT': - return expensifyIcons.RNMapStopWaypoint; - default: - return expensifyIcons.RNMapWaypoint; - } - }; - - return getMapMarkerIconAsset; -} - -export default useMapMarkerIconAsset; diff --git a/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.ts b/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.ts deleted file mode 100644 index b1260fc54c7a..000000000000 --- a/src/hooks/useMapMarkers/useMapMarkerIconAsset/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; -import type {MapMarkerType} from '@hooks/useMapMarkers/types'; -import type IconAsset from '@src/types/utils/IconAsset'; - -function useMapMarkerIconAsset() { - const expensifyIcons = useMemoizedLazyExpensifyIcons(['MapStartWaypoint', 'MapStopWaypoint', 'MapWaypoint']); - - const getMapMarkerIconAsset = (markerType: MapMarkerType): IconAsset => { - switch (markerType) { - case 'START_WAYPOINT': - return expensifyIcons.MapStartWaypoint; - case 'STOP_WAYPOINT': - return expensifyIcons.MapStopWaypoint; - default: - return expensifyIcons.MapWaypoint; - } - }; - - return getMapMarkerIconAsset; -} - -export default useMapMarkerIconAsset; From dbc77a7c27002f2624f0ebfc6b7f53325c2a39e3 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Wed, 20 May 2026 10:14:50 +0200 Subject: [PATCH 13/18] Fix Mobile-Expensify conflict --- Mobile-Expensify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mobile-Expensify b/Mobile-Expensify index 3f230549b9cd..5576bb9a7fd0 160000 --- a/Mobile-Expensify +++ b/Mobile-Expensify @@ -1 +1 @@ -Subproject commit 3f230549b9cd33370e4e6ab9cc9ca8f925a869fa +Subproject commit 5576bb9a7fd05aa43767639ef1243e06715b9e9e From 63244858b3e548af055979a1abe054566e3da2a0 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Wed, 20 May 2026 11:57:48 +0200 Subject: [PATCH 14/18] Do not display current user's location on ConfirmedRoute --- src/components/ConfirmedRoute.tsx | 1 + src/components/MapView/MapView.tsx | 15 ++++++++++++--- src/components/MapView/MapViewImpl.web.tsx | 14 +++++++++++--- src/components/MapView/MapViewTypes.ts | 3 +++ 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/components/ConfirmedRoute.tsx b/src/components/ConfirmedRoute.tsx index 858581089c00..2316c66ec1a4 100644 --- a/src/components/ConfirmedRoute.tsx +++ b/src/components/ConfirmedRoute.tsx @@ -91,6 +91,7 @@ function ConfirmedRoute({transaction, isSmallerIcon, shouldHaveBorderRadius = tr waypoints={waypointMarkers} styleURL={CONST.MAPBOX.STYLE_URL} requireRouteToDisplayMap={requireRouteToDisplayMap} + shouldDisplayCurrentLocation={false} /> ) : ( !userInteractedWithMap && (!waypoints || waypoints.length === 0), [userInteractedWithMap, waypoints]); + const shouldPanMapToCurrentPosition = useCallback( + () => !userInteractedWithMap && !shouldDisplayCurrentLocation && (!waypoints || waypoints.length === 0), + [userInteractedWithMap, waypoints, shouldDisplayCurrentLocation], + ); const setCurrentPositionToInitialState: GeolocationErrorCallback = useCallback( (error) => { @@ -277,7 +281,7 @@ function MapView({ centerCoordinate={initCenterCoordinate} bounds={initBounds} /> - {interactive && ( + {interactive && shouldDisplayCurrentLocation && ( { const MarkerComponent = markerComponent; - if (utils.areSameCoordinate([coordinate[0], coordinate[1]], [currentPosition?.longitude ?? 0, currentPosition?.latitude ?? 0]) && interactive) { + if ( + utils.areSameCoordinate([coordinate[0], coordinate[1]], [currentPosition?.longitude ?? 0, currentPosition?.latitude ?? 0]) && + interactive && + shouldDisplayCurrentLocation + ) { return null; } + return ( !userInteractedWithMap && (!waypoints || waypoints.length === 0), [userInteractedWithMap, waypoints]); + const shouldPanMapToCurrentPosition = useCallback( + () => !userInteractedWithMap && !shouldDisplayCurrentLocation && (!waypoints || waypoints.length === 0), + [userInteractedWithMap, waypoints, shouldDisplayCurrentLocation], + ); const setCurrentPositionToInitialState: GeolocationErrorCallback = useCallback( (error) => { @@ -268,7 +272,7 @@ function MapViewImpl({ mapStyle={styleURL} interactive={interactive} > - {interactive && ( + {interactive && shouldDisplayCurrentLocation && ( { const MarkerComponent = markerComponent; - if (utils.areSameCoordinate([coordinate[0], coordinate[1]], [currentPosition?.longitude ?? 0, currentPosition?.latitude ?? 0]) && interactive) { + if ( + utils.areSameCoordinate([coordinate[0], coordinate[1]], [currentPosition?.longitude ?? 0, currentPosition?.latitude ?? 0]) && + interactive && + shouldDisplayCurrentLocation + ) { return null; } return ( diff --git a/src/components/MapView/MapViewTypes.ts b/src/components/MapView/MapViewTypes.ts index 898722864ef6..2982b8a5cb86 100644 --- a/src/components/MapView/MapViewTypes.ts +++ b/src/components/MapView/MapViewTypes.ts @@ -34,6 +34,9 @@ type MapViewProps = { // Reference to the outerElement ref?: React.ForwardedRef; + + // Whether it should display the current user's location on the map + shouldDisplayCurrentLocation?: boolean; }; type DirectionProps = { From 3ce77b45340cde6da813d9c8eb89959cf78fc719 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Wed, 20 May 2026 12:01:08 +0200 Subject: [PATCH 15/18] sourceId --- src/components/MapView/Direction.web.tsx | 65 ++++++++++++------------ 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/components/MapView/Direction.web.tsx b/src/components/MapView/Direction.web.tsx index 45a13a60dfd2..61b838b52b7d 100644 --- a/src/components/MapView/Direction.web.tsx +++ b/src/components/MapView/Direction.web.tsx @@ -25,38 +25,39 @@ function Direction({coordinates}: DirectionProps) { return ( - {validSegments.map((segmentCoordinates, index) => ( - - - - - ))} + {validSegments.map((segmentCoordinates, index) => { + const sourceId = `${CONST.MAP_VIEW_LAYERS.ROUTE_SOURCE}-segment-${index}`; + return ( + + + + + ); + })} ); } From c12ba832d74f0016dc2e835e01f53e311b0a5b15 Mon Sep 17 00:00:00 2001 From: GCyganek Date: Wed, 20 May 2026 12:16:21 +0200 Subject: [PATCH 16/18] Fix shouldPanMapToCurrentPosition --- src/components/MapView/MapView.tsx | 2 +- src/components/MapView/MapViewImpl.web.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx index 5894188e8d11..e6e8e53a63f4 100644 --- a/src/components/MapView/MapView.tsx +++ b/src/components/MapView/MapView.tsx @@ -72,7 +72,7 @@ function MapView({ // false if user has already started dragging the map or // if there are one or more waypoints present. const shouldPanMapToCurrentPosition = useCallback( - () => !userInteractedWithMap && !shouldDisplayCurrentLocation && (!waypoints || waypoints.length === 0), + () => !userInteractedWithMap && shouldDisplayCurrentLocation && (!waypoints || waypoints.length === 0), [userInteractedWithMap, waypoints, shouldDisplayCurrentLocation], ); diff --git a/src/components/MapView/MapViewImpl.web.tsx b/src/components/MapView/MapViewImpl.web.tsx index abba2671179e..d78c31a632c8 100644 --- a/src/components/MapView/MapViewImpl.web.tsx +++ b/src/components/MapView/MapViewImpl.web.tsx @@ -77,7 +77,7 @@ function MapViewImpl({ // false if user has already started dragging the map or // if there are one or more waypoints present. const shouldPanMapToCurrentPosition = useCallback( - () => !userInteractedWithMap && !shouldDisplayCurrentLocation && (!waypoints || waypoints.length === 0), + () => !userInteractedWithMap && shouldDisplayCurrentLocation && (!waypoints || waypoints.length === 0), [userInteractedWithMap, waypoints, shouldDisplayCurrentLocation], ); From 2a2206ca4a441a31161625055dd8c171e61659ea Mon Sep 17 00:00:00 2001 From: GCyganek Date: Wed, 20 May 2026 14:04:30 +0200 Subject: [PATCH 17/18] MapMarkerShadowFilter --- .../MapView/Icons/MapCurrentLocation.tsx | 26 ++++----------- .../MapView/Icons/MapMarkerShadowFilter.tsx | 32 +++++++++++++++++++ .../MapView/Icons/MapStartWaypoint.tsx | 26 ++++----------- .../MapView/Icons/MapStopWaypoint.tsx | 26 ++++----------- src/components/MapView/Icons/MapWaypoint.tsx | 26 ++++----------- 5 files changed, 60 insertions(+), 76 deletions(-) create mode 100644 src/components/MapView/Icons/MapMarkerShadowFilter.tsx diff --git a/src/components/MapView/Icons/MapCurrentLocation.tsx b/src/components/MapView/Icons/MapCurrentLocation.tsx index 281aa20a39e3..4c7cfa1e4c47 100644 --- a/src/components/MapView/Icons/MapCurrentLocation.tsx +++ b/src/components/MapView/Icons/MapCurrentLocation.tsx @@ -1,6 +1,7 @@ import React, {useId} from 'react'; -import {Defs, FeDropShadow, Filter, G, Path, Svg} from 'react-native-svg'; +import {G, Path, Svg} from 'react-native-svg'; import type {SvgProps} from 'react-native-svg'; +import MapMarkerShadowFilter from './MapMarkerShadowFilter'; function MapCurrentLocation({width = 48, height = 48}: SvgProps) { const filterId = useId(); @@ -11,24 +12,11 @@ function MapCurrentLocation({width = 48, height = 48}: SvgProps) { viewBox="0 0 48 48" fill="none" > - - - - - + + + + + + ); +} + +export default MapMarkerShadowFilter; diff --git a/src/components/MapView/Icons/MapStartWaypoint.tsx b/src/components/MapView/Icons/MapStartWaypoint.tsx index 4f581628dfb9..e0bd885cf540 100644 --- a/src/components/MapView/Icons/MapStartWaypoint.tsx +++ b/src/components/MapView/Icons/MapStartWaypoint.tsx @@ -1,6 +1,7 @@ import React, {useId} from 'react'; -import {Defs, FeDropShadow, Filter, G, Path, Svg} from 'react-native-svg'; +import {G, Path, Svg} from 'react-native-svg'; import type {SvgProps} from 'react-native-svg'; +import MapMarkerShadowFilter from './MapMarkerShadowFilter'; function MapStartWaypoint({width = 48, height = 48}: SvgProps) { const filterId = useId(); @@ -11,24 +12,11 @@ function MapStartWaypoint({width = 48, height = 48}: SvgProps) { viewBox="0 0 48 48" fill="none" > - - - - - + - - - - - + - - - - - + Date: Fri, 22 May 2026 12:29:37 +0200 Subject: [PATCH 18/18] Add React import --- src/components/MapView/Icons/MapMarkerShadowFilter.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/MapView/Icons/MapMarkerShadowFilter.tsx b/src/components/MapView/Icons/MapMarkerShadowFilter.tsx index 0086f0f68fb3..74d52e7da3ff 100644 --- a/src/components/MapView/Icons/MapMarkerShadowFilter.tsx +++ b/src/components/MapView/Icons/MapMarkerShadowFilter.tsx @@ -1,3 +1,4 @@ +import React from 'react'; import {Defs, FeDropShadow, Filter} from 'react-native-svg'; type MapMarkerShadowFilterProps = {