TrainConsist/index.tsx
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...