TrainConsist/index.tsx
unknown
typescript
2 years ago
21 kB
10
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...