Skip to content

Commit

Permalink
Merge pull request #55 from yeukfei02/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
yeukfei02 authored May 3, 2022
2 parents 6e2835b + 289e5d3 commit 7f06abf
Show file tree
Hide file tree
Showing 8 changed files with 598 additions and 73 deletions.
6 changes: 3 additions & 3 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Singapore Bus Arrival App",
"slug": "singapore-bus-arrival-app",
"platforms": ["ios", "android"],
"version": "0.3.5",
"version": "0.3.6",
"orientation": "portrait",
"icon": "./assets/appstore-icon.png",
"splash": {
Expand All @@ -17,7 +17,7 @@
"assetBundlePatterns": ["**/*"],
"ios": {
"bundleIdentifier": "com.donaldwu.singaporebusarrivalapp",
"buildNumber": "0.3.5",
"buildNumber": "0.3.6",
"infoPlist": {
"NSLocationWhenInUseUsageDescription": "Singapore Bus Arrival App requires your location so that we can find related bus arrival information for you",
"NSLocationAlwaysUsageDescription": "Singapore Bus Arrival App requires your location so that we can find related bus arrival information for you",
Expand All @@ -28,7 +28,7 @@
},
"android": {
"package": "com.donaldwu.singaporebusarrivalapp",
"versionCode": 36,
"versionCode": 37,
"permissions": ["ACCESS_COARSE_LOCATION", "ACCESS_FINE_LOCATION"]
},
"description": "Singpaore Bus Arrival App",
Expand Down
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;
Loading

0 comments on commit 7f06abf

Please sign in to comment.