Skip to content

Commit

Permalink
feat: 🎸 add bus map view
Browse files Browse the repository at this point in the history
  • Loading branch information
yeukfei02 committed Oct 24, 2021
1 parent 5932657 commit d84b81a
Show file tree
Hide file tree
Showing 7 changed files with 324 additions and 1 deletion.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.0.tar.gz",
"react-native-gesture-handler": "~1.8.0",
"react-native-maps": "^0.29.3",
"react-native-paper": "^4.3.1",
"react-native-reanimated": "~1.13.0",
"react-native-safe-area-context": "3.1.9",
Expand Down
15 changes: 14 additions & 1 deletion src/components/busArrivalDetails/BusArrivalDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ function BusArrivalDetails(props: any): JSX.Element {
props.navigation.goBack();
};

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

const renderBusArrivalResultDiv = () => {
let busArrivalResultDiv = (
<View style={styles.noDataContainer}>
Expand Down Expand Up @@ -193,7 +201,12 @@ function BusArrivalDetails(props: any): JSX.Element {
return (
<View key={i} style={styles.busArrivalResultContainer}>
<View style={styles.busArrivalResultHeaderContainer}>
<Text style={{ fontSize: 20, fontWeight: 'bold' }}>{item.busNumber}</Text>
<Text
style={{ fontSize: 20, fontWeight: 'bold', textDecorationLine: 'underline' }}
onPress={() => handleBusNumberClick(item.busNumber)}
>
{item.busNumber}
</Text>
<Text style={{ fontSize: 15, fontWeight: 'bold' }}>{firstBusTimeDiffStr}</Text>
</View>
<Text style={{ marginVertical: 15 }}>{item.operator}</Text>
Expand Down
291 changes: 291 additions & 0 deletions src/components/busMapView/BusMapView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, ScrollView, View, TouchableOpacity, RefreshControl, Dimensions } from 'react-native';
import { MaterialIcons } from '@expo/vector-icons';
import { useRoute } from '@react-navigation/native';
import MapView, { Marker, Polyline } from 'react-native-maps';

import { gql, useLazyQuery } from '@apollo/client';

import { getAsyncStorageData } from '../../common/common';

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,
},
mapContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
map: {
width: Dimensions.get('window').width,
height: Dimensions.get('window').height,
},
});

const GET_BUS_SERVICE_BY_BUS_SERVICE_NO = gql`
query busServiceByBusServiceNo($busServiceNo: String!) {
busServiceByBusServiceNo(busServiceNo: $busServiceNo) {
serviceNo
operator
direction
category
originCode
originBusStop {
busStopCode
roadName
description
latitude
longitude
}
destinationCode
destinationBusStop {
busStopCode
roadName
description
latitude
longitude
}
amPeakFreq
amOffpeakFreq
pmPeakFreq
pmOffpeakFreq
loopDesc
}
}
`;

const singaporeLatitude = 1.3521;
const singaporeLongitude = 103.8198;

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

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

const [region, setRegion] = useState({
latitude: singaporeLatitude,
longitude: singaporeLongitude,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
});

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

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

const [getBusServiceByBusServiceNo, { loading, error, data, client }] = useLazyQuery(
GET_BUS_SERVICE_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;
getBusServiceByBusServiceNo({
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 = () => {
setRefreshing(true);

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

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

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

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

if (loading) {
busMapViewResultDiv = (
<View style={styles.loadingContainer}>
<Text>Loading...</Text>
</View>
);
} else {
if (error) {
busMapViewResultDiv = (
<View style={styles.errorContainer}>
<Text>There is error</Text>
</View>
);
} else {
if (responseData && responseData.busServiceByBusServiceNo) {
const markerList: any[] = [];
const coordinatesList: any[] = [];

responseData.busServiceByBusServiceNo.forEach((item: any, i: number) => {
if (item.originBusStop && item.destinationBusStop) {
if (item.direction === 1) {
setData(item, markerList, coordinatesList);
}
}
});

busMapViewResultDiv = (
<View style={styles.mapContainer}>
<MapView style={styles.map} region={region} showsUserLocation={true} followsUserLocation={true}>
{renderMarkers(markerList)}
{renderPolyline(coordinatesList)}
</MapView>
</View>
);
}
}
}

return busMapViewResultDiv;
};

const setData = (item: any, markerList: any[], coordinatesList: any[]) => {
// marker
const originBusStopLatLng = {
title: item.originBusStop.roadName,
description: item.originBusStop.description,
latlng: {
latitude: item.originBusStop.latitude,
longitude: item.originBusStop.longitude,
},
};
markerList.push(originBusStopLatLng);

const destinationBusStopLatLng = {
title: item.destinationBusStop.roadName,
description: item.destinationBusStop.description,
latlng: {
latitude: item.destinationBusStop.latitude,
longitude: item.destinationBusStop.longitude,
},
};
markerList.push(destinationBusStopLatLng);

// coordinates
const originBusStopCoordinates = {
latitude: item.originBusStop.latitude,
longitude: item.originBusStop.longitude,
};
coordinatesList.push(originBusStopCoordinates);

const destinationBusStopCoordinates = {
latitude: item.destinationBusStop.latitude,
longitude: item.destinationBusStop.longitude,
};
coordinatesList.push(destinationBusStopCoordinates);
};

const renderMarkers = (markerList: any[]) => {
let markers: any[] = [];

if (markerList) {
markers = markerList.map((marker: any, i: number) => {
return <Marker key={i} coordinate={marker.latlng} title={marker.title} description={marker.description} />;
});
}

return markers;
};

const renderPolyline = (coordinatesList: any[]) => {
const polyline = (
<Polyline
coordinates={coordinatesList}
strokeColor="#FF6347" // fallback for when `strokeColors` is not supported by the map-provider
strokeColors={['tomato']}
strokeWidth={5}
/>
);
return polyline;
};

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 Map View
</Text>

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

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

export default BusMapView;
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 BusMapView from '../busMapView/BusMapView';

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="BusMapView" component={BusMapView} />
</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 BusMapView from '../busMapView/BusMapView';

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="BusMapView" component={BusMapView} />
</Stack.Navigator>
</NavigationContainer>
);
Expand Down
2 changes: 2 additions & 0 deletions src/components/searchView/SearchView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createStackNavigator } from '@react-navigation/stack';

import Search from '../search/Search';
import BusArrivalDetails from '../busArrivalDetails/BusArrivalDetails';
import BusMapView from '../busMapView/BusMapView';

const Stack = createStackNavigator();

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

0 comments on commit d84b81a

Please sign in to comment.