TrainConsist/index.tsx

 avatar
unknown
typescript
2 years ago
21 kB
6
Indexable
/* eslint-disable react-native/no-inline-styles */
import React, {useCallback, useEffect, useState} from 'react';
import {
  SafeAreaView,
  Text,
  View,
  ScrollView,
  Alert,
  Keyboard,
  useWindowDimensions,
  RefreshControl,
  ActivityIndicator,
} from 'react-native';
import {TouchableOpacity} from 'react-native-gesture-handler';
import {KeyboardAwareScrollView} from 'react-native-keyboard-aware-scroll-view';

// AWS Amplify
import {Auth} from 'aws-amplify';

// Lodash
import isEmpty from 'lodash/isEmpty';

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

// Redux
import {useDispatch, useSelector} from 'react-redux';
import {getOrientation, getActiveEnv} from '@Redux/common/selectors';
import {getUserAuthorizationSelector, getUserTier} from '@Redux/auth/selectors';
import {
  getTrainSelectionInfo,
  getLocoModelList as getLocoModelListSelector,
  getTrainLoading,
} from '@Redux/train/selectors';
import {getModelsLoading} from '@Redux/model/selectors';
import {
  getRouteDirection,
  getRouteId,
  getTripDispatch,
} from '@Redux/trip/selectors';

import {setTrainConsistUserInput, getLocoModelList} from '@Redux/train/actions';
import {clearStopStation} from '@Redux/track/actions';
import {setRunning, setFinished} from '@Redux/common/actions';
import {logout} from '@Redux/auth/actions';
import {clearInstructionGroup} from '@Redux/instruction/actions';
import {getModels} from '@Redux/model/actions';

// Utils
import {tonsToLb} from '@Utils/tonsToLb';

// Components
import InputField from '@Com/InputField';
import {ChevronRight, ChevronDown} from '@Svg';
import Header from '../Header';

// Types
import {UseStateTuple} from '@Types';

// Styles
import styles from './styles';
import {getSimpleTrainConsist} from 'src/redux/trip/actions';

