Map/InfoCar/index.tsx

mail@pastecode.io avatar
unknown
plain_text
7 months ago
31 kB
2
Indexable
Never
/* eslint-disable react-native/no-inline-styles */
import React, {useEffect, useRef, useState, useMemo} from 'react';
import {
  Text,
  View,
  TouchableOpacity,
  Animated,
  useWindowDimensions,
} from 'react-native';
import GetLocation from 'react-native-get-location';
import isEmpty from 'lodash/isEmpty';
import dayjs from 'dayjs';

// Navigation
import {useNavigation} from '@react-navigation/native';
import ScreensName from '@Configs/navigator';

// Redux Selectors
import {useSelector, useDispatch} from 'react-redux';
import {
  getRunningTrains,
  getCurrentTripKey,
  getTripId,
  getStationHistory,
  getSimpleTrainConsistSelector,
} from '@Redux/trip/selectors';
import {getLocationData, getPosition} from '@Redux/info/selectors';
import {getModels} from '@Redux/model/selectors';
import {
  getWaitingStatus,
  getRunningStatus,
  getFinishedStatus,
  getTravelDistance,
  getOrientation,
  getActiveEnv,
  getOutOfTrack,
  getUserInteractTime,
  getShowTrackGradeView,
  getCurrentMilepost,
  getLastTimeFinishedChanged,
} from '@Redux/common/selectors';
import {getUserAuthorizationSelector, getUsername} from '@Redux/auth/selectors';
import {getInstructionGroup} from '@Redux/instruction/selectors';
import {getStopStations, getTrackGroupData} from '@Redux/track/selectors';
import {
  getSelectedTrainId,
  getTrainSelectionInfo,
} from '@Redux/train/selectors';
import {getMultipleSpeedProfileList} from '@Redux/speedProfile/selectors';
import {getConsistTrain, getCurrentSpeed} from '@Redux/train/selectors';
import {getStationActive} from '@Redux/station/selectors';

// Redux Actions
import {
  setRunning,
  setFinished,
  setWaiting,
  setTravelDistance,
} from '@Redux/common/actions';
import {
  setGpsItem,
  setCurrentTripKey,
  cleanGpsList,
  clearModelEventList,
  setModelEventItem,
  setStartStationHistory,
  setEndStationHistory,
  addStationHistoryItem,
  addSpeedHistoryItem,
} from '@Redux/trip/actions';
import {clearInstructionGroup} from '@Redux/instruction/actions';

// Components
import Loader from './Loader';
import RightWidget from './RightWidget';
import ETA from './ETA';
import RecommendationItem from './RecommendationItem/RecommendationItem';
import Recenter from '@Com/Recenter';
import CloseTrip from './CloseTrip';
import ZoomInOut from '@Com/ZoomInOut';
import TrackGradeView from '@Com/TrackGradeView';
import ScaleBar from '@Com/ScaleBar';
import Speedometer from '@Com/Speedometer';

// Constants
import {
  END_TRIP_ON_ARRIVE_AFTER_SECONDS,
  TRAIN_IMAGE_WIDTH_BY_KM,
} from '@Constants';

// Types
import {UseStateTuple, Region} from '@Types';
import {ModelEventType} from '@Types';

// Utils
import {modelInterface} from '@Utils/modelInterface';
import {filterInterface} from '@Utils/filterInterface';
import {
  getOffsetCoordinate,
  getBearingAngle,
  haversineDistance,
} from '@Utils/geometryHelper';
import {getSegmentIdFromCoord} from '@Utils/getCorridorSegmentDetails';
import {
  createNewGPSFile,
  generateGPSFileName,
  generateGpsData,
} from '@Utils/gpsData';
import {
  generateModelFileName,
  createNewModelFile,
  appendToModelFile,
} from '@Utils/modelData';

// Hooks
import useLogGPSLocation from '@Hooks/useLogGPSLocation';

// Styles
import styles from './styles';

const ModelInterface = new modelInterface();

