SpeedLimitSection/index.tsx

src/ui/components/widgets/SpeedLimitSection/index.tsx
mail@pastecode.io avatar
unknown
typescript
24 days ago
14 kB
1
Indexable
Never
import { useSpeedLimitStore } from '@Contexts'
import { useSearchParams } from '@Hooks'
import { LoadingSpinner, RvTable } from '@Shared'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useLocation } from 'react-router-dom'
import SpeedLimitFiller from './components/SpeedLimitFiller'
import { useSpeedLimitFilter } from './hooks'
import { useSpeedLimitReviewTable } from './hooks'
import { useSpeedLimitReducer } from './reducer'
import { ActionTypes, speedLimitItemType } from './types'
import PopupModel from './components/PopupModel'
import { CButton, CCard } from '@coreui/react'
import { Icons } from '@Assets/icons/Icons'
import { useDispatch, useSelector } from 'react-redux'
import {
  MapContainer,
  TileLayer,
  Polyline,
  Marker,
  Popup,
  useMap,
  Tooltip,
  useMapEvents
} from 'react-leaflet'
import {
  MAP_URLS,
  MAP_ATTRIBUTION,
  DEFAULT_MAP_CENTER,
  DEFAULT_ZOOM_LEVEL,
  SCROLL_WHEEL_ZOOM
} from '../../../components/widgets/Map/constants/config.js'
import React from 'react'
import Controls from '../../../components/widgets/Map/components/Controls/Controls.js'
import StationList from '../../../components/widgets/Map/components/Station/StationList.js'
import {
  getRoutesByRailroad,
  getStationsByRouteId,
  getTSOSpeedLimitsByRouteId,
  getTrackCoordsByRouteId,
  getZoneSpeedLimitsByRouteId
} from '../../../../../src/graphQL/Api.js'
import Station from '../../../components/widgets/Map/components/Station/Station.js'
import L from 'leaflet'

import {
  fetchTSOSpeedLimitsByRouteId,
  fetchZoneSpeedLimitsByRouteId,
  fetchStationsByRouteId
} from '@Redux/slices/portalDataSlice'
import { divIcon } from 'leaflet'
import classNames from 'classnames'

interface selectedItemType {
  item: speedLimitItemType
  index: number
}
interface Station {
  station: string
  lat: number
  lng: number
  abbreviation: string
}

