Skip to content

Commit

Permalink
feat: 🎸 add busServiceRoutes page
Browse files Browse the repository at this point in the history
  • Loading branch information
yeukfei02 committed May 3, 2022
1 parent d4d57d4 commit 6d05aa1
Show file tree
Hide file tree
Showing 7 changed files with 595 additions and 70 deletions.
4 changes: 3 additions & 1 deletion src/components/busArrivalDetails/BusArrivalDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ function BusArrivalDetails(props: any): JSX.Element {

const handleBusNumberClick = (busNumber: string) => {
if (busNumber) {
console.log('busNumber = ', busNumber);
props.navigation.navigate(`BusServiceRoutes`, {
busServiceNo: busNumber,
});
}
};

Expand Down
301 changes: 301 additions & 0 deletions src/components/busServiceRoutes/BusServiceRoutes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, ScrollView, View, RefreshControl, TouchableOpacity, Platform, Linking } from 'react-native';
import { MaterialIcons } from '@expo/vector-icons';
import { gql, useLazyQuery } from '@apollo/client';
import { useRoute } from '@react-navigation/native';
import { Switch } from 'react-native-paper';

import { getAsyncStorageData } from '../../helpers/helpers';
import _ from 'lodash';

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'white',
},
viewContainer: {
marginVertical: 65,
marginHorizontal: 30,
},
noDataContainer: {
backgroundColor: 'gainsboro',
padding: 20,
borderRadius: 5,
},
loadingContainer: {
backgroundColor: 'moccasin',
padding: 20,
borderRadius: 5,
},
errorContainer: {
backgroundColor: 'tomato',
padding: 20,
borderRadius: 5,
},
busServiceRoutesContainer: {
backgroundColor: 'gainsboro',
padding: 20,
borderRadius: 5,
marginVertical: 10,
},
});

const GET_BUS_ROUTE_BY_BUS_SERVICE_NO = gql`
query busRouteByBusServiceNo($busServiceNo: String!) {
busRouteByBusServiceNo(busServiceNo: $busServiceNo) {
serviceNo
operator
direction
stopSequence
busStopCode
busStop {
busStopCode
roadName
description
latitude
longitude
}
distance
wdFirstBus
wdLastBus
satFirstBus
satLastBus
sunFirstBus
sunLastBus
}
}
`;

function BusServiceRoutes(props: any): JSX.Element {
const route = useRoute();

const [refreshing, setRefreshing] = useState(false);

const [theme, setTheme] = useState('light');

const [isSwitchOn, setIsSwitchOn] = useState(true);

const [responseData, setResponseData] = useState<any>(null);

const [getBusRouteByBusServiceNo, { loading, error, data, client }] = useLazyQuery(GET_BUS_ROUTE_BY_BUS_SERVICE_NO);

console.log('loading = ', loading);
console.log('error = ', error);
console.log('data = ', data);

useEffect(() => {
getThemeData();
props.navigation.addListener('focus', () => {
getThemeData();
});
}, []);

useEffect(() => {
if (route.params) {
const busServiceNo = (route.params as any).busServiceNo;
getBusRouteByBusServiceNo({
variables: { busServiceNo: busServiceNo },
});
}
}, [route.params]);

useEffect(() => {
if (data) {
setResponseData(data);
}
}, [data]);

const getThemeData = async () => {
const theme = await getAsyncStorageData('@theme');
if (theme) {
setTheme(theme);
}
};

const onRefresh = async () => {
setRefreshing(true);

getThemeData();
client?.clearStore();
setResponseData(null);
if (route.params) {
const busServiceNo = (route.params as any).busServiceNo;
getBusRouteByBusServiceNo({
variables: { busServiceNo: busServiceNo },
});
}

if (!loading) {
setRefreshing(false);
}
};

const onToggleSwitch = () => {
if (isSwitchOn) {
setIsSwitchOn(false);
} else {
setIsSwitchOn(true);
}
};

const handleBackButtonClick = () => {
props.navigation.goBack();
};

const renderBusServiceRoutesResultDiv = () => {
let busServiceRoutesResultDiv = (
<View style={styles.noDataContainer}>
<Text>There is no data</Text>
</View>
);

if (loading) {
busServiceRoutesResultDiv = (
<View style={styles.loadingContainer}>
<Text>Loading...</Text>
</View>
);
} else {
if (error) {
busServiceRoutesResultDiv = (
<View style={styles.errorContainer}>
<Text>There is error</Text>
</View>
);
} else {
if (responseData && responseData.busRouteByBusServiceNo) {
const groupedBusRouteByBusServiceNo = _.groupBy(responseData.busRouteByBusServiceNo, 'direction');

busServiceRoutesResultDiv = (
<View>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<Switch value={isSwitchOn} onValueChange={onToggleSwitch} color="tomato" />
<Text
style={{
fontSize: 20,
color: theme === 'light' ? 'black' : 'white',
marginLeft: 8,
}}
>
{isSwitchOn ? `Inbound` : `Outbound`}
</Text>
</View>

{renderBusServiceRoutesList(isSwitchOn, groupedBusRouteByBusServiceNo)}
</View>
);
}
}
}

return busServiceRoutesResultDiv;
};

const renderBusServiceRoutesList = (isSwitchOn: boolean, groupedBusRouteByBusServiceNo: any) => {
let busServiceRoutesList = null;

if (isSwitchOn) {
const inboundList = groupedBusRouteByBusServiceNo['1'];
if (inboundList) {
busServiceRoutesList = inboundList.map((item: any, i: number) => {
if (item.busStop) {
return (
<View key={i} style={styles.busServiceRoutesContainer}>
<Text style={{ fontSize: 20, fontWeight: 'bold', marginVertical: 8 }}>{item.stopSequence}</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginVertical: 6 }}>
Bus Stop Code: {item.busStop.busStopCode}
</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginVertical: 6 }}>
Road Name: {item.busStop.roadName}
</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginVertical: 6 }}>
Description: {item.busStop.description}
</Text>
<TouchableOpacity
onPress={() => handleCheckBusStopInMap(item.busStop.latitude, item.busStop.longitude)}
>
<Text style={{ color: 'blue', textDecorationLine: 'underline', marginVertical: 5 }}>
Check bus stop in map
</Text>
</TouchableOpacity>
</View>
);
}
});
}
} else {
const outboundList = groupedBusRouteByBusServiceNo['2'];
if (outboundList) {
busServiceRoutesList = outboundList.map((item: any, i: number) => {
if (item.busStop) {
return (
<View key={i} style={styles.busServiceRoutesContainer}>
<Text style={{ fontSize: 20, fontWeight: 'bold', marginVertical: 8 }}>{item.stopSequence}</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginVertical: 6 }}>
Bus Stop Code: {item.busStop.busStopCode}
</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginVertical: 6 }}>
Road Name: {item.busStop.roadName}
</Text>
<Text style={{ fontSize: 18, fontWeight: 'bold', marginVertical: 6 }}>
Description: {item.busStop.description}
</Text>
<TouchableOpacity
onPress={() => handleCheckBusStopInMap(item.busStop.latitude, item.busStop.longitude)}
>
<Text style={{ color: 'blue', textDecorationLine: 'underline', marginVertical: 5 }}>
Check bus stop in map
</Text>
</TouchableOpacity>
</View>
);
}
});
}
}

