SelectonGroup/SelectionTrip.tsx

mail@pastecode.io avatar
unknown
plain_text
7 months ago
16 kB
1
Indexable
Never
/* eslint-disable react-native/no-inline-styles */
import React, {useEffect, useState, useCallback} from 'react';
import {
  SafeAreaView,
  Text,
  View,
  ScrollView,
  useWindowDimensions,
  ActivityIndicator,
} from 'react-native';
import {TouchableOpacity} from 'react-native-gesture-handler';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';

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

// Redux Selectors
import {useDispatch, useSelector} from 'react-redux';
import {getOrientation, getActiveEnv} from '@Redux/common/selectors';
import {getStationList} from '@Redux/station/selectors';
import {getTripDispatch} from '@Redux/trip/selectors';
import {getConsistTrain, getTrainSelectionInfo} from '@Redux/train/selectors';
import {getTrackLoading} from '@Redux/track/selectors';
import {
  getIntermediateStations,
  validStationPair,
} from '@Utils/intermediateStations';
import {getModelsLoading} from '@Redux/model/selectors';

// Redux Actions
import {
  setAutoCenter,
  setUseTestData,
  setUseSimulatedTestData,
  setWaiting,
  setTravelDistance,
  resetUserInteractTime,
  setCurrentMilepost,
} from '@Redux/common/actions';
import {setStopStation, getTrackGroupData} from '@Redux/track/actions';
import {
  cleanGpsList,
  clearModelEventList,
  clearSpeedHistory,
  generateRandomTripId,
  setCurrentTripKey,
  setTripDispatchUserInput,
  clearStationHistory,
} from '@Redux/trip/actions';
import {getSpeedMultipleProfile} from '@Redux/speedProfile/actions';
import {getLocoModelList, setCurrentSpeed} from '@Redux/train/actions';
import {setStationActive} from '@Redux/station/actions';
import {getUserAuthorizationSelector} from '@Redux/auth/selectors';

// Hooks
import useCheckAuthenticated from '@Hooks/useCheckAuthenticated';
import useKeyboardSubscription from '@Hooks/useKeyboardSubscription';

// Components
import {ChevronRight, VerticalTripPath, VerticalTripPathList} from '@Svg';
import Header from '../Header';
import IntermediateStationList from './IntermediateStationList';
import DemoCheckboxes from './DemoCheckboxes';

// Types
import {UseStateTuple} from '@Types';
import {Station} from '@Redux/station/type';

// Styles
import styles from './styles';
import RefactorAutocompleteInput from '@Com/RefactorAutoCompleteInput';

const NextLoader = ({
  width,
  height,
  envName,
}: {
  width: number;
  height: number;
  envName: string;
}): JSX.Element => {
  return (
    <View
      style={[
        styles.loading,
        {width, height: envName === 'production' ? height : height - 25},
      ]}>
      <ActivityIndicator size={'large'} color={'#B20610'} />
    </View>
  );
};