const SpeedLimitSection = () => {
  const [fakeLoading, setFakeLoading] = useState(false)
  const [isFirstLoad, setIsFirstLoad] = useState(true)

  const location = useLocation()
  const dispatch = useDispatch()
  const searchParams = useSearchParams()
  const {
    data: { railroadId }
  } = useSelector((state: any) => state.userInfo)

  const {
    deleteTSOSpeedLimitById: { loading: deleteTSOSpeedLimitByIdLoading }
  } = useSelector((state: any) => state.portalAction)
  const speedLimitStore = useSpeedLimitStore

  const speedLimitData = useSpeedLimitStore.use.speedLimits()
  const fetchData = useSpeedLimitStore.use.fetchData()
  const deleteTSOSpeedLimit = useSpeedLimitStore.use.deleteTSOSpeedLimit()

  const [state, actions] = useSpeedLimitReducer()
  const { routes } = useSpeedLimitFilter(state, actions)
  const { fields, customCells, data, loading } = useSpeedLimitReviewTable(
    state,
    actions
  )
  const {
    type,
    actionType,
    page,
    routeId,
    isDeleteModal,
    temporarySpeedLimitIdDelete,
    errorModal
  } = state

  const [stations, setStations] = useState<Station[]>([])
  const [trackData, setTrackData] = useState([])
  const [milepostMarkers, setMilepostMarkers] = useState([])
  const [tsoSpeedLimitsData, setTSOSpeedLimits] = useState([])
  const [zoneSpeedLimitsData, setZoneSpeedLimits] = useState([])

  const handleDeleteSpeedLimit = () => {
    const payload = {
      temporarySpeedLimitIdDelete,
      onSuccess: () => {
        const routeIdParam = searchParams.getSearchParam('route-id')
        const directionParam = searchParams.getSearchParam('direction')
        const endDestinationId = routeIdParam
          ?.split('_')
          .filter(item => item !== directionParam)
        actions.onSelectedDeleteItem(null)
        actions.onChangeIsOpenModalDelete(false)
        if (routeIdParam) {
          dispatch(
            fetchTSOSpeedLimitsByRouteId({
              routeId: routeIdParam,
              railroadId: railroadId,
              startDestinationId: directionParam!,
              endDestinationId: endDestinationId![0]
            })
          )
        }
        actions.onChangeActionType(ActionTypes.View)
      },
      onFailure: (error: string) => {
        actions.onIsOpenError(error)
        actions.onChangeIsOpenModalDelete(false)
      }
    }
    deleteTSOSpeedLimit(payload)
  }

  const showData = useCallback(() => {
    const typeArr = type?.split(',')
    const updateSpeedLimits =
      data?.filter(
        (speedLimit: speedLimitItemType) =>
          typeArr.includes(speedLimit?.type!) || type === ''
      ) || []
    speedLimitStore.setState({ speedLimits: updateSpeedLimits })
    setFakeLoading(true)
    setTimeout(() => {
      setFakeLoading(false)
    }, 300)
  }, [data, type])

  const onChangePage = useCallback(
    (e: any) => {
      if (!isFirstLoad) {
        setTimeout(() => {
          actions.onChangePage(e.toString())
        }, 20)
      }
    },
    [isFirstLoad]
  )

  const handleRowClick = (item: speedLimitItemType, index: number) => {}

  useEffect(() => {
    const pageParam = searchParams.getSearchParam('page')
    pageParam && actions.onChangePage(pageParam)
    if (data && isFirstLoad) {
      setTimeout(() => {
        setIsFirstLoad(false)
      }, 500)
    }

    // if (data && !isFirstLoad ) {
    //   setTimeout(() => {
    //     actions.onChangePage('')
    //   }, 100)
    // }
  }, [data])

  useEffect(() => {
    data && showData()
    actions.onChangeActionType(ActionTypes.View)
  }, [data, type])
  useEffect(() => {
    const page = searchParams.getSearchParam('page')
    if (actionType === ActionTypes.Add && data) {
      // onChangePage(1)
      actions.onChangePage('')
      searchParams.delSearchParam('page')
      const newSpeedLimitData = [{}, ...(speedLimitData ?? [])]
      speedLimitStore.setState({ speedLimits: newSpeedLimitData })
      if (page && page !== '1') {
        setFakeLoading(true)
        setTimeout(() => {
          setFakeLoading(false)
        }, 100)
      }
    }
  }, [actionType])

  // ---------------------------

  useEffect(() => {
    const fetchTrackData = async () => {
      try {
        const trackLatLongData = await getTrackCoordsByRouteId({
          railroadId: 'VIA',
          routeId: 'TRTO_OTTW',
          startDestinationId: 'TRTO',
          endDestinationId: 'OTTW'
        })
        setTrackData(trackLatLongData)
        // console.log('trackData:', trackLatLongData)
      } catch (error) {
        console.error('Error fetching track data:', error)
      }
    }
    const fetchStationsData = async () => {
      try {
        const stationsData = await getStationsByRouteId({
          railroadId: 'VIA',
          routeId: 'TRTO_OTTW'
        })
        // console.log('Station Data:', stationsData)
        setStations(stationsData)
      } catch (error) {
        console.error('Error fetching track data:', error)
      }
    }
    const fetchRoutesData = async () => {
      try {
        // console.log('🚀 BEFORE Routes CALL:')
        const routesData = await getRoutesByRailroad('VIA')
        // console.log('🚀 ROUTES  Data:', routesData)
      } catch (error) {
        console.error('Error fetching ROUTES data:', error)
      }
    }
    const fetchTSOSpeedLimitsData = async () => {
      try {
        // console.log('🚀 BEFORE TSO CALL:')
        const tsoSpeedLimitsData = await getTSOSpeedLimitsByRouteId({
          railroadId: 'VIA',
          routeId: 'TRTO_OTTW',
          startDestinationId: 'TRTO',
          endDestinationId: 'OTTW'
        })
        // console.log('🚀 TSO Speed Limits Data:', tsoSpeedLimitsData)
        setTSOSpeedLimits(tsoSpeedLimitsData)
      } catch (error) {
        console.error('Error fetching TSO speed limits data:', error)
      }
    }
    const fetchZoneSpeedLimitsData = async () => {
      try {
        // console.log('🚀 BEFORE ZONE LIMIT CALL')
        const zoneSpeedLimitsData = await getZoneSpeedLimitsByRouteId({
          railroadId: 'VIA',
          routeId: 'TRTO_OTTW',
          startDestinationId: 'TRTO',
          endDestinationId: 'OTTW'
        })
        // console.log('🚀 Zone Speed Limits Data:', zoneSpeedLimitsData)
        setZoneSpeedLimits(zoneSpeedLimitsData)
      } catch (error) {
        console.error('Error fetching Zone speed limits data:', error)
      }
    }
    fetchRoutesData()
    fetchTrackData()
    fetchStationsData()
    fetchTSOSpeedLimitsData()
    fetchZoneSpeedLimitsData()
  }, [])
  const customIcon = divIcon({
    className: 'w-full h-full bg-[#555555] rounded-full',
    iconSize: [12, 12]
  })
  const bounds =
    stations.length > 0
      ? L.latLngBounds(stations.map(station => [station.lat, station.lng]))
      : L.latLngBounds([
          [0, 0],
          [0, 0]
        ])
  const FitBounds = ({ bounds }: { bounds: L.LatLngBounds }) => {
    const map = useMap()
    useEffect(() => {
      if (bounds.isValid()) {
        map.fitBounds(bounds)
      } else {
        console.error('Bounds are not valid.')
      }
    }, [map, bounds])
    return null
  }
  const [showMarkers, setShowMarkers] = useState(true)

  const toggleMarkers = () => {
    setShowMarkers(prevShowMarkers => !prevShowMarkers)
  }

  return (
    <div id="rv-portal">
      <h4>Speed limit</h4>
      <SpeedLimitFiller state={state} actions={actions} />

      {loading ? (
        <LoadingSpinner classNames="my-5" />
      ) : fakeLoading ? (
        <LoadingSpinner classNames="my-5" />
      ) : (
        <RvTable
          items={speedLimitData}
          fields={fields}
          itemsPerPage={5}
          sorter={false}
          striped={false}
          onRowClick={(item, index) => {
            handleRowClick(item, index)
          }}
          customizedCells={customCells}
          sorterValue={undefined}
          onPageChange={onChangePage}
          activePage={parseInt(state.page) ?? 1}
        />
      )}
      <button onClick={toggleMarkers}>
        {showMarkers ? 'Hide Stations' : 'Show Stations'}
      </button>
      <CCard
        style={{
          width: '100%',
          height: '70vh'
        }}
      >
        <MapContainer
          center={[43.64606677, -79.37180328]}
          zoom={DEFAULT_ZOOM_LEVEL}
          doubleClickZoom={false}
          scrollWheelZoom={SCROLL_WHEEL_ZOOM}
        >
          <Controls />

          <TileLayer
            attribution={MAP_ATTRIBUTION}
            url={MAP_URLS.MAPBOX_BASIC}
          />
          {showMarkers &&
            stations.map(({ abbreviation, lat, lng }) => (
              <Marker
                key={abbreviation}
                position={[lat, lng]}
                icon={customIcon}
              >
                <Tooltip>{abbreviation}</Tooltip>
                <div className="relative h-[12px] w-[12px]"></div>
              </Marker>
            ))}
          <Polyline
            positions={trackData.map(({ gps_coordinates: { lat, lng } }) => [
              lat,
              lng
            ])}
            color="#57a7f2"
          />
          <FitBounds bounds={bounds} />
        </MapContainer>
      </CCard>

      <PopupModel isOpen={isDeleteModal}>
        <div className="flex flex-col gap-2  px-4 py-4">
          <div className="flex gap-2 justify-start">
            <Icons.Warning className="w-[42px] h-[42px]" />
            <div>
              <div className=" mb-1">
                <span className="font-medium text-2xl ">
                  Delete Speed Limit
                </span>
              </div>
              <div>
                <span className="w-full font-normal text-[16px]">
                  Are you sure you want to delete speed limit
                </span>
              </div>
            </div>
          </div>
        </div>

        <div className="flex justify-end gap-2 px-4 pb-4">
          <CButton
            color="secondary"
            onClick={() => {
              actions.onChangeIsOpenModalDelete(false)
              actions.onSelectedDeleteItem(null)
            }}
          >
            Cancel
          </CButton>
          <CButton
            color="danger"
            disabled={deleteTSOSpeedLimitByIdLoading}
            onClick={handleDeleteSpeedLimit}
          >
            Delete
          </CButton>
        </div>
      </PopupModel>

      <PopupModel isOpen={!!errorModal}>
        <div className="flex flex-col gap-2  px-4 py-4">
          <div className="flex gap-2 justify-start">
            <div>
              <div className=" flex justify-start items-center gap-2 mb-1">
                <Icons.Error className="w-[42px] h-[42px]" />
                <span className="font-medium text-2xl ">Error</span>
              </div>
              <div>
                <span className="w-full font-normal text-[16px]">
                  {errorModal}
                </span>
              </div>
            </div>
          </div>
        </div>

        <div className="flex justify-end gap-2 px-4 pb-4">
          <CButton
            color="secondary"
            onClick={() => {
              actions.onIsOpenError('')
            }}
          >
            Close
          </CButton>
        </div>
      </PopupModel>
    </div>
  )
}

export default SpeedLimitSection
Leave a Comment