return busServiceRoutesList;
};

const handleCheckBusStopInMap = (latitude: number, longitude: number) => {
const scheme = Platform.select({ ios: 'maps:0,0?q=', android: 'geo:0,0?q=' });
const latLng = `${latitude},${longitude}`;
const label = 'Bus stop';
const url = Platform.select({
ios: `${scheme}${label}@${latLng}`,
android: `${scheme}${latLng}(${label})`,
});

if (url) {
Linking.openURL(url);
}
};

return (
<ScrollView
style={{ flex: 1, backgroundColor: theme === 'light' ? 'white' : 'black' }}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} colors={['tomato', 'tomato', 'black']} />
}
contentContainerStyle={{ flexGrow: 1 }}
>
<View style={styles.viewContainer}>
<TouchableOpacity onPress={() => handleBackButtonClick()}>
<MaterialIcons name="arrow-back" size={24} color={theme === 'light' ? 'black' : 'white'} />
</TouchableOpacity>

<View style={{ marginVertical: 15 }}></View>

<Text style={{ fontSize: 25, fontWeight: 'bold', color: theme === 'light' ? 'black' : 'white' }}>
Bus Service Routes
</Text>

<View style={{ marginVertical: 10 }}></View>

{renderBusServiceRoutesResultDiv()}
</View>
</ScrollView>
);
}

export default BusServiceRoutes;
49 changes: 49 additions & 0 deletions src/components/customRadioButton/CustomRadioButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { Text, View } from 'react-native';

function CustomRadioButton(props: any): JSX.Element {
return (
<View
style={{
flex: 1,
backgroundColor: props.theme === 'light' ? 'white' : 'black',
flexDirection: 'row',
alignItems: 'center',
marginBottom: 20,
}}
>
<View
style={[
{
height: 24,
width: 24,
borderRadius: 12,
borderWidth: 2,
borderColor: props.theme === 'light' ? 'black' : 'white',
alignItems: 'center',
justifyContent: 'center',
},
props.style,
]}
>
{props.checked ? (
<View
style={{
height: 12,
width: 12,
borderRadius: 6,
backgroundColor: props.theme === 'light' ? 'black' : 'white',
}}
/>
) : null}
</View>
<Text
style={{ fontSize: 14, fontWeight: 'bold', color: props.theme === 'light' ? 'black' : 'white', marginLeft: 8 }}
>
{props.text}
</Text>
</View>
);
}

export default CustomRadioButton;
2 changes: 2 additions & 0 deletions src/components/favouritesView/FavouritesView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createStackNavigator } from '@react-navigation/stack';

import Favourites from '../favourites/Favourites';
import BusArrivalDetails from '../busArrivalDetails/BusArrivalDetails';
import BusServiceRoutes from '../busServiceRoutes/BusServiceRoutes';

const Stack = createStackNavigator();

Expand All @@ -13,6 +14,7 @@ function FavouritesView(): JSX.Element {
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="Favourites" component={Favourites} />
<Stack.Screen name="BusArrivalDetails" component={BusArrivalDetails} />
<Stack.Screen name="BusServiceRoutes" component={BusServiceRoutes} />
</Stack.Navigator>
</NavigationContainer>
);
Expand Down
2 changes: 2 additions & 0 deletions src/components/nearMeView/NearMeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createStackNavigator } from '@react-navigation/stack';

import NearMe from '../nearMe/NearMe';
import BusArrivalDetails from '../busArrivalDetails/BusArrivalDetails';
import BusServiceRoutes from '../busServiceRoutes/BusServiceRoutes';

const Stack = createStackNavigator();

Expand All @@ -13,6 +14,7 @@ function NearMeView(): JSX.Element {
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name="NearMe" component={NearMe} />
<Stack.Screen name="BusArrivalDetails" component={BusArrivalDetails} />
<Stack.Screen name="BusServiceRoutes" component={BusServiceRoutes} />
</Stack.Navigator>
</NavigationContainer>
);
Expand Down
Loading

0 comments on commit 6d05aa1

Please sign in to comment.