// Constants
import {TIERS} from '@Constants';

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

  const navigation = useNavigation();
  const {width, height} = useWindowDimensions();

  const envName = useSelector(state => getActiveEnv(state));

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

  const tripDispatchData = useSelector(state => getTripDispatch(state));
  const routeId = useSelector(state => getRouteId(state));
  const routeDirection = useSelector(state => getRouteDirection(state));
  const trainInfo = useSelector(state => getTrainSelectionInfo(state));
  const trainLocoLoading = useSelector(state => getTrainLoading(state));
  const locomotiveList = useSelector(state => getLocoModelListSelector(state));

  const userAuthorization = useSelector(state =>
    getUserAuthorizationSelector(state),
  );

  const userTier = useSelector(state => getUserTier(state));
  const shouldHaveRecommendations = userTier === TIERS.FUEL_SAVINGS_MODE;

  const railCarRef = React.useRef();
  const grossWeightRef = React.useRef();
  const totalLengthRef = React.useRef();

  const [locoModel, setLocoModel]: UseStateTuple<string> = useState('');
  /*Refresh*/
  const [refreshing, handleRefreshing] = useState(false);
  useEffect(() => {
    if (!trainLocoLoading && refreshing) {
      handleRefreshing(false);
    }
  }, [trainLocoLoading, refreshing]);
  const handleRefresh = () => {
    handleRefreshing(true);
    dispatch(getLocoModelList(userAuthorization?.railroadId));
  };
  /*End Refresh*/

  const [railCar, setRailCar]: UseStateTuple<string> = useState('');
  const [railCarFocused, setRailCarFocused]: UseStateTuple<boolean> =
    useState(false);

  const [grossWeight, setGrossWeight]: UseStateTuple<string> = useState('');
  const [grossWeightFocused, setGrossWeightFocused]: UseStateTuple<boolean> =
    useState(false);

  const [totalLength, setTotalLength]: UseStateTuple<string> = useState('');
  const [totalLengthFocused, setTotalLengthFocused]: UseStateTuple<boolean> =
    useState(false);

  const [keyboardStatus, setKeyboardStatus]: UseStateTuple<boolean> =
    useState(false);

  const [showLocoModal, setShowLocoModal]: UseStateTuple<boolean> =
    useState(false);
  const [locomotivesNumber, setLocomotivesNumber]: UseStateTuple<number> =
    useState();

  /**** demo-logic ****/
  const numberOfLocomotivesData = [
    {
      value: 1,
      name: '1',
    },
    {
      value: 2,
      name: '2',
    },
    {
      value: 3,
      name: '3',
    },
    {
      value: 4,
      name: '4',
    },
    {
      value: 5,
      name: '5',
    },
  ];

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

  /**** demo-logic ****/

  useEffect(() => {
    const showSubscription = Keyboard.addListener('keyboardDidShow', () =>
      setKeyboardStatus(true),
    );
    const hideSubscription = Keyboard.addListener('keyboardDidHide', () =>
      setKeyboardStatus(false),
    );
    return () => {
      showSubscription.remove();
      hideSubscription.remove();
    };
  }, []);

  useEffect(() => {
    Auth.currentAuthenticatedUser()
      .then(() => {
        console.log('login success');
      })
      .catch(error => {
        console.log('error authenticate', error);
        Alert.alert(
          'Caution!',
          'There is an error with authentication process, please login again.',
          [
            {
              text: 'Go to Login',
              onPress: () => {
                dispatch(setRunning(false));
                dispatch(setFinished(false));
                dispatch(logout());
              },
            },
          ],
          {
            cancelable: false,
          },
        );
      });
  }, []);

  const tryNavigate = useCallback(() => {
    navigation.navigate(ScreensName.MAP, {
      trainID: trainInfo.trainID,
      crewID: trainInfo.crewID,
    });
  }, [navigation]);

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

  const backSelection = (): void => {
    dispatch(clearInstructionGroup());
    dispatch(clearStopStation());
    navigation.goBack();
  };

  const proceedToNextScreen = (): void => {
    const grossWeightInt = parseInt(grossWeight, 10);
    const totalLengthInt = parseInt(totalLength, 10);

    const consistData = {
      locomotiveModel: locoModel,
      locomotiveCount: locomotivesNumber,
      carCount: parseInt(railCar),
      grossWeight: tonsToLb(
        grossWeightInt,
        userAuthorization?.companyId,
      ).toString(),
      totalLengthFt: totalLengthInt,
    };

    const simpleTrainConsistRequestData = {
      ...consistData,
      startLocationId: tripDispatchData[0].startLocationId,
      endLocationId:
        tripDispatchData[tripDispatchData?.length - 1].endLocationId,
      userInputCrewName: trainInfo?.crewID,
      userInputTrainId: trainInfo?.trainID,
      userId: userAuthorization?.userId,
      railroadId: userAuthorization?.railroadId,
      routeId: routeId,
      routeDirection: routeDirection,
    };

    dispatch(setTrainConsistUserInput(consistData));
    dispatch(getSimpleTrainConsist(simpleTrainConsistRequestData));
    if (shouldHaveRecommendations) {
      dispatch(
        getModels(
          parseInt(railCar),
          totalLengthInt * 0.304,
          locomotivesNumber,
          userAuthorization?.railroadId,
          routeDirection,
          routeId,
          tonsToLb(grossWeightInt, userAuthorization?.companyId),
        ),
      );
    }
    setReady(true);
  };

  return (
    <SafeAreaView style={[styles.container]}>
      <Header backAction={backSelection} />
      <KeyboardAwareScrollView
        keyboardShouldPersistTaps="always"
        nestedScrollEnabled
        refreshControl={
          <RefreshControl refreshing={refreshing} onRefresh={handleRefresh} />
        }
        contentContainerStyle={styles.formContainer}
        extraHeight={200}>
        <View style={styles.formComponent}>
          <View style={styles.fieldsContainer}>
            <Text style={styles.title}>Train Consist</Text>
            <View style={styles.inputContent}>
              <View
                style={{
                  position: 'relative',
                  zIndex: 999,
                  opacity: locomotiveList && locomotiveList.length ? 1 : 0.7,
                }}>
                <Text style={styles.label}>{'LEAD LOCOMOTIVE'}</Text>
                <TouchableOpacity
                  disabled={!(locomotiveList && locomotiveList.length)}
                  onPress={() => setShowLocoModal((prev: boolean) => !prev)}
                  testID="lead-locomotive-input"
                  style={styles.locoDropdown}>
                  <Text
                    style={{
                      fontFamily: 'SFProDisplay-Regular',
                      fontSize: 20,
                      lineHeight: 24,
                      color: !isEmpty(locoModel)
                        ? '#626E7B'
                        : locomotiveList && locomotiveList.length === 0
                        ? '#B6BCC3'
                        : !locomotiveList
                        ? '#D73A49'
                        : '#B6BCC3',
                      fontWeight: '600',
                    }}>
                    {!isEmpty(locoModel)
                      ? locoModel
                      : locomotiveList && locomotiveList.length === 0
                      ? 'Choose Lead Locomotive'
                      : !locomotiveList
                      ? 'No locomotive models data!'
                      : 'Choose Lead Locomotive'}
                  </Text>
                  <View
                    style={
                      showLocoModal
                        ? {
                            transform: [{rotate: '180deg'}],
                          }
                        : null
                    }>
                    <ChevronDown />
                  </View>
                </TouchableOpacity>
                {showLocoModal ? (
                  <View
                    style={{
                      width: 460,
                      height:
                        locomotiveList?.length > 4
                          ? 330
                          : locomotiveList?.length > 3
                          ? 266
                          : locomotiveList?.length > 2
                          ? 202
                          : locomotiveList?.length > 1
                          ? 138
                          : 76,
                      backgroundColor: '#FFF',
                      position: 'absolute',
                      top: 120,
                      left: 0,
                      display: 'flex',
                      alignItems: 'center',
                      justifyContent: 'center',
                    }}>
                    <View
                      style={{
                        width: 450,
                        height:
                          locomotiveList?.length > 4
                            ? 330
                            : locomotiveList?.length > 3
                            ? 266
                            : locomotiveList?.length > 2
                            ? 202
                            : locomotiveList?.length > 1
                            ? 138
                            : 76,
                        backgroundColor: '#FFF',
                        shadowColor: '#000',
                        shadowOffset: {
                          width: 0,
                          height: 2,
                        },
                        shadowOpacity: 0.25,
                        shadowRadius: 3.84,
                        elevation: 5,
                        borderRadius: 6,
                      }}>
                      <ScrollView
                        style={{
                          flex: 1,
                        }}>
                        {locomotiveList && locomotiveList.length
                          ? locomotiveList?.map(
                              (item: any, index: number): JSX.Element => {
                                return (
                                  <TouchableOpacity
                                    key={item?.locomotive_id}
                                    onPress={() => {
                                      setLocoModel(item?.locomotive_id);
                                      setShowLocoModal(false);
                                    }}
                                    testID={`lead-locomotive-option-${index}`}
                                    style={{
                                      width: '100%',
                                      height: 64,
                                      display: 'flex',
                                      alignItems: 'center',
                                      justifyContent: 'center',
                                    }}>
                                    <Text
                                      style={{
                                        textAlign: 'left',
                                        width: '100%',
                                        paddingHorizontal: 16,
                                      }}
                                      numberOfLines={1}>
                                      {item?.locomotive_id}
                                    </Text>
                                  </TouchableOpacity>
                                );
                              },
                            )
                          : null}
                      </ScrollView>
                    </View>
                  </View>
                ) : null}
              </View>
              <Text style={styles.label}>{'NUMBER OF LOCOMOTIVES'}</Text>
              <View style={styles.buttonNumbersContainer}>
                {numberOfLocomotivesData.map(
                  (item: {value: number; name: string}, index: number) => {
                    return (
                      <TouchableOpacity
                        key={item?.value}
                        onPress={() => setLocomotivesNumber(item.value)}
                        testID={`locomotive-number-${item.name}-${
                          item.value === locomotivesNumber
                        }`}
                        style={{
                          display: 'flex',
                          alignItems: 'center',
                          justifyContent: 'center',
                          width: 92,
                          height: 64,
                          backgroundColor:
                            item.value === locomotivesNumber
                              ? '#DDEEFF'
                              : '#EEF2F7',
                          margin: 1,
                          borderTopLeftRadius: index === 0 ? 4 : 0,
                          borderBottomLeftRadius: index === 0 ? 4 : 0,
                          borderTopRightRadius:
                            index === numberOfLocomotivesData.length - 1
                              ? 4
                              : 0,
                          borderBottomRightRadius:
                            index === numberOfLocomotivesData.length - 1
                              ? 4
                              : 0,
                        }}>
                        <Text
                          style={{
                            color:
                              item.value === locomotivesNumber
                                ? '#286ED7'
                                : '#97A1AA',
                          }}>
                          {item.name}
                        </Text>
                      </TouchableOpacity>
                    );
                  },
                )}
              </View>

              <InputField
                ref={railCarRef}
                onFocus={() => {
                  setRailCarFocused(true);
                }}
                onBlur={() => {
                  setRailCarFocused(false);
                }}
                containerStyle={styles.inputItem}
                labelStyle={styles.labelInput}
                inputStyle={[
                  styles.inputStyle,
                  {
                    borderWidth: 0.5,
                    borderColor: railCarFocused ? '#D3D3D3' : 'transparent',
                  },
                ]}
                placeholderTextColor={'#B6BCC3'}
                value={railCar}
                onTextChange={(text: string) => {
                  if (text.length && !/^[0-9]+$/.test(text)) {
                    return;
                  }
                  if (parseInt(text, 10) > 999) {
                    Alert.alert(
                      'Number of rail cars cannot be greater than 999!',
                    );
                    return;
                  }
                  setRailCar(text);
                }}
                hasClearIcon={railCar?.length}
                onClearAction={() => setRailCar('')}
                label={'NUMBER OF RAIL CARS'}
                placeholder={'Enter number of rail cars'}
                keyboardType="number-pad"
              />

              <InputField
                ref={grossWeightRef}
                onFocus={() => {
                  setGrossWeightFocused(true);
                }}
                onBlur={() => {
                  setGrossWeightFocused(false);
                }}
                containerStyle={styles.inputItem}
                labelStyle={styles.labelInput}
                inputStyle={[
                  styles.inputStyle,
                  {
                    borderWidth: 0.5,
                    borderColor: grossWeightFocused ? '#D3D3D3' : 'transparent',
                  },
                ]}
                placeholderTextColor={'#B6BCC3'}
                value={grossWeight}
                onTextChange={(text: string) => {
                  if (text.length && !/^[0-9]+$/.test(text)) {
                    return;
                  }

                  if (parseInt(text, 10) > 25000) {
                    Alert.alert(
                      'The total gross weight cannot be greater than 25,000t!',
                    );
                    return;
                  }

                  setGrossWeight(text);
                }}
                hasClearIcon={grossWeight?.length}
                onClearAction={() => setGrossWeight('')}
                label={'TOTAL GROSS WEIGHT IN TONS'}
                placeholder={'Enter total gross weight in tons'}
                keyboardType="number-pad"
              />

              <InputField
                ref={totalLengthRef}
                onFocus={() => {
                  setTotalLengthFocused(true);
                }}
                onBlur={() => {
                  setTotalLengthFocused(false);
                }}
                containerStyle={styles.inputItem}
                labelStyle={styles.labelInput}
                inputStyle={[
                  styles.inputStyle,
                  {
                    borderWidth: 0.5,
                    borderColor: totalLengthFocused ? '#D3D3D3' : 'transparent',
                  },
                ]}
                placeholderTextColor={'#B6BCC3'}
                value={totalLength}
                onTextChange={(text: string) => {
                  if (text.length && !/^[0-9]+$/.test(text)) {
                    return;
                  }

                  if (parseInt(text, 10) > 20000) {
                    Alert.alert(
                      'The total length cannot be greater than 20,000ft!',
                    );
                    return;
                  }

                  setTotalLength(text);
                }}
                hasClearIcon={totalLength?.length}
                onClearAction={() => setTotalLength('')}
                label={'TOTAL LENGTH IN FEET'}
                placeholder={'Enter total length in feet'}
                keyboardType="number-pad"
              />
            </View>
          </View>
        </View>
      </KeyboardAwareScrollView>
      <View
        style={[
          styles.buttonContainer,
          !locoModel ||
          !railCar ||
          !grossWeight ||
          !locomotivesNumber ||
          !totalLength
            ? styles.buttonDisabled
            : null,
        ]}>
        <TouchableOpacity
          onPress={proceedToNextScreen}
          disabled={
            !locoModel ||
            !railCar ||
            !grossWeight ||
            !locomotivesNumber ||
            !totalLength ||
            !tripDispatchData
          }
          testID="next-button"
          style={styles.button}>
          <ChevronRight color="#FFF" />
        </TouchableOpacity>
      </View>
      {modelsLoading ? <NextLoader /> : null}
    </SafeAreaView>
  );
};

export default TrainConsist;
Editor is loading...