Skip to content

Commit 660f4bb

Browse files
authored
Merge pull request #25 from AdvancedSoftwareEngineeringGroup3/sust/route-em
Sust/route em --- sustainability dashboard, and some tests
2 parents f30381c + 198b346 commit 660f4bb

9 files changed

Lines changed: 457 additions & 8 deletions

File tree

client/App.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { NavigationContainer } from '@react-navigation/native';
44
import LoginScreen from './LogIn';
55
import MapScreen from './Map';
66
import WeatherScreen from './Weather';
7+
import Dashboard from './SustainabilityDashboard'
78

89
const Stack = createNativeStackNavigator();
910

@@ -14,6 +15,7 @@ export default function App() {
1415
<Stack.Screen name="Map" component={MapScreen} />
1516
<Stack.Screen name="LoginScreen" component={LoginScreen} />
1617
<Stack.Screen name="WeatherScreen" component={WeatherScreen} />
18+
<Stack.Screen name="Dashboard" component={Dashboard} />
1719
</Stack.Navigator>
1820
</NavigationContainer>
1921
);

client/Map.js

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef } from 'react';
22
import { StyleSheet, View, Text, TouchableOpacity, Alert, Platform } from 'react-native';
33
import MapView, { Marker } from 'react-native-maps';
44
import * as Location from 'expo-location';
5+
import Dashboard from './SustainabilityDashboard';
56