export type MapProps = {
  region?: Region;
};

const InfoCar: React.FC<{
  mapRef: any;
  regionRef: any;
  isReady: boolean;
}> = ({mapRef, regionRef, isReady}) => {
  const {width, height: screenHeight} = useWindowDimensions();
  const dispatch = useDispatch();
  const navigation = useNavigation();
  const currentAngleRef = useRef();
  const currentTravelDistance = useRef(0);
  const [totalDistanceBase, setTotalDistanceBase]: UseStateTuple<number> =
    useState(0);

  const trains = useSelector(state => getRunningTrains(state));
  const orientation = useSelector(state => getOrientation(state));
  const envName = useSelector(state => getActiveEnv(state));
  const height = envName === 'production' ? screenHeight : screenHeight - 25;

  const models = useSelector(state => getModels(state));

  const runningStatus = useSelector(state => getRunningStatus(state));
  const waitingStatus = useSelector(state => getWaitingStatus(state));
  const finishedStatus = useSelector(state => getFinishedStatus(state));
  const lastTimeFinishedChanged = useSelector(state =>
    getLastTimeFinishedChanged(state),
  );
  const isOutOfTrack = useSelector(state => getOutOfTrack(state));
  const selectedTrainId = useSelector(state => getSelectedTrainId(state));
  const currentMilePost = useSelector(getCurrentMilepost);

  const position = useSelector(state => getPosition(state));
  const location = useSelector(state => getLocationData(state));
  const travelDistance = useSelector(state => getTravelDistance(state));
  const instructionGroup = useSelector(state => getInstructionGroup(state));

  const stopStations = useSelector(state => getStopStations(state));
  const currentTripKey = useSelector(state => getCurrentTripKey(state));
  const trackGroupData = useSelector(state => getTrackGroupData(state));

  const tripId = useSelector(state => getTripId(state));
  const username = useSelector(state => getUsername(state));
  const userAuthorization = useSelector(state =>
    getUserAuthorizationSelector(state),
  );
  const trainSelectionInfo = useSelector(state => getTrainSelectionInfo(state));
  const simpleTrainConsist = useSelector(state =>
    getSimpleTrainConsistSelector(state),
  );

  const stationHistory = useSelector(state => getStationHistory(state));

  const multipleSpeedProfile = useSelector(state =>
    getMultipleSpeedProfileList(state),
  );

  const userInteractTime = useSelector(state => getUserInteractTime(state));
  const showTrackGradeView = useSelector(getShowTrackGradeView);

  const activeStation = useSelector(getStationActive);
  const consistTrain = useSelector(getConsistTrain);
  const currentSpeed = useSelector(getCurrentSpeed);

  let speedProfile = [];
  if (currentTripKey && !isEmpty(multipleSpeedProfile)) {
    if (typeof multipleSpeedProfile[currentTripKey] !== 'undefined') {
      speedProfile = multipleSpeedProfile[currentTripKey]?.data || [];
    }
  }

  const corridorList: any[] = useMemo(() => {
    if (currentTripKey && !isEmpty(trackGroupData)) {
      if (typeof trackGroupData[currentTripKey] !== 'undefined') {
        return trackGroupData[currentTripKey]?.data?.corridors || [];
      } else {
        return [];
      }
    } else {
      return [];
    }
  }, [trackGroupData, currentTripKey]);

  let instructions = [];
  if (currentTripKey && !isEmpty(instructionGroup)) {
    if (typeof instructionGroup[currentTripKey] !== 'undefined') {
      instructions = instructionGroup[currentTripKey]?.data || [];
    }
  }
  const [count, setCount] = useState(0);
  const [gpsJsonFileName, setGPSJsonFileName]: UseStateTuple<string | any> =
    useState(null);
  const [modelJsonFileName, setModelJsonFileName]: UseStateTuple<string | any> =
    useState(null);
  const [arriveTime, setArriveTime]: UseStateTuple<any> = useState(null);
  const opacityRef = useRef(new Animated.Value(1)).current;
  const trackingTrainId = isEmpty(selectedTrainId) ? 'none' : selectedTrainId;
  const [zoomScale, setZoomScale]: UseStateTuple<number> = useState(0);
  const [cameraCenter, setCameraCenter]: UseStateTuple<any> = useState(null);
  const [prevZoomScale, setPrevZoomScale]: UseStateTuple<number> = useState(0);
  const [loading, setLoading]: UseStateTuple<boolean> = useState(true);
  const [startAngle, setStartAngle]: UseStateTuple<number> = useState(0);
  const [startPos, setStartPos]: UseStateTuple<any> = useState();
  const [timerCheck, setTimerCheck]: UseStateTuple<number> = useState(0);
  const [confirmArrived, setConfirmArrived]: UseStateTuple<boolean> =
    useState(false);
  const [currentRecommendation, setCurrentRecommendation]: UseStateTuple<any> =
    useState(null);
  const [
    incomingRecommendation,
    setIncomingRecommendation,
  ]: UseStateTuple<any> = useState(null);

  const corridorListFilter = useMemo(
    () =>
      corridorList.map((item: any) => {
        return [
          item.gpsCoordinates.lat,
          item.gpsCoordinates.lng,
          item.corridor,
          item.station,
          item.stn1x,
          item.stn2x,
          item.distanceToNext,
          item.milepost,
        ];
      }),
    [corridorList],
  );

  const sortInstruction = instructions.sort((a: any, b: any) => {
    return a.startMile - b.startMile;
  });

  const nextInstructionIndex = sortInstruction.findIndex((item: any) => {
    return item.startMile > travelDistance;
  });

  const filterSpeedProfile = speedProfile.sort(
    (a, b) => a?.distance - b?.distance,
  );
  const currentSpeedProfleValueIndex = filterSpeedProfile.findIndex(item => {
    return item?.distance >= travelDistance;
  });
  const currentSpeedProfleValue =
    currentSpeedProfleValueIndex >= 0
      ? filterSpeedProfile[currentSpeedProfleValueIndex]
      : filterSpeedProfile[filterSpeedProfile.length - 1];

  const estimatedTimeWithSpeedProfile = useMemo(() => {
    let timeToArrival;
    if (Number.isNaN(currentSpeedProfleValue?.estimatedDurationToArrival)) {
      timeToArrival = dayjs();
    } else {
      timeToArrival = dayjs().add(
        currentSpeedProfleValue?.estimatedDurationToArrival,
        'minute',
      );
    }
    return timeToArrival.format('h:mma');
  }, [currentSpeedProfleValue, timerCheck]);

  useEffect(() => {
    ModelInterface.loadAllModels(models);
  }, []);

  useEffect(() => {
    const timerInterval = setInterval(() => {
      setTimerCheck(prev => (prev += 1));
    }, 60000);
    return () => {
      clearInterval(timerInterval);
    };
  }, []);

  useEffect(() => {
    const trackGroupDataValues = Object.values(trackGroupData) || [];
    const firstTrackData = trackGroupDataValues.find(item => item.order === 0);
    if (firstTrackData) {
      setStartPos([
        firstTrackData?.data?.corridors[0]?.gpsCoordinates.lat,
        firstTrackData?.data?.corridors[0]?.gpsCoordinates.lng,
      ]);
    }
  }, []);

  useEffect(() => {
    checkForZoomLevel(userInteractTime);
  }, [userInteractTime]);

  const checkForZoomLevel = async (numberCheck = 0) => {
    try {
      const camera = await mapRef.current?.getCamera();
      if (numberCheck === 0 || !camera) {
        setZoomScale(13.5);
      } else {
        setZoomScale(camera.zoom);
      }
    } catch (error) {
      setZoomScale(13.5);
      console.log('setZoomScale Error', error);
    }
  };

  const opacity = opacityRef.interpolate({
    inputRange: [0, 1],
    outputRange: [0, 1],
  });

  const closeLoader = () => {
    Animated.timing(opacityRef, {
      toValue: 0,
      duration: 500,
      useNativeDriver: true,
    }).start(() => {
      setLoading(false);
    });
  };

  const setCameraMap = async (
    trainsSet: any,
    latitude: number,
    longitude: number,
    isGettingReady: boolean = false,
  ) => {
    let angleCarDefault = 90;
    const camera = await mapRef.current?.getCamera();
    setCameraCenter(camera.center);
    if (!zoomScale) {
      setZoomScale(camera.zoom);
    }
    // if (zoomScale !== prevZoomScale) {
    //   setPrevZoomScale(zoomScale);
    //   hideTrain();
    // }
    const offsetWithCorridor = getOffsetCoordinate(
      [latitude, longitude],
      TRAIN_IMAGE_WIDTH_BY_KM / 2,
      angleCarDefault + trainsSet[0].angle + 90,
    );
    const offsetValue = (zoom: number) => {
      const isLandScape = orientation === 'landscape' ? true : false;
      if (zoom < 10.5) {
        return isLandScape ? 6 : 16;
      }
      switch (Math.floor(zoom)) {
        case 10:
          return isLandScape ? 4 : 10;
        case 11:
          return isLandScape ? 2 : 6;
        case 12:
          return isLandScape ? 1 : 3;
        case 13:
          if (zoom > 13.5) {
            return isLandScape ? 0.4 : 1.2;
          }
          return isLandScape ? 0.8 : 2;
        case 14:
          return isLandScape ? 0.25 : 0.6;
        case 15:
          return isLandScape ? 0.14 : 0.3;
        case 16:
          return isLandScape ? 0.07 : 0.2;
        case 17:
          return isLandScape ? 0.04 : 0.1;
        default:
          return 0;
      }
    };
    let offsetWithCenter;
    if (runningStatus) {
      offsetWithCenter = getOffsetCoordinate(
        [offsetWithCorridor.latitude, offsetWithCorridor.longitude],
        isOutOfTrack ? 0 : offsetValue(zoomScale),
        angleCarDefault + trainsSet[0].angle,
      );
    } else {
      offsetWithCenter = getOffsetCoordinate(
        [offsetWithCorridor.latitude, offsetWithCorridor.longitude],
        isOutOfTrack && !isGettingReady ? 0 : offsetValue(zoomScale),
        angleCarDefault + startAngle,
      );
    }

    const autoCenterLocation = {
      latitude: offsetWithCenter.latitude,
      longitude: offsetWithCenter.longitude,
    };

    let autoHeading = angleCarDefault + startAngle;
    if (runningStatus) {
      if (isOutOfTrack) {
        autoHeading = currentAngleRef.current
          ? currentAngleRef.current
          : angleCarDefault + startAngle;
      } else {
        autoHeading = angleCarDefault + trainsSet[0].angle;
        currentAngleRef.current = angleCarDefault + trainsSet[0].angle;
      }
    } else {
      autoHeading = angleCarDefault + startAngle;
    }

    // autoCenter
    //   ? mapRef.current.animateCamera({
    //       ...camera,
    //       zoom: zoomScale ? zoomScale : camera.zoom,
    //       heading: autoCenter ? autoHeading : camera.heading,
    //       center: autoCenter ? autoCenterLocation : camera.center,
    //     })
    //   : null;
    /**
     * check Loading
     */
    if (loading) {
      setTimeout(() => {
        closeLoader();
      }, 3000);
    }
  };

  useEffect(() => {
    if (loading) {
      setTimeout(() => {
        closeLoader();
      }, 3000);
    }
  }, []);

  const processStopStations = useMemo(() => {
    return Object.values(stopStations).sort(
      (a: any, b: any) => a?.order - b?.order,
    );
  }, [stopStations]);

  const setGpsDataToStore = () => {
    GetLocation.getCurrentPosition({
      enableHighAccuracy: true,
      timeout: 15000,
    })
      .then(location => {
        const gpsData = generateGpsData(location);
        if (runningStatus) {
          // if (regionRef.current?.latitude !== location.latitude) {
          dispatch(setGpsItem(gpsData));
          // }
        }
      })
      .catch(error => {
        const {code, message} = error;
        // console.warn(code, message);
      });
  };

  useEffect(() => {
    dispatch(
      addSpeedHistoryItem({
        distance: travelDistance + totalDistanceBase,
        speed: currentSpeed,
      }),
    );

    if (trackingTrainId === 'none') {
      return;
    }
    setGpsDataToStore();
  }, [position]);

  // CHECK ARRIVED AT LAST STATION AND CLOSE THE TRIP
  useEffect(() => {
    const timeout = setTimeout(() => {
      setCount(count + 1);
      const currentTime = Math.floor(Date.now() / 1000);
      if (
        finishedStatus &&
        lastTimeFinishedChanged + END_TRIP_ON_ARRIVE_AFTER_SECONDS < currentTime
      ) {
        const stationPair = currentTripKey.split('-');
        dispatch(
          setEndStationHistory({
            stationId: stationPair[1],
            arrivedTimeStamp: new Date().toString(),
            departedTimeStamp: null,
          }),
        );
        dispatch(setFinished(false));
        dispatch(setWaiting(false));
        dispatch(setRunning(false));
        dispatch(clearInstructionGroup());
        navigation.navigate(ScreensName.TRIP_REVIEW);
      }
    }, 5000);

    return () => clearTimeout(timeout);
  }, [finishedStatus, lastTimeFinishedChanged, count]);

  // CHECK ARRIVED_AT_STATION
  useEffect(() => {
    if (
      !(corridorList && corridorList.length > 0 && position && stopStations)
    ) {
      return;
    }

    const currentEndStation = corridorList[corridorList.length - 1];

    // Calculate distance between current train position and current end station
    const distTrainToCurrentEndStation = haversineDistance(position, [
      currentEndStation.gpsCoordinates.lat,
      currentEndStation.gpsCoordinates.lng,
    ]);

    const ARRIVED_RADIUS = 0.5;

    if (distTrainToCurrentEndStation < ARRIVED_RADIUS) {
      const currentMovementOrder = stopStations[currentTripKey]?.order;
      const numberOfMovements = Object.keys(stopStations).length;
      const isLastMovement = currentMovementOrder === numberOfMovements - 1;

      if (isLastMovement) {
        dispatch(setFinished(true));
        dispatch(setWaiting(false));
      } else {
        dispatch(setWaiting(true));
      }
      setCurrentRecommendation(null);
      setIncomingRecommendation(null);
    }
  }, [position, corridorList]);

  useEffect(() => {
    const startingAngle = getBearingAngle(
      [
        corridorList[0]?.gpsCoordinates.lat,
        corridorList[0]?.gpsCoordinates.lng,
      ],
      [
        corridorList[corridorList?.length - 1]?.gpsCoordinates.lat,
        corridorList[corridorList?.length - 1]?.gpsCoordinates.lng,
      ],
    );
    setStartAngle(startingAngle);
  }, [corridorList]);

  // useEffect(() => {
  //   if (trackingTrainId !== 'none' && trains.length > 0) {
  //     const train = getCurrentTrain(trackingTrainId, trains);
  //     if (train.position) {
  //       const {latitude, longitude} = train.position;
  //       setGpsDataToStore();
  //       regionRef.current = {
  //         latitude,
  //         longitude,
  //         zoom: Math.floor(zoomScale),
  //         zoomDetail: zoomScale,
  //       };
  //       if (isReady) {
  //         if (runningStatus || waitingStatus || !startPos?.length) {
  //           setCameraMap(trains, latitude, longitude);
  //         } else {
  //           setCameraMap(trains, startPos[0], startPos[1], true);
  //         }
  //       }
  //     }
  //   }
  // }, [
  //   trains,
  //   trackingTrainId,
  //   mapRef,
  //   zoomScale,
  //   runningStatus,
  //   waitingStatus,
  //   startPos,
  //   startAngle,
  //   autoCenter,
  //   loading,
  // ]);

  const startSetCameraCenter = async () => {
    const camera = await mapRef.current?.getCamera();
    if (camera) {
      setCameraCenter(camera.center);
    }
  };
  useEffect(() => {
    startSetCameraCenter();
  }, []);

  const handleIncomingRecommendation = (
    position: [number, number],
    milepost: number,
    speed: number,
    currentSegmentId: number,
  ) => {
    const recommendation = ModelInterface.getIncomingRecommendation(
      milepost,
      speed,
      corridorList,
      currentSegmentId,
      travelDistance,
    );

    appendToModelFile(
      modelJsonFileName,
      ModelEventType.MODEL_RUN,
      location,
      recommendation,
    );

    const filteredResult = filterInterface.filterRecommendation(
      recommendation,
      speed,
    );

    if (filteredResult.filtered) {
      appendToModelFile(
        modelJsonFileName,
        ModelEventType.MODEL_FILTERED_RECOMMENDATION,
        location,
        recommendation,
      );
    }

    if (
      !incomingRecommendation &&
      !currentRecommendation &&
      recommendation &&
      !filteredResult.filtered
    ) {
      setIncomingRecommendation({...recommendation, position: position});

      appendToModelFile(
        modelJsonFileName,
        ModelEventType.MODEL_UI_INCOMING_RECOMMENDATIONS,
        location,
        recommendation,
      );
    }
  };

  const handleCurrentRecommendation = async (
    position: [number, number],
    milepost: number,
    speed: number,
  ) => {
    const recommendation = ModelInterface.getCurrentRecommendation(
      milepost,
      speed,
    );

    appendToModelFile(
      modelJsonFileName,
      ModelEventType.MODEL_RUN,
      location,
      recommendation,
    );

    const isFiltered = filterInterface.filterRecommendation(
      recommendation,
      speed,
    );

    if (isFiltered.filtered) {
      appendToModelFile(
        modelJsonFileName,
        ModelEventType.MODEL_FILTERED_RECOMMENDATION,
        location,
        recommendation,
      );
    }

    if (!currentRecommendation && recommendation && !isFiltered.filtered) {
      setCurrentRecommendation({...recommendation, position: position});

      appendToModelFile(
        modelJsonFileName,
        ModelEventType.MODEL_UI_ACTIVE_RECOMMENDATION_START,
        location,
        recommendation,
      );
    }

    setIncomingRecommendation(null);
  };

  // Check for incoming recommendation
  useEffect(() => {
    const currentSegmentId = getSegmentIdFromCoord(
      position,
      corridorListFilter,
    );

    if (!currentTravelDistance.current) {
      currentTravelDistance.current = travelDistance;
    }

    if (Math.abs(travelDistance - currentTravelDistance.current) > 0.1) {
      currentTravelDistance.current = travelDistance;
      if (!incomingRecommendation && !currentRecommendation) {
        handleIncomingRecommendation(
          travelDistance,
          currentMilePost,
          currentSpeed,
          currentSegmentId,
        );
      } else if (
        incomingRecommendation &&
        !currentRecommendation &&
        travelDistance >= incomingRecommendation.targetDistance
      ) {
        handleCurrentRecommendation(
          travelDistance,
          currentMilePost,
          currentSpeed,
        );
      }
    }
  }, [travelDistance, currentSpeed]);

  // Check to clear recommendation
  useEffect(() => {
    if (currentRecommendation) {
      if (
        travelDistance - currentRecommendation.position >
        currentRecommendation.distance
      ) {
        appendToModelFile(
          modelJsonFileName,
          ModelEventType.MODEL_UI_ACTIVE_RECOMMENDATION_END,
          location,
          currentRecommendation,
        );

        setCurrentRecommendation(null);
      }
    }
  }, [travelDistance, currentRecommendation]);

  useLogGPSLocation(gpsJsonFileName);

  return (
    <>
      {loading && <Loader opacity={opacity} />}

      {/* Display or hide arrived/start buttons */}
      {finishedStatus ? (
        <TouchableOpacity
          style={[
            styles.btnStartStop,
            styles.wrapOver,
            {
              left: orientation === 'landscape' ? 260 : 145,
            },
          ]}
          onPress={() => {
            const stationPair = currentTripKey.split('-');
            dispatch(
              setEndStationHistory({
                stationId: stationPair[1],
                arrivedTimeStamp: new Date().toString(),
                departedTimeStamp: null,
              }),
            );
            dispatch(setFinished(false));
            dispatch(setWaiting(false));
            dispatch(setRunning(false));
            dispatch(clearInstructionGroup());
            navigation.navigate(ScreensName.TRIP_REVIEW);
          }}>
          <Text style={styles.btnArrivedAtStationText}>End Trip</Text>
        </TouchableOpacity>
      ) : waitingStatus && !confirmArrived ? (
        <TouchableOpacity
          style={[
            styles.btnStartStop,
            styles.wrapOver,
            {
              left: orientation === 'landscape' ? 260 : 145,
            },
          ]}
          onPress={() => {
            if (waitingStatus) {
              const currentOrder = Object.values(stopStations).find(
                item => item.key === currentTripKey,
              )?.order;
              const nextRoute = Object.values(stopStations).find(
                item => item.order === currentOrder + 1,
              );
              dispatch(setCurrentTripKey(nextRoute?.key || currentTripKey));
            }
            dispatch(setRunning(false));
            dispatch(cleanGpsList());
            dispatch(clearModelEventList());
            setTotalDistanceBase(travelDistance + totalDistanceBase);
            dispatch(setTravelDistance(0));
            setConfirmArrived(true);
            setArriveTime(new Date().toString());
          }}>
          <Text style={styles.btnArrivedAtStationText}>End Trip Section</Text>
        </TouchableOpacity>
      ) : waitingStatus ? (
        <TouchableOpacity
          style={[
            styles.btnStartStop,
            styles.wrapOver,
            {
              left: orientation === 'landscape' ? 260 : 145,
            },
          ]}
          onPress={async () => {
            if (!gpsJsonFileName) {
              const fileName = generateGPSFileName(
                String(userAuthorization?.railroadId),
                String(simpleTrainConsist?.simpleTrainConsistId),
              );
              setGPSJsonFileName(fileName);
              await createNewGPSFile(
                String(userAuthorization?.railroadId),
                String(simpleTrainConsist?.tripId),
                String(userAuthorization?.userId),
                fileName,
                location,
                String(simpleTrainConsist?.simpleTrainConsistId),
                String(consistTrain?.locomotiveModel),
              );
            }
            const [currentStartStationId, currentEndStationId] =
              currentTripKey.split('-');
            if (stationHistory?.startStationHistory) {
              dispatch(
                addStationHistoryItem({
                  stationId: currentStartStationId,
                  arrivedTimeStamp: arriveTime,
                  departedTimeStamp: new Date().toString(),
                }),
              );
            } else {
              dispatch(
                setStartStationHistory({
                  stationId: currentStartStationId,
                  arrivedTimeStamp: null,
                  departedTimeStamp: new Date().toString(),
                }),
              );
            }
            const loadModel = ModelInterface.selectModel(
              currentStartStationId,
              currentEndStationId,
            );
            if (!modelJsonFileName) {
              const fileName = generateModelFileName(
                String(userAuthorization?.railroadId),
                String(simpleTrainConsist?.simpleTrainConsistId),
              );
              setModelJsonFileName(fileName);
              await createNewModelFile(
                String(userAuthorization?.railroadId),
                String(simpleTrainConsist?.tripId),
                String(userAuthorization?.userId),
                fileName,
                location,
                String(simpleTrainConsist?.simpleTrainConsistId),
                String(consistTrain?.locomotiveModel),
                loadModel
                  ? ModelEventType.MODEL_LOADED
                  : ModelEventType.MODEL_LOAD_FAILED,
              );
            }

            dispatch(setRunning(true));
            setConfirmArrived(false);
            dispatch(setWaiting(false));
          }}>
          <Text style={styles.btnStartText} testID="start-button">
            Start Trip Section
          </Text>
        </TouchableOpacity>
      ) : runningStatus ? (
        currentRecommendation ? (
          <RecommendationItem
            instruction={currentRecommendation}
            travelValue={
              currentRecommendation?.position +
              currentRecommendation?.distance -
              travelDistance
            }
          />
        ) : null
      ) : (
        <TouchableOpacity
          style={[
            styles.btnStartStop,
            styles.wrapOver,
            {
              left: orientation === 'landscape' ? 260 : 145,
            },
          ]}
          onPress={async () => {
            if (!gpsJsonFileName) {
              const fileName = generateGPSFileName(
                String(userAuthorization?.railroadId),
                String(simpleTrainConsist?.simpleTrainConsistId),
              );
              setGPSJsonFileName(fileName);
              await createNewGPSFile(
                String(userAuthorization?.railroadId),
                String(simpleTrainConsist?.tripId),
                String(userAuthorization?.userId),
                fileName,
                location,
                String(simpleTrainConsist?.simpleTrainConsistId),
                String(consistTrain?.locomotiveModel),
              );
            }
            const [currentStartStationId, currentEndStationId] =
              currentTripKey.split('-');
            if (stationHistory?.startStationHistory) {
              dispatch(
                addStationHistoryItem({
                  stationId: currentStartStationId,
                  arrivedTimeStamp: arriveTime,
                  departedTimeStamp: new Date().toString(),
                }),
              );
            } else {
              dispatch(
                setStartStationHistory({
                  stationId: currentStartStationId,
                  arrivedTimeStamp: null,
                  departedTimeStamp: new Date().toString(),
                }),
              );
            }
            const loadModel = ModelInterface.selectModel(
              currentStartStationId,
              currentEndStationId,
            );
            if (!modelJsonFileName) {
              const fileName = generateModelFileName(
                String(userAuthorization?.railroadId),
                String(simpleTrainConsist?.simpleTrainConsistId),
              );
              setModelJsonFileName(fileName);
              await createNewModelFile(
                String(userAuthorization?.railroadId),
                String(simpleTrainConsist?.tripId),
                String(userAuthorization?.userId),
                fileName,
                location,
                String(simpleTrainConsist?.simpleTrainConsistId),
                String(consistTrain?.locomotiveModel),
                loadModel
                  ? ModelEventType.MODEL_LOADED
                  : ModelEventType.MODEL_LOAD_FAILED,
              );
            }
            dispatch(setRunning(true));
          }}>
          <Text style={styles.btnStartText} testID="start-button">
            Start Trip
          </Text>
        </TouchableOpacity>
      )}

      <CloseTrip />
      <ETA estimatedTime={estimatedTimeWithSpeedProfile} />
      <View style={styles.wrapControlButtons}>
        <ZoomInOut
          mapRef={mapRef}
          zoomScale={zoomScale}
          setZoomScale={setZoomScale}
        />
        <Recenter mapRef={mapRef} zoomScale={zoomScale} />
      </View>
      <Speedometer />
      <TrackGradeView track={corridorList} />
      <RightWidget
        zoomScale={zoomScale}
        incomingRecommendation={incomingRecommendation}
      />
      <ScaleBar
        zoomLevel={zoomScale || null}
        latitude={cameraCenter?.latitude || null}
        overridenStyles={{bottom: showTrackGradeView ? 270 : 70}}
      />
    </>
  );
};

export default InfoCar;