From a7f149a559ef9704dccbf7baeaf0ccf58ddbae79 Mon Sep 17 00:00:00 2001 From: Dorin zrihen Date: Wed, 12 Jun 2024 16:22:02 +0300 Subject: [PATCH 1/4] feat: add to single line map buttons for better navigation --- .../components/map-related/MapContent.tsx | 36 +++++++++++++------ .../MapFooterButtons/MapFooterButtons.tsx | 18 ++++++++++ .../map-related/MapLayers/BusToolTip.tsx | 7 ++-- .../map-related/MapWithLocationsAndPath.tsx | 4 +-- src/pages/components/map-related/map-types.ts | 3 +- src/pages/singleLineMap/index.tsx | 3 +- 6 files changed, 53 insertions(+), 18 deletions(-) create mode 100644 src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx diff --git a/src/pages/components/map-related/MapContent.tsx b/src/pages/components/map-related/MapContent.tsx index 04bf9397..db83b56e 100644 --- a/src/pages/components/map-related/MapContent.tsx +++ b/src/pages/components/map-related/MapContent.tsx @@ -1,5 +1,6 @@ -import { Marker, Polyline, Popup, TileLayer } from 'react-leaflet' -import { Icon, IconOptions } from 'leaflet' +import { useRef } from 'react' +import { Marker, Polyline, Popup, TileLayer, useMap } from 'react-leaflet' +import { Icon, IconOptions, Marker as LeafletMarker } from 'leaflet' import { useAgencyList } from 'src/api/agencyList' import { busIcon, busIconPath } from '../utils/BusIcon' import { BusToolTip } from './MapLayers/BusToolTip' @@ -8,12 +9,13 @@ import '../../Map.scss' import { MapProps } from './map-types' import { useRecenterOnDataChange } from './useRecenterOnDataChange' import { MapIndex } from './MapIndex' +import MapFooterButtons from './MapFooterButtons/MapFooterButtons' -export function MapContent({ positions, plannedRouteStops }: MapProps) { +export function MapContent({ positions, plannedRouteStops, showNavigationButtons }: MapProps) { useRecenterOnDataChange({ positions, plannedRouteStops }) - + const markerRef = useRef<{[key: number]: LeafletMarker | null}>({}) + const map = useMap() const agencyList = useAgencyList() - const getIcon = (path: string, width: number = 10, height: number = 10): Icon => { return new Icon({ iconUrl: path, @@ -28,6 +30,16 @@ export function MapContent({ positions, plannedRouteStops }: MapProps) { const actualRouteStopMarker = getIcon(actualRouteStopMarkerPath, 20, 20) const plannedRouteStopMarker = getIcon(plannedRouteStopMarkerPath, 20, 25) + const navigateMarkers = (positionId: number) => { + const loc = positions[positionId].loc + if (!map || !loc) return + const marker = markerRef?.current && markerRef?.current[positionId] + if (marker) { + map.flyTo(loc, map.getZoom()) + marker.openPopup(); + } + } + return ( <> agency.operator_ref === pos.operator) - ?.agency_name, - }) + operator_id: pos.operator?.toString() || 'default', + name: agencyList.find((agency) => agency.operator_ref === pos.operator) + ?.agency_name, + }) : actualRouteStopMarker return ( - + markerRef.current[i] = ref} position={pos.loc} icon={icon} key={i}> - + + {showNavigationButtons && } + ) diff --git a/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx b/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx new file mode 100644 index 00000000..a58e1867 --- /dev/null +++ b/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx @@ -0,0 +1,18 @@ +import { + LeftOutlined, + RightOutlined +} from '@ant-design/icons' +import { Point } from 'src/pages/timeBasedMap' + +function MapFooterButtons({index, positions, navigateMarkers}: {index: number, positions: Point[], navigateMarkers: (id: number) => void}){ + const checkIfValidStep = (i: number) => { + return Boolean(positions.at(i)) + } + + return <> + navigateMarkers(index+1)} /> + navigateMarkers(index-1)} /> + +} + +export default MapFooterButtons \ No newline at end of file diff --git a/src/pages/components/map-related/MapLayers/BusToolTip.tsx b/src/pages/components/map-related/MapLayers/BusToolTip.tsx index 19c644f6..2fda1256 100644 --- a/src/pages/components/map-related/MapLayers/BusToolTip.tsx +++ b/src/pages/components/map-related/MapLayers/BusToolTip.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from 'react' +import { ReactNode, useEffect, useState } from 'react' import { Link } from 'react-router-dom' import { Point } from 'src/pages/timeBasedMap' import { Button } from '@mui/material' @@ -11,9 +11,9 @@ import CircularProgress from '@mui/material/CircularProgress' import cn from 'classnames' import CustomTreeView from '../../CustomTreeView' -export type BusToolTipProps = { position: Point; icon: string } +export type BusToolTipProps = { position: Point; icon: string, children: ReactNode } -export function BusToolTip({ position, icon }: BusToolTipProps) { +export function BusToolTip({ position, icon, children }: BusToolTipProps) { const [siriRide, setSiriRide] = useState() const [isLoading, setIsLoading] = useState(false) const [showJson, setShowJson] = useState(false) @@ -110,6 +110,7 @@ export function BusToolTip({ position, icon }: BusToolTipProps) { )} + {children} )} diff --git a/src/pages/components/map-related/MapWithLocationsAndPath.tsx b/src/pages/components/map-related/MapWithLocationsAndPath.tsx index ecefe1a0..dcba112c 100644 --- a/src/pages/components/map-related/MapWithLocationsAndPath.tsx +++ b/src/pages/components/map-related/MapWithLocationsAndPath.tsx @@ -12,7 +12,7 @@ const position: Point = { color: 0, } -export function MapWithLocationsAndPath({ positions, plannedRouteStops }: MapProps) { +export function MapWithLocationsAndPath({ positions, plannedRouteStops, showNavigationButtons }: MapProps) { const [isExpanded, setIsExpanded] = useState(false) const toggleExpanded = useCallback(() => setIsExpanded((expanded) => !expanded), []) @@ -23,7 +23,7 @@ export function MapWithLocationsAndPath({ positions, plannedRouteStops }: MapPro - + ) diff --git a/src/pages/components/map-related/map-types.ts b/src/pages/components/map-related/map-types.ts index 9ac8e679..d1ce9580 100644 --- a/src/pages/components/map-related/map-types.ts +++ b/src/pages/components/map-related/map-types.ts @@ -11,5 +11,6 @@ export interface Path { export interface MapProps { positions: Point[] - plannedRouteStops: BusStop[] + plannedRouteStops: BusStop[], + showNavigationButtons?: boolean, } diff --git a/src/pages/singleLineMap/index.tsx b/src/pages/singleLineMap/index.tsx index 7ca2d2e8..63c1076c 100644 --- a/src/pages/singleLineMap/index.tsx +++ b/src/pages/singleLineMap/index.tsx @@ -136,7 +136,8 @@ const SingleLineMapPage = () => { + showNavigationButtons + /> ) } From 07202e1b8195a3cc8fa24abd7b479261fcb1103f Mon Sep 17 00:00:00 2001 From: Dorin zrihen Date: Wed, 12 Jun 2024 19:09:29 +0300 Subject: [PATCH 2/4] fix css & lint --- .../components/map-related/MapContent.tsx | 28 +++++++++---- .../MapFooterButtons/MapFooterButtons.scss | 9 ++++ .../MapFooterButtons/MapFooterButtons.tsx | 41 +++++++++++++------ .../map-related/MapLayers/BusToolTip.tsx | 2 +- .../map-related/MapWithLocationsAndPath.tsx | 12 +++++- src/pages/components/map-related/map-types.ts | 4 +- src/pages/singleLineMap/index.tsx | 2 +- 7 files changed, 70 insertions(+), 28 deletions(-) create mode 100644 src/pages/components/map-related/MapFooterButtons/MapFooterButtons.scss diff --git a/src/pages/components/map-related/MapContent.tsx b/src/pages/components/map-related/MapContent.tsx index db83b56e..4d1f4a8d 100644 --- a/src/pages/components/map-related/MapContent.tsx +++ b/src/pages/components/map-related/MapContent.tsx @@ -13,7 +13,7 @@ import MapFooterButtons from './MapFooterButtons/MapFooterButtons' export function MapContent({ positions, plannedRouteStops, showNavigationButtons }: MapProps) { useRecenterOnDataChange({ positions, plannedRouteStops }) - const markerRef = useRef<{[key: number]: LeafletMarker | null}>({}) + const markerRef = useRef<{ [key: number]: LeafletMarker | null }>({}) const map = useMap() const agencyList = useAgencyList() const getIcon = (path: string, width: number = 10, height: number = 10): Icon => { @@ -31,12 +31,12 @@ export function MapContent({ positions, plannedRouteStops, showNavigationButtons const plannedRouteStopMarker = getIcon(plannedRouteStopMarkerPath, 20, 25) const navigateMarkers = (positionId: number) => { - const loc = positions[positionId].loc + const loc = positions[positionId]?.loc if (!map || !loc) return const marker = markerRef?.current && markerRef?.current[positionId] if (marker) { map.flyTo(loc, map.getZoom()) - marker.openPopup(); + marker.openPopup() } } @@ -62,16 +62,26 @@ export function MapContent({ positions, plannedRouteStops, showNavigationButtons const icon = i === 0 ? busIcon({ - operator_id: pos.operator?.toString() || 'default', - name: agencyList.find((agency) => agency.operator_ref === pos.operator) - ?.agency_name, - }) + operator_id: pos.operator?.toString() || 'default', + name: agencyList.find((agency) => agency.operator_ref === pos.operator) + ?.agency_name, + }) : actualRouteStopMarker return ( - markerRef.current[i] = ref} position={pos.loc} icon={icon} key={i}> + (markerRef.current[i] = ref)} + position={pos.loc} + icon={icon} + key={i}> - {showNavigationButtons && } + {showNavigationButtons && ( + + )} diff --git a/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.scss b/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.scss new file mode 100644 index 00000000..b50969e4 --- /dev/null +++ b/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.scss @@ -0,0 +1,9 @@ +.map-footer-buttons { + display: flex; + justify-content: space-between; + + .disabled { + pointer-events: none; + opacity: 0.5; + } +} \ No newline at end of file diff --git a/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx b/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx index a58e1867..de80bce6 100644 --- a/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx +++ b/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx @@ -1,18 +1,33 @@ -import { - LeftOutlined, - RightOutlined -} from '@ant-design/icons' +import { LeftOutlined, RightOutlined } from '@ant-design/icons' import { Point } from 'src/pages/timeBasedMap' +import './MapFooterButtons.scss' -function MapFooterButtons({index, positions, navigateMarkers}: {index: number, positions: Point[], navigateMarkers: (id: number) => void}){ - const checkIfValidStep = (i: number) => { - return Boolean(positions.at(i)) - } +type TMapFooterButtons = { + index: number + positions: Point[] + navigateMarkers: (id: number) => void +} + +function MapFooterButtons({ index, positions, navigateMarkers }: TMapFooterButtons) { + const rightStep = index + 1 + const leftStep = index - 1 + + const checkIfValidStep = (i: number) => { + return Boolean(positions.at(i)) + } - return <> - navigateMarkers(index+1)} /> - navigateMarkers(index-1)} /> - + return ( +
+ navigateMarkers(rightStep)} + /> + navigateMarkers(leftStep)} + /> +
+ ) } -export default MapFooterButtons \ No newline at end of file +export default MapFooterButtons diff --git a/src/pages/components/map-related/MapLayers/BusToolTip.tsx b/src/pages/components/map-related/MapLayers/BusToolTip.tsx index 2fda1256..02e9f25d 100644 --- a/src/pages/components/map-related/MapLayers/BusToolTip.tsx +++ b/src/pages/components/map-related/MapLayers/BusToolTip.tsx @@ -11,7 +11,7 @@ import CircularProgress from '@mui/material/CircularProgress' import cn from 'classnames' import CustomTreeView from '../../CustomTreeView' -export type BusToolTipProps = { position: Point; icon: string, children: ReactNode } +export type BusToolTipProps = { position: Point; icon: string; children: ReactNode } export function BusToolTip({ position, icon, children }: BusToolTipProps) { const [siriRide, setSiriRide] = useState() diff --git a/src/pages/components/map-related/MapWithLocationsAndPath.tsx b/src/pages/components/map-related/MapWithLocationsAndPath.tsx index dcba112c..3cf92c4e 100644 --- a/src/pages/components/map-related/MapWithLocationsAndPath.tsx +++ b/src/pages/components/map-related/MapWithLocationsAndPath.tsx @@ -12,7 +12,11 @@ const position: Point = { color: 0, } -export function MapWithLocationsAndPath({ positions, plannedRouteStops, showNavigationButtons }: MapProps) { +export function MapWithLocationsAndPath({ + positions, + plannedRouteStops, + showNavigationButtons, +}: MapProps) { const [isExpanded, setIsExpanded] = useState(false) const toggleExpanded = useCallback(() => setIsExpanded((expanded) => !expanded), []) @@ -23,7 +27,11 @@ export function MapWithLocationsAndPath({ positions, plannedRouteStops, showNavi - + ) diff --git a/src/pages/components/map-related/map-types.ts b/src/pages/components/map-related/map-types.ts index d1ce9580..5c98a8cf 100644 --- a/src/pages/components/map-related/map-types.ts +++ b/src/pages/components/map-related/map-types.ts @@ -11,6 +11,6 @@ export interface Path { export interface MapProps { positions: Point[] - plannedRouteStops: BusStop[], - showNavigationButtons?: boolean, + plannedRouteStops: BusStop[] + showNavigationButtons?: boolean } diff --git a/src/pages/singleLineMap/index.tsx b/src/pages/singleLineMap/index.tsx index 63c1076c..6c8fa569 100644 --- a/src/pages/singleLineMap/index.tsx +++ b/src/pages/singleLineMap/index.tsx @@ -137,7 +137,7 @@ const SingleLineMapPage = () => { positions={filteredPositions} plannedRouteStops={plannedRouteStops} showNavigationButtons - /> + /> ) } From c6fe354bfcadb271bf707077646c5b9ae2d3c9d1 Mon Sep 17 00:00:00 2001 From: Dorin zrihen Date: Thu, 13 Jun 2024 11:14:09 +0300 Subject: [PATCH 3/4] fix typescript issue --- src/pages/components/map-related/MapLayers/BusToolTip.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/components/map-related/MapLayers/BusToolTip.tsx b/src/pages/components/map-related/MapLayers/BusToolTip.tsx index 02e9f25d..85dfb8bc 100644 --- a/src/pages/components/map-related/MapLayers/BusToolTip.tsx +++ b/src/pages/components/map-related/MapLayers/BusToolTip.tsx @@ -11,7 +11,7 @@ import CircularProgress from '@mui/material/CircularProgress' import cn from 'classnames' import CustomTreeView from '../../CustomTreeView' -export type BusToolTipProps = { position: Point; icon: string; children: ReactNode } +export type BusToolTipProps = { position: Point; icon: string; children?: ReactNode } export function BusToolTip({ position, icon, children }: BusToolTipProps) { const [siriRide, setSiriRide] = useState() From 3cf63bac9b754cd57689fcc9dc4741f9e2b094cf Mon Sep 17 00:00:00 2001 From: Dorin zrihen Date: Fri, 14 Jun 2024 16:11:32 +0300 Subject: [PATCH 4/4] after review --- .../map-related/MapFooterButtons/MapFooterButtons.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx b/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx index de80bce6..369c9616 100644 --- a/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx +++ b/src/pages/components/map-related/MapFooterButtons/MapFooterButtons.tsx @@ -19,10 +19,12 @@ function MapFooterButtons({ index, positions, navigateMarkers }: TMapFooterButto return (
navigateMarkers(rightStep)} /> navigateMarkers(leftStep)} />