67
export default function MapScreen({ navigation }) {
78
const [webSocket, setWebSocket] = useState(null);
@@ -129,13 +130,19 @@ export default function MapScreen({ navigation }) {
129130
<Text style={styles.buttonText}>Send Location</Text>
130131
</TouchableOpacity>
131132
<TouchableOpacity
132-
style={styles.TouchableOpacity}
133+
style={styles.loginButton}
133134
onPress={() => navigation.navigate('LoginScreen')}
134135
>
135136
<Text style={styles.buttonText}>Log In</Text>
136137
</TouchableOpacity>
137138
<TouchableOpacity
138-
style={styles.TouchableOpacity1}
139+
style={styles.dashboardButton}
140+
onPress={() => navigation.navigate('Dashboard')}
141+
>
142+
<Text style={styles.buttonText}>Sustainability Dashboard</Text>
143+
</TouchableOpacity>
144+
<TouchableOpacity
145+
style={styles.weatherButton}
139146
onPress={() => navigation.navigate('WeatherScreen')}
140147
>
141148
<Text style={styles.buttonText}>Weather</Text>
@@ -158,8 +165,8 @@ const styles = StyleSheet.create({
158165
},
159166
sendButton: {
160167
position: 'absolute',
161-
bottom: 20,
162-
left: '50%',
168+
bottom: 15,
169+
left: '80%',
163170
transform: [{ translateX: -50 }],
164171
backgroundColor: '#007bff',
165172
paddingVertical: 10,
@@ -171,7 +178,7 @@ const styles = StyleSheet.create({
171178
fontWeight: 'bold',
172179
textAlign: 'center',
173180
},
174-
TouchableOpacity: {
181+
loginButton: {
175182
position: 'absolute',
176183
alignItems: 'center',
177184
left: '70%',
@@ -186,7 +193,7 @@ const styles = StyleSheet.create({
186193
shadowRadius: 5,
187194
elevation: 5,
188195
},
189-
TouchableOpacity1: {
196+
weatherButton: {
190197
position: 'absolute',
191198
alignItems: 'center',
192199
left: '0%',
@@ -201,6 +208,21 @@ const styles = StyleSheet.create({
201208
shadowRadius: 5,
202209
elevation: 5,
203210
},
211+
dashboardButton: {
212+
position: 'absolute',
213+
alignItems: 'center',
214+
left: '0%',
215+
top: '93%',
216+
backgroundColor: '#007bff',
217+
paddingVertical: 10,
218+
paddingHorizontal: 10,
219+
borderRadius: 10,
220+
shadowColor: '#000',
221+
shadowOpacity: 0.2,
222+
shadowOffset: { width: 0, height: 2 },
223+
shadowRadius: 5,
224+
elevation: 5,
225+
},
204226
error: {
205227
flex: 1,
206228
textAlign: 'center',

client/SustainabilityDashboard.js

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
import {
2+
LineChart,
3+
PieChart
4+
} from "react-native-chart-kit";
5+
import { StyleSheet, TouchableOpacity, Text } from 'react-native';
6+
7+
// Dummy pie chart data
8+
const data = [
9+
{
10+
name: "Bus",
11+
emissions: 20,
12+
color: "#e0ac2b",
13+
legendFontColor: "#7F7F7F",
14+
legendFontSize: 15
15+
},
16+
{
17+
name: "Luas",
18+
emissions: 34,
19+
color: "#e85252",
20+
legendFontColor: "#7F7F7F",
21+
legendFontSize: 15
22+
},
23+
{
24+
name: "Train",
25+
emissions: 28,
26+
color: "#6689c6",
27+
legendFontColor: "#7F7F7F",
28+
legendFontSize: 15
29+
},
30+
{
31+
name: "Walk",
32+
emissions: 45,
33+
color: "#9a6fb0",
34+
legendFontColor: "#7F7F7F",
35+
legendFontSize: 15
36+
},
37+
{
38+
name: "Cycle",
39+
emissions: 75,
40+
color: "#a53253",
41+
legendFontColor: "#7F7F7F",
42+
legendFontSize: 15
43+
}
44+
];
45+
46+
// Dummy line chart data - year
47+
const yearData_lineGraph = {
48+
labels: ["January", "February", "March", "April", "May", "June"],
49+
datasets: [
50+
{
51+
data: [455, 896, 231, 473, 147, 369],
52+
color: (opacity = 1) => `rgba(7, 32, 114, ${opacity})`,
53+
strokeWidth: 2
54+
}
55+
],
56+
legend: ["Rainy Days"],
57+
};
58+
59+
// Dummy line chart data - month
60+
const monthData_lineGraph = {
61+
labels: ["Week 1", "Week 2", "Week 3", "Week 4"],
62+
datasets: [
63+
{
64+
data: [20, 45, 28, 80],
65+
color: (opacity = 1) => `rgba(7, 32, 114, ${opacity})`,
66+
strokeWidth: 2
67+
}
68+
],
69+
legend: ["Rainy Days"],
70+
};
71+
72+
// chart configuration (for chart kit)
73+
const chartConfig = {
74+
backgroundGradientFrom: "#1E2923",
75+
backgroundGradientFromOpacity: 0,
76+
backgroundGradientTo: "#08130D",
77+
backgroundGradientToOpacity: 0,
78+
color: (opacity = 1) => `rgba(91, 87, 89, ${opacity})`,
79+
strokeWidth: 2,
80+
useShadowColorFromDataset: false
81+
};
82+
83+
export default function Dashboard({ navigation }) {
84+
// this needs to be updated reactively, perhaps using usestate
85+
let lineGraphData = yearData_lineGraph;
86+
87+
const switchTimeframe = (time_frame) => {
88+
89+
if (time_frame == 'm'){
90+
lineGraphData = monthData_lineGraph;
91+
}
92+
else if(time_frame == 'y'){
93+
lineGraphData = yearData_lineGraph;
94+
}
95+
};
96+
97+
return (
98+
<>
99+
<PieChart
100+
data={data}
101+
width={370}
102+
height={240}
103+
chartConfig={chartConfig}
104+
accessor={"emissions"}
105+
backgroundColor={"transparent"}
106+
paddingLeft={"15"}
107+
center={[10, 0]}
108+
absolute
109+
/>
110+
<LineChart
111+
style={styles.lineChart}
112+
data={lineGraphData}
113+
width={370}
114+
height={220}
115+
chartConfig={chartConfig}
116+
/>
117+
<TouchableOpacity style={styles.monthButton} onPress={switchTimeframe('m')}>
118+
<Text style={styles.buttonText}>Month</Text>
119+
</TouchableOpacity>
120+
<TouchableOpacity style={styles.yearButton} onPress={switchTimeframe('y')}>
121+
<Text style={styles.buttonText}>Year</Text>
122+
</TouchableOpacity>
123+
</>
124+
)
125+
}
126+
127+
const styles = StyleSheet.create({
128+
lineChart: {
129+
position: 'absolute',
130+
bottom: 40,
131+
right: '0%',
132+
paddingVertical: 10,
133+
paddingHorizontal: 20,
134+
borderRadius: 10,
135+
},
136+
monthButton: {
137+
position: 'absolute',
138+
bottom: 15,
139+
left: '80%',
140+
transform: [{ translateX: -50 }],
141+
backgroundColor: '#007bff',
142+
paddingVertical: 10,
143+
paddingHorizontal: 20,
144+
borderRadius: 10,
145+
},
146+
yearButton: {
147+
position: 'absolute',
148+
bottom: 15,
149+
left: '20%',
150+
transform: [{ translateX: -50 }],
151+
backgroundColor: '#007bff',
152+
paddingVertical: 10,
153+
paddingHorizontal: 20,
154+
borderRadius: 10,
155+
}
156+
})
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from '@react-native-async-storage/async-storage/jest/async-storage-mock';
2+

client/caching.jsx

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import AsyncStorage from '@react-native-async-storage/async-storage';
2+
3+
export const storeData = async (key, data) => {
4+
try {
5+
await AsyncStorage.setItem(
6+
JSON.stringify(key),
7+
JSON.stringify(data),
8+
);
9+
} catch (error) {
10+
console.error('Error storing data in cache');
11+
}
12+
};
13+
14+
export const retrieveData = async (key) => {
15+
try {
16+
const value = await AsyncStorage.getItem(JSON.stringify(key));
17+
if (value !== null) {
18+
console.log(value);
19+
return value != null ? JSON.parse(value) : null;
20+
}
21+
} catch (error) {
22+
console.error('Error retrieving data from cache')
23+
}
24+
};
25+
26+
export const removeData = async (key) => {
27+
try {
28+
await AsyncStorage.removeItem(JSON.stringify(key));
29+
console.log('Removed successfully');
30+
} catch {
31+
console.error('Error removing data from cache')
32+
}
33+
};
34+
35+
export const updateData = async (key, changedData) => {
36+
try {
37+
AsyncStorage.mergeItem(
38+
JSON.stringify(key),
39+
JSON.stringify(changedData)
40+
);
41+
} catch (error) {
42+
console.error('Error updating data in cache');
43+
}
44+
};
45+
46+
/*
47+
weekly emisions
48+
49+
{
50+
"sustScore": 0,
51+
"distanceTravelledPerVehicle": { // running total
52+
"bus": 0,
53+
"car": 0,
54+
"luas": 0,
55+
"train": 0,
56+
"bike": 0,
57+
"walking": 0
58+
},
59+
"last7daysEmmisions": { // at midnight, each day gets replaced by the day value before it. today replaced with 0
60+
"today": 0,
61+
"t-1": 0,
62+
"t-2": 0,
63+
"t-3": 0,
64+
"t-4": 0,
65+
"t-5": 0,
66+
"t-6": 0
67+
},
68+
"lastYear": { // at mifnight each days total added to it's month, at new month reset to 0
69+
"jan": 0,
70+
"feb": 0,
71+
"mar": 0,
72+
"apr": 0,
73+
"may": 0,
74+
"jun": 0,
75+
"jul": 0,
76+
"aug": 0,
77+
"sep": 0,
78+
"oct": 0,
79+
"nov": 0,
80+
"dec": 0
81+
}
82+
}
83+
84+
*/

0 commit comments

Comments
 (0)