components/SpeedLimitProfile/Map.tsx

src/ui/components/widgets/SpeedLimitSection/components/SpeedLimitProfile/Map.tsx
mail@pastecode.io avatar
unknown
typescript
10 days ago
7.2 kB
0
Indexable
Never
import { useSpeedLimitStore } from '@Contexts'
import { LoadingSpinner } from '@Shared'
import { CButton, CCard } from '@coreui/react'
import { Stack, Typography } from '@mui/material'
import L from 'leaflet'
import { useEffect, useState } from 'react'
import { MapContainer, TileLayer, ZoomControl, useMap } from 'react-leaflet'
import { useSelector } from 'react-redux'
import { AntSwitch } from './AntSwitch'
import MilepostMarkers from './MilepostMarkers'
import StationMarkers from './StationMarkers'
import TSOLines from './TSOLines'
import TrackLines from './TrackLines'
import * as MapConfig from './config'
import {
  actionCreatorsProps,
  speedLimitStates,
  SpeedLimitType
} from '../../types'

interface SpeedLimitFillerType {
  state: speedLimitStates
  actions: actionCreatorsProps
}

const SpeedLimitMap = ({ state, actions }: SpeedLimitFillerType) => {
  const { TSOSpeedLimitSelected } = state

  const {
    trackCoordinatesByRouteId: {
      data: trackCoordinatesData,
      loading: trackCoordinatesLoading,
      error: trackCoordinatesError
    }
  } = useSelector((state: any) => state.portalData)

  const {
    stationsByRouteId: {
      data: stationsData,
      loading: stationsLoading,
      error: stationsError
    }
  } = useSelector((state: any) => state.portalData)

  const {
    speedLimitsDataByRouteId: {
      loading: speedLimitsDataLoading,
      error: speedLimitsDataError
    }
  } = useSelector((state: any) => state.portalData)

  const speedLimitData = useSpeedLimitStore.use.speedLimits()
  const tsoSpeedLimitData = (speedLimitData || []).filter(
    (speedLimit: any) => speedLimit.type === 'TSO'
  )

  // Toggles
  const [showMileposts, setShowMileposts] = useState(false)
  const [showStationMarkers, setShowStationMarkers] = useState(true)
  const [showSpeedLimits, setShowSpeedLimits] = useState(true)

  const boundsFit =
    stationsData?.length > 0
      ? L.latLngBounds(
          stationsData?.map((station: any) => [station.lat, station.lng])
        )
      : L.latLngBounds([
          [0, 0],
          [0, 0]
        ])

  //for automatic adjustments to the map
  const FitBounds = ({
    TSOSpeedLimitSelected
  }: {
    TSOSpeedLimitSelected: any
  }) => {
    console.log(
      '🚀 ~ SpeedLimitMap ~ TSOSpeedLimitSelected:',
      TSOSpeedLimitSelected
    )
    const map = useMap()

    useEffect(() => {
      const {
        start_gps_coordinates = { lat: 0, lng: 0 },
        end_gps_coordinates = { lat: 0, lng: 0 }
      } = TSOSpeedLimitSelected || {}

      const boundsTSO =
        TSOSpeedLimitSelected?.type === SpeedLimitType.TSO
          ? L.latLngBounds([
              [start_gps_coordinates?.lat, start_gps_coordinates?.lng],
              [end_gps_coordinates?.lat, end_gps_coordinates?.lng]
            ])
          : undefined

      if (boundsTSO?.isValid()) {
        map.fitBounds(boundsTSO)
      }
    }, [TSOSpeedLimitSelected])

    return null
  }

  if (stationsLoading || trackCoordinatesLoading || speedLimitsDataLoading) {
    return (
      <div className="text-center flex items-center justify-center">
        <div>
          <LoadingSpinner classNames="my-5" />
          <p>Loading map and track data...</p>
        </div>
      </div>
    )
  }

  return (
    <div className="flex justify-center h-[480px] w-full">
      <CCard
        style={{
          width: '100%',
          height: '100%'
        }}
      >
        <MapContainer
          // center={[43.3, -7]}
          zoom={MapConfig.DEFAULT_ZOOM_LEVEL}
          doubleClickZoom={false}
          scrollWheelZoom={MapConfig.SCROLL_WHEEL_ZOOM}
          zoomControl={false}
          bounds={boundsFit}
          boundsOptions={{
            padding: [50, 50],
            maxZoom: 15,
            animate: true
          }}
        >
          {/* Track Lines */}
          <TrackLines trackCoordinatesData={trackCoordinatesData} />

          {/* TSO Lines */}
          {showSpeedLimits && (
            <TSOLines
              tsoSpeedLimitData={tsoSpeedLimitData}
              trackCoordinatesData={trackCoordinatesData}
            />
          )}

          {/* Milepost Markers */}
          {showMileposts && (
            <MilepostMarkers trackCoordinatesData={trackCoordinatesData} />
          )}

          {/* Station Markers */}
          {showStationMarkers && <StationMarkers stationsData={stationsData} />}

          {/* <FitBounds bounds={bounds} /> */}
          <TileLayer
            attribution={MapConfig.MAP_ATTRIBUTION}
            url={MapConfig.MAP_URLS.MAPBOX_BASIC}
          />
          <ZoomControl position="bottomright" />

          <FitBounds TSOSpeedLimitSelected={TSOSpeedLimitSelected} />
        </MapContainer>

        {/* Toggle Buttons */}
        <Stack
          spacing={1}
          direction="column"
          style={{ position: 'absolute', top: 20, left: 20, zIndex: 1000 }}
        >
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <AntSwitch
              checked={showMileposts}
              onChange={(event: any) => setShowMileposts(event.target.checked)}
              inputProps={{ 'aria-label': 'ant design' }}
            />
            <Typography
              className="ml-[10px] text-gray-700 font-semibold text-sm opacity-80"
              style={{
                fontFamily: 'Inter, sans-serif',
                letterSpacing: '0.5px',
                lineHeight: '1.4'
              }}
            >
              Mileposts
            </Typography>
          </div>
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <AntSwitch
              checked={showStationMarkers}
              onChange={(event: any) =>
                setShowStationMarkers(event.target.checked)
              }
              inputProps={{ 'aria-label': 'ant design' }}
            />
            <Typography
              className="ml-[10px] text-gray-700 font-semibold text-sm opacity-80"
              style={{
                fontFamily: 'Inter, sans-serif',
                letterSpacing: '0.5px',
                lineHeight: '1.4'
              }}
            >
              Stations
            </Typography>
          </div>
          <div style={{ display: 'flex', alignItems: 'center' }}>
            <AntSwitch
              checked={showSpeedLimits}
              onChange={(event: any) =>
                setShowSpeedLimits(event.target.checked)
              }
              inputProps={{ 'aria-label': 'ant design' }}
            />
            <Typography
              className="ml-[10px] text-gray-700 font-semibold text-sm opacity-80"
              style={{
                fontFamily: 'Inter, sans-serif',
                letterSpacing: '0.5px',
                lineHeight: '1.4'
              }}
            >
              Speed Limits
            </Typography>
          </div>
        </Stack>
      </CCard>
    </div>
  )
}

export default SpeedLimitMap
Leave a Comment