const SelectionTrip: React.FC<{}> = () => {
  const dispatch = useDispatch();

  const navigation = useNavigation();
  const {width, height} = useWindowDimensions();
  const {keyboardStatus} = useKeyboardSubscription();
  const orientation = useSelector(state => getOrientation(state));

  // User auth & env
  const userAuthorization = useSelector(state =>
    getUserAuthorizationSelector(state),
  );
  const envName = useSelector(state => getActiveEnv(state));

  // Loadings
  const trackLoading = useSelector(state => getTrackLoading(state));
  const modelsLoading = useSelector(state => getModelsLoading(state));

  // Dispatch, consist,...
  const tripDispatchData = useSelector(state => getTripDispatch(state));
  const consistTrainData = useSelector(state => getConsistTrain(state));
  const trainInfo = useSelector(state => getTrainSelectionInfo(state));

  const [ready, setReady]: UseStateTuple<boolean> = useState(false);

  const [routeId, setRouteId]: UseStateTuple<string> = useState('');

  // Selected start and end location
  const [startStationName, setStartStationName]: UseStateTuple<string> =
    useState('');
  const [endStationName, setEndStationName]: UseStateTuple<string> =
    useState('');

  // Station List
  const stationList = useSelector(state => getStationList(state));

  // Create station list for Route dropdown
  const routeIdDropdownList = stationList?.routes.map((item: any) => {
    return item.route_name.toUpperCase();
  });

  // Selected route id value
  const selectedRouteId =
    stationList?.routes.find(
      e => e.route_name.toUpperCase() === routeId.toUpperCase(),
    )?.route_id || '';

  // Get station list for selected route id
  const stationListByRouteId = stationList?.stations.filter(
    item => item.route_id === selectedRouteId,
  );

  const stationNameList = stationListByRouteId.map(
    item => `${item.abbreviation} - ${item.location_name}`,
  );

  // Filter start and end station dropdown lists
  const startStationDropdownList = stationNameList.filter((item: any) => {
    return (
      item.toLowerCase().includes(startStationName.toLowerCase()) &&
      !(
        endStationName !== '' &&
        item.toLowerCase().includes(endStationName.toLowerCase())
      )
    );
  });
  const endStationDropdownList = stationNameList.filter((item: any) => {
    return (
      item.toLowerCase().includes(endStationName.toLowerCase()) &&
      !(
        startStationName !== '' &&
        item.toLowerCase().includes(startStationName.toLowerCase())
      )
    );
  });

  // Intermediate stations
  const [intermediateStations, setIntermediateStations] = useState<Station[]>(
    [],
  );
  const activeListStationRef = React.useRef();

  useCheckAuthenticated();

  // Prefill route ID and stations
  useEffect(() => {
    if (tripDispatchData?.startDestination) {
      const start = tripDispatchData?.startDestination;
      setStartStationName(`${start.id} - ${start.name}`);
    }

    if (tripDispatchData?.endDestination) {
      const end = tripDispatchData?.endDestination;
      setEndStationName(`${end.id} - ${end.name}`);
    }

    if (tripDispatchData?.routeId) {
      const matchingRoute = stationList?.routes.find(
        item => item.route_id === tripDispatchData.routeId,
      );
      if (matchingRoute) {
        setRouteId(matchingRoute.route_name.toUpperCase());
      }
    }
  }, [tripDispatchData]);

  // Load intermediate stations
  useEffect(() => {
    if (!validStationPair(startStationName, endStationName, stationNameList))
      return setIntermediateStations([]);

    const startStation = stationListByRouteId.find(
      station => station.abbreviation === startStationName.split(' - ')[0],
    );
    const endStation = stationListByRouteId.find(
      station => station.abbreviation === endStationName.split(' - ')[0],
    );

    setIntermediateStations(
      getIntermediateStations(stationListByRouteId, startStation, endStation),
    );
  }, [startStationName, endStationName]);

  const tryNavigate = useCallback(() => {
    if (consistTrainData) {
      navigation.navigate(ScreensName.SELECTION_TRAIN_CONSIST);
    } else {
      navigation.navigate(ScreensName.SELECTION_TRAIN_CONSIST);
    }
  }, [trainInfo, navigation, tripDispatchData]);

  useEffect(() => {
    if (ready && !modelsLoading && !trackLoading) {
      setReady(false);
      tryNavigate();
    }
  }, [modelsLoading, ready, navigation, tryNavigate, trackLoading]);

  const getDataByStopStations = (
    start: string,
    end: string,
    selectedIntermediateStationList: string[],
  ) => {
    const stops = [start, ...selectedIntermediateStationList, end];

    // One single track data call
    dispatch(
      getTrackGroupData(
        start,
        end,
        selectedRouteId,
        userAuthorization?.railroadId,
        stops,
      ),
    );

    // Call ETA query for each section
    for (let i = 0; i < stops?.length - 1; i++) {
      dispatch(
        setStopStation({
          key: `${stops[i]}-${stops[i + 1]}`,
          order: i,
        }),
      );
      dispatch(
        getSpeedMultipleProfile(
          stops[i],
          stops[i + 1],
          selectedRouteId,
          userAuthorization?.railroadId,
          i,
        ),
      );
    }
  };

  const clearTripStates = () => {
    if (envName !== 'dev') {
      dispatch(setUseTestData(false));
      dispatch(setUseSimulatedTestData(false));
    }
    dispatch(getLocoModelList(userAuthorization?.railroadId));
    dispatch(cleanGpsList());
    dispatch(clearModelEventList());
    dispatch(clearSpeedHistory());
    dispatch(clearStationHistory());
    dispatch(resetUserInteractTime());
    dispatch(setCurrentSpeed(0));
    dispatch(setTravelDistance(0));
    dispatch(setCurrentMilepost(null));
    dispatch(setAutoCenter(true));
    dispatch(setWaiting(false));
    dispatch(generateRandomTripId());
  };

  const prepareDispatchData = (
    start: string,
    end: string,
    selectedIntermediateStationList: string[],
  ) => {
    const allActiveStations = [start, ...selectedIntermediateStationList, end];
    const dispatchData = allActiveStations
      .map((station, idx) => {
        if (idx !== allActiveStations.length - 1) {
          return {
            startLocationId: station,
            endLocationId: allActiveStations[idx + 1],
          };
        }
      })
      .slice(0, -1);

    const startStationSequenceId = stationListByRouteId?.filter(
      item => item.abbreviation === start,
    )[0].sequence_id;

    const endStationSequenceId = stationListByRouteId?.filter(
      item => item.abbreviation === end,
    )[0].sequence_id;

    const routeDirection =
      startStationSequenceId <= endStationSequenceId ? 'ASC' : 'DESC';

    dispatch(
      setTripDispatchUserInput(dispatchData, selectedRouteId, routeDirection),
    );
  };

  const proceedToNextScreen = async (): Promise<void> => {
    clearTripStates();

    const start = startStationName?.split(' - ')[0];
    const end = endStationName?.split(' - ')[0];

    // Prepare active station list
    const currentActiveList = (
      activeListStationRef as any
    ).current.activeStationsList();

    const selectedIntermediateStationList = intermediateStations
      .filter(item => currentActiveList?.includes(item.abbreviation))
      .map(item => item.abbreviation);

    getDataByStopStations(start, end, selectedIntermediateStationList);

    // Set current trip key
    const currentTripKey =
      selectedIntermediateStationList?.length > 0
        ? start + '-' + selectedIntermediateStationList[0]
        : start + '-' + end;
    dispatch(setCurrentTripKey(currentTripKey));

    // Prepare dispatch Data
    prepareDispatchData(start, end, selectedIntermediateStationList);

    // Set active station list
    const activeIntermediateStationList = selectedIntermediateStationList.map(
      item => {
        const stationData = intermediateStations.find(
          e => e.abbreviation === item,
        );
        return stationData;
      },
    );
    const activeStationList = {
      departure: start,
      destination: end,
      activeStationList: activeIntermediateStationList,
    };

    dispatch(setStationActive(activeStationList));
    setReady(true);
  };

  return (
    <SafeAreaView style={[styles.container]}>
      <Header />
      <KeyboardAwareScrollView
        contentContainerStyle={styles.formContainer}
        keyboardShouldPersistTaps="always"
        extraHeight={150}>
        <ScrollView>
          <View style={styles.formComponent}>
            <Text style={styles.title}>Trip Selection</Text>

            <View style={styles.fieldsWidth}>
              {/* ROUTE ID */}
              <RefactorAutocompleteInput
                textFieldProps={{
                  placeholder: 'Choose Route',
                  value: routeId,
                  setValue: routeId => {
                    setStartStationName('');
                    setEndStationName('');
                    setRouteId(routeId);
                  },
                }}
                label={'ROUTE'}
                data={routeIdDropdownList}
                iconRightShow={!!routeId}
              />

              <View
                style={{
                  display: 'flex',
                  flexDirection: 'row',
                  paddingTop: 24,
                  alignItems: 'flex-start',
                  justifyContent: 'space-between',
                }}>
                {/* VERTICAL ICONS */}
                <View style={styles.iconPath}>
                  {intermediateStations.length > 0 ||
                  validStationPair(
                    startStationName,
                    endStationName,
                    stationNameList,
                  ) ? (
                    <VerticalTripPathList height={370} />
                  ) : (
                    <VerticalTripPath width={18} />
                  )}
                </View>

                <View
                  style={{
                    width: '100%',
                  }}>
                  {/* START STATION */}
                  <RefactorAutocompleteInput
                    textFieldProps={{
                      placeholder: 'Choose Station, Yard, Service Station, etc',
                      value: startStationName,
                      setValue: setStartStationName,
                    }}
                    label="DEPARTURE"
                    data={startStationDropdownList}
                    iconRightShow={!!startStationName}
                    // containerStyles={{marginTop: 32}}
                    isDisabled={
                      !startStationDropdownList ||
                      startStationDropdownList.length === 0
                    }
                  />

                  {/* INTERMEDIATE STATIONS */}
                  {validStationPair(
                    startStationName,
                    endStationName,
                    stationNameList,
                  ) ? (
                    <IntermediateStationList
                      ref={activeListStationRef}
                      intermediateStations={intermediateStations}
                    />
                  ) : (
                    <></>
                  )}

                  {/* END STATION */}
                  <RefactorAutocompleteInput
                    textFieldProps={{
                      placeholder: 'Choose Station, Yard, Service Station, etc',
                      value: endStationName,
                      setValue: setEndStationName,
                    }}
                    label={'DESTINATION'}
                    data={endStationDropdownList}
                    iconRightShow={!!endStationName}
                    containerStyles={{marginTop: 24}}
                    isDisabled={
                      !endStationDropdownList ||
                      endStationDropdownList.length === 0
                    }
                  />
                </View>
              </View>

              {/* CHECKBOXES IN DEV MODE */}
              {envName === 'dev' && <DemoCheckboxes />}
            </View>
          </View>
        </ScrollView>
      </KeyboardAwareScrollView>

      {/* RIGHT NAVIGATION */}
      <View
        style={[
          styles.buttonContainer,
          {
            right: 20,
            top: keyboardStatus
              ? orientation === 'portrait'
                ? (height - 64) / 2 - 140
                : orientation === 'landscape'
                ? (height - 64) / 4
                : 100
              : (height - 64) / 2,
          },
          !validStationPair(startStationName, endStationName, stationNameList)
            ? styles.buttonDisabled
            : null,
        ]}>
        <TouchableOpacity
          onPress={proceedToNextScreen}
          disabled={
            !validStationPair(startStationName, endStationName, stationNameList)
          }
          testID="next-button"
          style={styles.button}>
          <ChevronRight color="#fff" />
        </TouchableOpacity>
      </View>

      {/* NEXT LOADING ICON */}
      {(consistTrainData && modelsLoading) || trackLoading ? (
        <NextLoader width={width} height={height} envName={envName} />
      ) : null}
    </SafeAreaView>
  );
};

export default SelectionTrip;