From 3abaa28b036f1f734dd1704875dd4115843593ba Mon Sep 17 00:00:00 2001 From: Ishav Sohal Date: Fri, 15 Dec 2023 23:45:37 -0500 Subject: [PATCH 1/5] fixes --- backend/routes/transportation.py | 6 +- frontend/src/models/Transportation.ts | 1 + .../Transportation/transportationHistory.tsx | 80 ++++++++++++++----- 3 files changed, 62 insertions(+), 25 deletions(-) diff --git a/backend/routes/transportation.py b/backend/routes/transportation.py index 9e809ac..a3473fa 100644 --- a/backend/routes/transportation.py +++ b/backend/routes/transportation.py @@ -52,7 +52,7 @@ def get_transportation_entries_for_user_using_date_range() -> Response: @transportation_service.route("/get_transportation_metric_for_today", methods=['GET']) @carbon_auth.auth.login_required def get_transportation_metric_for_today() -> Response: - try: + #try: user = FirebaseAPI.get_user(flask.request.headers.get('Authorization').split()[1]) query = {"user_id": ObjectId(user.oid), "date": weekly_metric_reset(datetime.now())} item = CarbonTrackDB.transportation_coll.find_one(query) @@ -62,8 +62,8 @@ def get_transportation_metric_for_today() -> Response: else: item = TransportationEntry.from_json(item).to_json() return jsonify({'transportation': item}) - except CarbonTrackError as e: - abort(code=400, description=f"{e}") + #except CarbonTrackError as e: + # abort(code=400, description=f"{e}") @carbon_auth.auth.login_required diff --git a/frontend/src/models/Transportation.ts b/frontend/src/models/Transportation.ts index a4d528a..2f4d998 100644 --- a/frontend/src/models/Transportation.ts +++ b/frontend/src/models/Transportation.ts @@ -10,6 +10,7 @@ export interface TransportationEntry { motorbike: number; electric_car: number; gasoline_car: number; + fuel_efficiency: number; } export interface MonthlyEntry { diff --git a/frontend/src/screens/Transportation/transportationHistory.tsx b/frontend/src/screens/Transportation/transportationHistory.tsx index 3857d74..55b31e8 100644 --- a/frontend/src/screens/Transportation/transportationHistory.tsx +++ b/frontend/src/screens/Transportation/transportationHistory.tsx @@ -13,7 +13,11 @@ import Colors from '../../../assets/colorConstants'; import { useFonts } from 'expo-font'; import { BarChart } from 'react-native-chart-kit'; import { TransportationAPI } from '../../APIs/TransportationAPI'; -import { type TransportationEntry, type MonthlyEntry } from '../../models/Transportation'; +import { + type TransportationEntry, + type MonthlyEntry, + type TransportationRecommendation, +} from '../../models/Transportation'; import { useNavigation } from '@react-navigation/native'; import { type StackNavigationProp } from '@react-navigation/stack'; import { type RootStackParamList } from '../../components/types'; @@ -32,6 +36,8 @@ export default function TransportationHistory(): JSX.Element { const [endDate] = useState(new Date(2023, 11, 1)); const navigation = useNavigation(); const [transportationEntry, setTransportationEntry] = useState(); + const [recommendationForToday, setRecommendationForToday] = + useState(); const toggleExpanded = (index: number): void => { const updatedStates = [...expandedStates]; @@ -63,27 +69,52 @@ export default function TransportationHistory(): JSX.Element { setTransportationEntry(res); } }); + + void TransportationAPI.getTransportationRecommendationForToday().then((res) => { + if (res != null) { + setRecommendationForToday(res); + } + }); }, [endDate, loaded, startDate, navigation]); - const data: Recommendation[] = [ - { - id: 1, - name: 'Vehicle', - description: - 'The emissions from your vehicle is above the threshold, consider switching to an electrical vehicle.', - }, - { - id: 2, - name: 'Car travel', - description: 'Your car travel is above the treshold, try taking public transit instead.', - }, - { - id: 3, - name: 'Motorbike', - description: 'Your motorike travel is above the threshold, consider biking instead.', - }, - // Add more items here - ]; + const checkRecommendations: any(() => { + if (recommendationForToday == null){ + const data: Recommendation[] = []; + } + + else{ + const data: Recommendation[] = [ + { + id: 1, + name: 'Bus', + description: recommendationForToday.bus_recommendation, + }, + { + id: 2, + name: 'Train', + description: recommendationForToday.train_recommendation, + }, + { + id: 3, + name: 'Motorbike', + description: recommendationForToday.motorbike_recommendation, + }, + { + id: 4, + name: 'Electric Car', + description: recommendationForToday.electric_car_recommendation, + }, + { + id: 5, + name: 'Gasoline Car', + description: recommendationForToday.gasoline_car_recommendation, + }, + // Add more items here + ]; + } + + }); + const [expandedItem, setExpandedItem] = useState(null); const toggleExpand = (itemId: number): void => { @@ -92,7 +123,7 @@ export default function TransportationHistory(): JSX.Element { const renderListItem = ({ item }: { item: Recommendation }): JSX.Element => { const isExpanded = expandedItem === item.id; - + return ( toggleExpand(item.id)}> @@ -107,7 +138,12 @@ export default function TransportationHistory(): JSX.Element { ); }; - if (!loaded || monthlyData === undefined || transportationEntry === undefined) { + if ( + !loaded || + monthlyData === undefined || + transportationEntry === undefined || + recommendationForToday === undefined + ) { return <>; } From 9ab85ee4932ae842466cc4e55b12b5f918e74a7a Mon Sep 17 00:00:00 2001 From: Ishav Sohal Date: Sat, 16 Dec 2023 00:01:20 -0500 Subject: [PATCH 2/5] updated default recommendations --- backend/models/energy.py | 6 +++--- backend/models/food.py | 16 ++++++++-------- backend/models/transportation.py | 10 +++++----- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/backend/models/energy.py b/backend/models/energy.py index b3d9d2d..6469aa2 100644 --- a/backend/models/energy.py +++ b/backend/models/energy.py @@ -124,9 +124,9 @@ def from_json(doc: json) -> EnergyEntry: def from_energy_entry(energy_entry: EnergyEntry) -> EnergyEntryRecommendation: submetric_threshold = EnergyEntry.metric_threshold/3 - heating_oil_recommendation = "" - natural_gas_recommendation = "" - electricity_recommendation = "" + heating_oil_recommendation = "Heating oil emissions look good!" + natural_gas_recommendation = "Natural gas emissions look good!" + electricity_recommendation = "Electricity emissions look good!" heating_oil_carbon_emissions = energy_entry.heating_oil * 2.753 natural_gas_carbon_emissions = energy_entry.natural_gas * 1.96 diff --git a/backend/models/food.py b/backend/models/food.py index d72f8b0..00ad1cb 100644 --- a/backend/models/food.py +++ b/backend/models/food.py @@ -141,14 +141,14 @@ def from_json(doc: json) -> FoodEntry: @staticmethod def from_food_entry(food_entry: FoodEntry) -> FoodEntryRecomendation: submetric_threshold = FoodEntry.metric_threshold/8 - beef_recommendation = "" - lamb_recommendation = "" - pork_recommendation = "" - chicken_recommendation = "" - fish_recommendation = "" - cheese_recommendation = "" - milk_recommendation = "" - food_waste_recommendation = "" + beef_recommendation = "Beef emissions look good!" + lamb_recommendation = "Lamb emissions look good!" + pork_recommendation = "Pork emissions look good!" + chicken_recommendation = "Chicken emissions look good!" + fish_recommendation = "Fish emissions look good!" + cheese_recommendation = "Cheese emissions look good!" + milk_recommendation = "Milk emissions look good!" + food_waste_recommendation = "Food waste emissions look good!" beef_carbon_emissions = food_entry.beef * 15.5 lamb_carbon_emissions = food_entry.lamb * 5.84 diff --git a/backend/models/transportation.py b/backend/models/transportation.py index 921509e..1ba7886 100644 --- a/backend/models/transportation.py +++ b/backend/models/transportation.py @@ -115,11 +115,11 @@ def from_json(doc: json) -> TransportationEntry: @staticmethod def from_transportation_entry(transportation_entry: TransportationEntry) -> TransportationEntryRecommendation: submetric_threshold = TransportationEntry.metric_threshold/5 - bus_recommendation = "" - train_recommendation = "" - motorbike_recommendation = "" - electric_car_recommendation = "" - gasoline_car_recommendation = "" + bus_recommendation = "Bus emissions look good!" + train_recommendation = "Train emissions look good!" + motorbike_recommendation = "Motorbike emissions look good!" + electric_car_recommendation = "Electric car emissions look good!" + gasoline_car_recommendation = "Gasoline emissions look good!" bus_carbon_emissions = transportation_entry.bus * 0.103 train_carbon_emissions = transportation_entry.train * 0.037 From 2b44539a9f7bead645c7b3dc1b06f4d2a2bd8243 Mon Sep 17 00:00:00 2001 From: squishyhoshi Date: Sat, 16 Dec 2023 06:14:14 -0500 Subject: [PATCH 3/5] connect recommendation and user attributes --- .../src/screens/Energy/energyEntryEdit.tsx | 234 +++++++----------- frontend/src/screens/Energy/energyForum.tsx | 55 +++- frontend/src/screens/Energy/energyHistory.tsx | 64 +++-- frontend/src/screens/Food/foodHistory.tsx | 86 +++++-- .../transportationEntryEdit.tsx | 1 + .../Transportation/transportationForum.tsx | 1 + .../Transportation/transportationHistory.tsx | 75 +++--- frontend/src/screens/signUpQuestions.tsx | 70 +++--- frontend/src/screens/yourForms.tsx | 91 +++---- 9 files changed, 368 insertions(+), 309 deletions(-) diff --git a/frontend/src/screens/Energy/energyEntryEdit.tsx b/frontend/src/screens/Energy/energyEntryEdit.tsx index a52494a..bf011cb 100644 --- a/frontend/src/screens/Energy/energyEntryEdit.tsx +++ b/frontend/src/screens/Energy/energyEntryEdit.tsx @@ -1,14 +1,5 @@ -import { - StyleSheet, - Text, - View, - TouchableOpacity, - ScrollView, - Modal, - Linking, -} from 'react-native'; +import { StyleSheet, Text, View, TouchableOpacity, ScrollView, TextInput } from 'react-native'; import * as React from 'react'; -import Icon from 'react-native-vector-icons/FontAwesome'; import { useEffect, useState } from 'react'; import { type StackNavigationProp } from '@react-navigation/stack'; import { type RootStackParamList } from '../../components/types'; @@ -16,7 +7,6 @@ import { useNavigation } from '@react-navigation/native'; import { useFonts } from 'expo-font'; import Colors from '../../../assets/colorConstants'; import { SafeAreaView } from 'react-native-safe-area-context'; -import Slider from '@react-native-community/slider'; import { EnergyAPI } from '../../APIs/EnergyAPI'; import { type EnergyEntry } from '../../models/Energy'; @@ -40,43 +30,6 @@ export default function EnergyEntryEdit(): JSX.Element { const [electricityUsage, setElectricityUsage] = useState(0); const [householdUsage, setHouseholdUsage] = useState(0); - const onSliderValueChange = (value: number, index: number): void => { - slidersData[index].initialValue = value - switch (index) { - case 0: - setHeatingOilUsage(value); - break; - case 1: - setNaturalGasUsage(value); - break; - case 2: - setElectricityUsage(value); - break; - case 3: - setHouseholdUsage(value); - break; - default: - break; - } - }; - - const openLink = async (url: string): Promise => { - const supported = await Linking.canOpenURL(url); - - if (supported) { - await Linking.openURL(url); - } else { - console.error('Cannot open the URL'); - } - }; - - const handleLinkPress = (): void => { - const url = 'https://fcr-ccc.nrcan-rncan.gc.ca/en'; - openLink(url).catch((error) => { - console.error('Error opening link:', error); - }); - }; - const [loaded] = useFonts({ Montserrat: require('../../../assets/fonts/MontserratThinRegular.ttf'), Josefin: require('../../../assets/fonts/JosefinSansThinRegular.ttf'), @@ -84,8 +37,6 @@ export default function EnergyEntryEdit(): JSX.Element { const navigation = useNavigation(); - const [modalVisible, setModalVisible] = useState(false); - const handleSurveySubmit = (): void => { // Process survey responses, e.g., send them to a server if (energyEntry != null) { @@ -98,36 +49,60 @@ export default function EnergyEntryEdit(): JSX.Element { natural_gas: naturalGasUsage, electricity: electricityUsage, province: energyEntry.province, - household: householdUsage - } + household: householdUsage, + }; void EnergyAPI.updateEnergy(newEntry).then(() => { - navigation.navigate('EnergyHistory'); - }) + navigation.navigate('DashBoard'); + }); } }; useEffect(() => { if (energyEntry != null) { setSliderData([ - { id: 1, label: 'Heating Oil', minValue: 0, maxValue: 800, initialValue: energyEntry.heating_oil }, - { id: 2, label: 'Natural Gas', minValue: 0, maxValue: 800, initialValue: energyEntry.natural_gas }, - { id: 3, label: 'Electricity', minValue: 0, maxValue: 800, initialValue: energyEntry.electricity }, - { id: 4, label: 'House Hold Members', minValue: 1, maxValue: 10, initialValue: energyEntry.household }, - ]) + { + id: 1, + label: 'Heating Oil', + minValue: 0, + maxValue: 800, + initialValue: energyEntry.heating_oil, + }, + { + id: 2, + label: 'Natural Gas', + minValue: 0, + maxValue: 800, + initialValue: energyEntry.natural_gas, + }, + { + id: 3, + label: 'Electricity', + minValue: 0, + maxValue: 800, + initialValue: energyEntry.electricity, + }, + { + id: 4, + label: 'House Hold Members', + minValue: 1, + maxValue: 10, + initialValue: energyEntry.household, + }, + ]); setHeatingOilUsage(energyEntry.heating_oil); setNaturalGasUsage(energyEntry.natural_gas); setElectricityUsage(energyEntry.electricity); setHouseholdUsage(energyEntry.household); } - }, [energyEntry]) + }, [energyEntry]); useEffect(() => { void EnergyAPI.getEnergyMetricForToday().then((res) => { if (res != null) { - setEnergyEntry(res) + setEnergyEntry(res); } - }) - }, [loaded]) + }); + }, [loaded]); if (!loaded || slidersData.length === 0) { return <>; @@ -138,56 +113,45 @@ export default function EnergyEntryEdit(): JSX.Element { Calculate your emissions from energy: - - - - - If you don't know your vehicle's fuel efficiency, it's available - online{' '} - - here - - . Select the "combination" value under Comsumption in L/100km. The average - fuel consumption of non-plug-in hybrid personal vehicles in Canada is 8.9 L / 100 - km. - - setModalVisible(!modalVisible)} - > - - - - - - - - On average, how much distance do you travel using the following methods per week: - - - {slidersData.map((slider, index) => ( - - - {slider.label}: {slidersData[index].initialValue} km - - onSliderValueChange(value, index)} - /> - - {slider.minValue} - {slider.maxValue} - - {/* You can include additional components related to this slider here */} - - ))} + + What is your monthly electricity consumption, in kWh: + { + setElectricityUsage(Number(text)); + }} + /> + + + + + What is your monthly natural gas consumption, in {'m\u00B3'}: + + { + setNaturalGasUsage(Number(text)); + }} + /> + + + + + What is your monthly heating oil consumption, in litres: + + { + setHeatingOilUsage(Number(text)); + }} + /> + Save @@ -203,34 +167,12 @@ const styles = StyleSheet.create({ justifyContent: 'center', backgroundColor: Colors.LIGHTFGREEN, }, - labelContainer: { - flexDirection: 'row', - justifyContent: 'space-between', - width: '100%', - paddingHorizontal: 12, - }, - modalBackground: { - backgroundColor: Colors.BLACKTRANS, - flex: 1, - }, - modalContainer: { - backgroundColor: Colors.WHITE, - marginHorizontal: 50, - marginVertical: 180, - padding: 20, - borderRadius: 10, - flex: 1, - flexDirection: 'row', - }, scrollContainer: { paddingTop: 30, flex: 1, paddingHorizontal: 30, backgroundColor: Colors.LIGHTFGREEN, }, - label: { - fontSize: 15, - }, header: { color: Colors.DARKGREEN, fontFamily: 'Montserrat', @@ -238,6 +180,14 @@ const styles = StyleSheet.create({ fontWeight: '700', marginBottom: 50, }, + input: { + borderWidth: 1, + borderColor: Colors.GREY, + padding: 8, + margin: 10, + width: 200, + backgroundColor: Colors.WHITE, + }, question: { fontFamily: 'Montserrat', fontSize: 20, @@ -260,18 +210,4 @@ const styles = StyleSheet.create({ questionContainer: { paddingBottom: 30, }, - infoText: { - fontSize: 20, - color: Colors.DARKGREEN, - }, - linkText: { - color: Colors.BLUE, - }, - closeIcon: { - marginLeft: 'auto', - }, - silder: { - height: 50, - width: '100%', - }, }); diff --git a/frontend/src/screens/Energy/energyForum.tsx b/frontend/src/screens/Energy/energyForum.tsx index 3e5ffaf..fcc532a 100644 --- a/frontend/src/screens/Energy/energyForum.tsx +++ b/frontend/src/screens/Energy/energyForum.tsx @@ -4,9 +4,13 @@ import { type StackNavigationProp } from '@react-navigation/stack'; import { type RootStackParamList } from '../../components/types'; import { useFonts } from 'expo-font'; import Colors from '../../../assets/colorConstants'; -import { useState } from 'react'; +import { useState, useEffect } from 'react'; import { useNavigation } from '@react-navigation/native'; import { SafeAreaView } from 'react-native-safe-area-context'; +import { UsersAPI } from '../../APIs/UsersAPI'; +import { type User } from '../../models/User'; +import { EnergyAPI } from '../../APIs/EnergyAPI'; +import { type EnergyEntry } from '../../models/Energy'; export type StackNavigation = StackNavigationProp; @@ -18,22 +22,55 @@ export default function EnergyForum(): JSX.Element { const navigation = useNavigation(); + const [energyEntry, setEnergyEntry] = useState(); + const [electricalConsumption, setElectricalConsumption] = useState(0); const [heatingOil, setHeatingOil] = useState(0); const [naturalGas, setNaturalGas] = useState(0); + const [user, setUser] = useState(undefined); + const handleSurveySubmit = (): void => { // Process survey responses, e.g., send them to a server - console.log('Survey Responses:', { - electricalConsumption, - heatingOil, - naturalGas, - }); - - navigation.navigate('MainApp'); + if (energyEntry != null && user != null) { + const newEntry: EnergyEntry = { + _id: energyEntry._id, + user_id: energyEntry.user_id, + carbon_emissions: energyEntry.carbon_emissions, + date: energyEntry.date, + heating_oil: heatingOil, + natural_gas: naturalGas, + electricity: electricalConsumption, + province: user.province, + household: user.household, + }; + void EnergyAPI.updateEnergy(newEntry).then(() => { + navigation.navigate('MainApp'); + }); + } }; + useEffect(() => { + if (energyEntry != null) { + setHeatingOil(energyEntry.heating_oil); + setNaturalGas(energyEntry.natural_gas); + setElectricalConsumption(energyEntry.electricity); + } + }, [energyEntry]); + + useEffect(() => { + void UsersAPI.GetLoggedInUser().then((res) => { + if (res != null) { + setUser(res); + } + }); + void EnergyAPI.getEnergyMetricForToday().then((res) => { + if (res != null) { + setEnergyEntry(res); + } + }); + }, [loaded]); - if (!loaded) { + if (!loaded || user === undefined) { return <>; } diff --git a/frontend/src/screens/Energy/energyHistory.tsx b/frontend/src/screens/Energy/energyHistory.tsx index 63510b9..c017c46 100644 --- a/frontend/src/screens/Energy/energyHistory.tsx +++ b/frontend/src/screens/Energy/energyHistory.tsx @@ -13,7 +13,11 @@ import Colors from '../../../assets/colorConstants'; import { useFonts } from 'expo-font'; import { BarChart } from 'react-native-chart-kit'; import { EnergyAPI } from '../../APIs/EnergyAPI'; -import { type EnergyEntry, type MonthlyEntry } from '../../models/Energy'; +import { + type EnergyEntry, + type MonthlyEntry, + type EnergyEntryRecommendation, +} from '../../models/Energy'; import { useNavigation } from '@react-navigation/native'; import { type StackNavigationProp } from '@react-navigation/stack'; import { type RootStackParamList } from '../../components/types'; @@ -32,6 +36,7 @@ export default function EnergyHistory(): JSX.Element { const [endDate] = useState(new Date(2023, 11, 1)); const navigation = useNavigation(); const [energyEntry, setEnergyEntry] = useState(); + const [recommendationForToday, setRecommendationForToday] = useState(); const toggleExpanded = (index: number): void => { const updatedStates = [...expandedStates]; @@ -61,30 +66,43 @@ export default function EnergyHistory(): JSX.Element { setEnergyEntry(res); } }); + void EnergyAPI.getEnergyRecommendationForToday().then((res) => { + if (res != null) { + setRecommendationForToday(res); + } + }); }, [endDate, loaded, startDate, navigation]); + const [expandedItem, setExpandedItem] = useState(null); - const data: Recommendation[] = [ - { - id: 1, - name: 'Electricity', - description: - 'Your electricity usage is above the threshold, consider keeping your lights turned off when not needed.', - }, - { - id: 2, - name: 'Natural gas', - description: - 'Your natural gas usage is above the threshold, consider switching to a fuel efficient furnance to heat your home instead.', - }, - { - id: 3, - name: 'Natural gas', - description: - 'Your natural gas usage is above the threshold, consider installing a smart thermostat to heat your household more efficiently.', - }, - // Add more items here - ]; + const checkRecommendations = (): Recommendation[] => { + if (recommendationForToday == null) { + return []; // Return an empty array if recommendationForToday is null + } + + // Populate data with recommendations if recommendationForToday is not null + const data: Recommendation[] = [ + { + id: 1, + name: 'Heating Oil', + description: recommendationForToday.heating_oil_recommendation, + }, + { + id: 2, + name: 'Natural Gas', + description: recommendationForToday.natural_gas_recommendation, + }, + { + id: 3, + name: 'Electricity', + description: recommendationForToday.electricity_recommendation, + }, + ]; + + return data; + }; + + const recommendations = checkRecommendations(); const toggleExpand = (itemId: number): void => { setExpandedItem(expandedItem === itemId ? null : itemId); @@ -205,7 +223,7 @@ export default function EnergyHistory(): JSX.Element { Recommendations: item.id.toString()} nestedScrollEnabled diff --git a/frontend/src/screens/Food/foodHistory.tsx b/frontend/src/screens/Food/foodHistory.tsx index 6aa5e1b..86b0208 100644 --- a/frontend/src/screens/Food/foodHistory.tsx +++ b/frontend/src/screens/Food/foodHistory.tsx @@ -13,7 +13,7 @@ import Colors from '../../../assets/colorConstants'; import { useFonts } from 'expo-font'; import { BarChart } from 'react-native-chart-kit'; import { FoodAPI } from '../../APIs/FoodAPI'; -import { type FoodEntry, type MonthlyEntry } from '../../models/Food'; +import { type FoodEntry, type MonthlyEntry, type FoodEntryRecommendation } from '../../models/Food'; import { useNavigation } from '@react-navigation/native'; import { type StackNavigationProp } from '@react-navigation/stack'; import { type RootStackParamList } from '../../components/types'; @@ -32,6 +32,7 @@ export default function FoodHistory(): JSX.Element { const [endDate] = useState(new Date(2023, 11, 1)); const navigation = useNavigation(); const [foodEntry, setFoodEntry] = useState(); + const [recommendationForToday, setRecommendationForToday] = useState(); const toggleExpanded = (index: number): void => { const updatedStates = [...expandedStates]; @@ -61,25 +62,69 @@ export default function FoodHistory(): JSX.Element { setFoodEntry(res); } }); + void FoodAPI.getFoodRecommendationForToday().then((res) => { + if (res != null) { + setRecommendationForToday(res); + } + }); }, [endDate, loaded, startDate, navigation]); const [expandedItem, setExpandedItem] = useState(null); - const data: Recommendation[] = [ - { - id: 1, - name: 'Beef', - description: - 'Your beef intake is above the threshold, consider switching to a more carbon efficient type of meat.', - }, - { - id: 2, - name: 'Food waste', - description: - 'Your food waste is above the threshold, consider buying less at the grocery store and checking your fridge for expired food.', - }, - // Add more items here - ]; + const checkRecommendations = (): Recommendation[] => { + if (recommendationForToday == null) { + return []; // Return an empty array if recommendationForToday is null + } + + // Populate data with recommendations if recommendationForToday is not null + const data: Recommendation[] = [ + { + id: 1, + name: 'Beef', + description: recommendationForToday.beef_recommendation, + }, + { + id: 2, + name: 'Lamb', + description: recommendationForToday.lamb_recommendation, + }, + { + id: 3, + name: 'Pork', + description: recommendationForToday.pork_recommendation, + }, + { + id: 4, + name: 'Chicken', + description: recommendationForToday.chicken_recommendation, + }, + { + id: 5, + name: 'Fish', + description: recommendationForToday.fish_recommendation, + }, + { + id: 6, + name: 'Cheese', + description: recommendationForToday.cheese_recommendation, + }, + { + id: 7, + name: 'Milk', + description: recommendationForToday.milk_recommendation, + }, + { + id: 8, + name: 'Food Waste', + description: recommendationForToday.food_waste_recommendation, + }, + // Add more items here + ]; + + return data; + }; + + const recommendations = checkRecommendations(); const toggleExpand = (itemId: number): void => { setExpandedItem(expandedItem === itemId ? null : itemId); @@ -102,7 +147,12 @@ export default function FoodHistory(): JSX.Element { ); }; - if (!loaded || monthlyData === undefined || foodEntry === undefined) { + if ( + !loaded || + monthlyData === undefined || + foodEntry === undefined || + recommendationForToday === undefined + ) { return <>; } @@ -200,7 +250,7 @@ export default function FoodHistory(): JSX.Element { Recommendations: item.id.toString()} nestedScrollEnabled diff --git a/frontend/src/screens/Transportation/transportationEntryEdit.tsx b/frontend/src/screens/Transportation/transportationEntryEdit.tsx index d41bf9d..a5641ce 100644 --- a/frontend/src/screens/Transportation/transportationEntryEdit.tsx +++ b/frontend/src/screens/Transportation/transportationEntryEdit.tsx @@ -75,6 +75,7 @@ export default function TransportationEntryEdit(): JSX.Element { gasoline_car: gasolineCarTravel, carbon_emissions: transportationEntry.carbon_emissions, date: transportationEntry.date, + fuel_efficiency: 1, }; void TransportationAPI.updateTransportation(newEntry).then(() => { navigation.navigate('DashBoard'); diff --git a/frontend/src/screens/Transportation/transportationForum.tsx b/frontend/src/screens/Transportation/transportationForum.tsx index 2c4fcab..cee2219 100644 --- a/frontend/src/screens/Transportation/transportationForum.tsx +++ b/frontend/src/screens/Transportation/transportationForum.tsx @@ -87,6 +87,7 @@ export default function TransportationForum(): JSX.Element { gasoline_car: gasolineCarTravel, carbon_emissions: transportationEntry.carbon_emissions, date: transportationEntry.date, + fuel_efficiency: 1, }; void TransportationAPI.updateTransportation(newEntry).then(() => { navigation.navigate('FoodForum'); diff --git a/frontend/src/screens/Transportation/transportationHistory.tsx b/frontend/src/screens/Transportation/transportationHistory.tsx index 55b31e8..950b88d 100644 --- a/frontend/src/screens/Transportation/transportationHistory.tsx +++ b/frontend/src/screens/Transportation/transportationHistory.tsx @@ -77,44 +77,45 @@ export default function TransportationHistory(): JSX.Element { }); }, [endDate, loaded, startDate, navigation]); - const checkRecommendations: any(() => { - if (recommendationForToday == null){ - const data: Recommendation[] = []; + const checkRecommendations = (): Recommendation[] => { + if (recommendationForToday == null) { + return []; // Return an empty array if recommendationForToday is null } - else{ - const data: Recommendation[] = [ - { - id: 1, - name: 'Bus', - description: recommendationForToday.bus_recommendation, - }, - { - id: 2, - name: 'Train', - description: recommendationForToday.train_recommendation, - }, - { - id: 3, - name: 'Motorbike', - description: recommendationForToday.motorbike_recommendation, - }, - { - id: 4, - name: 'Electric Car', - description: recommendationForToday.electric_car_recommendation, - }, - { - id: 5, - name: 'Gasoline Car', - description: recommendationForToday.gasoline_car_recommendation, - }, - // Add more items here - ]; - } + // Populate data with recommendations if recommendationForToday is not null + const data: Recommendation[] = [ + { + id: 1, + name: 'Bus', + description: recommendationForToday.bus_recommendation, + }, + { + id: 2, + name: 'Train', + description: recommendationForToday.train_recommendation, + }, + { + id: 3, + name: 'Motorbike', + description: recommendationForToday.motorbike_recommendation, + }, + { + id: 4, + name: 'Electric Car', + description: recommendationForToday.electric_car_recommendation, + }, + { + id: 5, + name: 'Gasoline Car', + description: recommendationForToday.gasoline_car_recommendation, + }, + // Add more items here + ]; - }); - + return data; + }; + + const recommendations = checkRecommendations(); const [expandedItem, setExpandedItem] = useState(null); const toggleExpand = (itemId: number): void => { @@ -123,7 +124,7 @@ export default function TransportationHistory(): JSX.Element { const renderListItem = ({ item }: { item: Recommendation }): JSX.Element => { const isExpanded = expandedItem === item.id; - + return ( toggleExpand(item.id)}> @@ -244,7 +245,7 @@ export default function TransportationHistory(): JSX.Element { Recommendations: item.id.toString()} nestedScrollEnabled diff --git a/frontend/src/screens/signUpQuestions.tsx b/frontend/src/screens/signUpQuestions.tsx index ec16338..db488c1 100644 --- a/frontend/src/screens/signUpQuestions.tsx +++ b/frontend/src/screens/signUpQuestions.tsx @@ -64,6 +64,16 @@ export default function SignUpQuestions(): JSX.Element { fuelEfficiency, fuelType, }); + if (user != null) { + try { + void UsersAPI.updateUserProvince(user, province); + void UsersAPI.updateUserOccupancy(user, numOfPpl); + } catch (error) { + // Handle errors if any of the updates fail + console.error(error); + // You might want to handle the error or show a message to the user + } + } navigation.navigate('TransportationForum'); }; @@ -90,7 +100,7 @@ export default function SignUpQuestions(): JSX.Element { updatedResponses[questionId] = data[questionId].options[optionIndex]; setResponses(updatedResponses); }; - + useEffect(() => { void UsersAPI.GetLoggedInUser().then((res) => { if (res != null) { @@ -100,41 +110,41 @@ export default function SignUpQuestions(): JSX.Element { }, [loaded]); useEffect(() => { - console.log("Updated Province:", province); + console.log('Updated Province:', province); }, [province]); // sanity check if (!loaded || user === undefined) { return <>; } - return ( - Before jump right in, why don't we get to know you a little more, {user.full_name}! + + Before jump right in, why don't we get to know you a little more, {user.full_name}! + - How many people live in your household: - - { - setNumOfPpl(Number(text)); - }} - /> - - + How many people live in your household: + + { + setNumOfPpl(Number(text)); + }} + /> + + What province do you live in? ) => setProvince(selectedProvince)} + onSelect={(selectedProvince: React.SetStateAction) => + setProvince(selectedProvince) + } /> - + - - - {data[0].question} {data[0].options.map((option, index) => ( @@ -180,14 +190,12 @@ export default function SignUpQuestions(): JSX.Element { - If you don't know your vehicle's fuel efficiency, it's available - online{' '} + If you don't know your vehicle's fuel efficiency, it's available online{' '} here - . Select the "combination" value under Consumption in L/100km. The - average fuel consumption of non-plug-in hybrid personal vehicles in Canada is 8.9 L - / 100 km. + . Select the "combination" value under Consumption in L/100km. The average + fuel consumption of non-plug-in hybrid personal vehicles in Canada is 8.9 L / 100 km. (); const [energyEntry, setEnergyEntry] = useState(); - useEffect(() => { - void TransportationAPI.getTransportationEntriesForUserUsingDataRange(startDate, endDate).then( - (res) => { - if (res != null) { - if (res.monthlyData != null) { - setMonthlyData(res.monthlyData); + useFocusEffect( + React.useCallback(() => { + const fetchData = async (): Promise => { + try { + const transportationEntries = + await TransportationAPI.getTransportationEntriesForUserUsingDataRange( + startDate, + endDate + ); + if (transportationEntries?.monthlyData != null) { + setMonthlyData(transportationEntries.monthlyData); } + + const transportationMetric = await TransportationAPI.getTransportationMetricForToday(); + if (transportationMetric != null) { + setTransportationEntry(transportationMetric); + } + + const foodEntries = await FoodAPI.getFoodEntriesForUserUsingDataRange(startDate, endDate); + if (foodEntries?.monthlyData != null) { + setMonthlyData(foodEntries.monthlyData); + } + + const foodMetric = await FoodAPI.getFoodMetricForToday(); + if (foodMetric != null) { + setFoodEntry(foodMetric); + } + + const energyEntries = await EnergyAPI.getEnergyEntriesForUserUsingDataRange( + startDate, + endDate + ); + if (energyEntries?.monthlyData != null) { + setMonthlyData(energyEntries.monthlyData); + } + + const energyMetric = await EnergyAPI.getEnergyMetricForToday(); + if (energyMetric != null) { + setEnergyEntry(energyMetric); + } + } catch (error) { + // Handle errors if needed + console.error(error); } - } - ); - void TransportationAPI.getTransportationMetricForToday().then((res) => { - if (res != null) { - setTransportationEntry(res); - } - }); - void FoodAPI.getFoodEntriesForUserUsingDataRange(startDate, endDate).then((res) => { - if (res != null) { - if (res.monthlyData != null) { - setMonthlyData(res.monthlyData); - } - } - }); - void FoodAPI.getFoodMetricForToday().then((res) => { - if (res != null) { - setFoodEntry(res); - } - }); - void EnergyAPI.getEnergyEntriesForUserUsingDataRange(startDate, endDate).then((res) => { - if (res != null) { - if (res.monthlyData != null) { - setMonthlyData(res.monthlyData); - } - } - }); - void EnergyAPI.getEnergyMetricForToday().then((res) => { - if (res != null) { - setEnergyEntry(res); - } - }); - }, [endDate, loaded, startDate, navigation]); + }; + + void fetchData(); + }, [startDate, endDate]) // Include startDate and endDate in the dependency array + ); if ( !loaded || @@ -89,7 +98,6 @@ export default function YourForms(): JSX.Element { }} > - {' '} This Week's Food Entry: {foodEntry.carbon_emissions.toString()} @@ -110,7 +118,6 @@ export default function YourForms(): JSX.Element { }} > - {' '} This Week's Energy Entry: {energyEntry.carbon_emissions.toString()} From ce4e25d619190da85c12f2f19d65511aa80ed99d Mon Sep 17 00:00:00 2001 From: squishyhoshi Date: Sat, 16 Dec 2023 07:15:54 -0500 Subject: [PATCH 4/5] users can now update fuel efficiency --- backend/routes/users.py | 207 +++++++++++------- frontend/src/APIs/UsersAPI.ts | 32 ++- .../src/screens/Energy/energyEntryEdit.tsx | 67 ++---- .../transportationEntryEdit.tsx | 15 +- .../Transportation/transportationForum.tsx | 15 +- frontend/src/screens/footpringDecomp.tsx | 30 ++- .../src/screens/settings/updateHomeScreen.tsx | 72 +++--- frontend/src/screens/signUpQuestions.tsx | 1 + frontend/src/screens/yourForms.tsx | 7 +- 9 files changed, 252 insertions(+), 194 deletions(-) diff --git a/backend/routes/users.py b/backend/routes/users.py index bba1ab1..6888a40 100644 --- a/backend/routes/users.py +++ b/backend/routes/users.py @@ -10,6 +10,7 @@ users = Blueprint("/users", __name__) + @users.route("/user/", methods=["GET"]) @carbon_auth.auth.login_required def get_user(user_id: str) -> Response: @@ -21,67 +22,78 @@ def get_user(user_id: str) -> Response: except CarbonTrackError as e: abort(code=400, description=f"{e}") -@users.route("/get_top_users", methods=['POST']) + +@users.route("/get_top_users", methods=["POST"]) @carbon_auth.auth.login_required def get_top_users() -> Response: - #try: - count = request.get_json()["count"] - - # Monthly - _top_monthly_users = CarbonTrackDB.users_coll.find().sort("monthly_score", -1).limit(count) - top_monthly_users = [] - rank = 1 - for user in _top_monthly_users: - obj = User.from_json(user) - user = { - 'rank': rank, - 'name': obj.full_name, - 'footprint': 0, - 'score': obj.overall_score, - } - rank += 1 - top_monthly_users.append(user) - - # Yearly - _top_yearly_users = CarbonTrackDB.users_coll.find().sort("yearly_score", -1).limit(count) - top_yearly_users = [] - rank = 1 - for user in _top_yearly_users: - obj = User.from_json(user) - user = { - 'rank': rank, - 'name': obj.full_name, - 'footprint': 0, - 'score': obj.overall_score, - } - rank += 1 - top_yearly_users.append(user) - - # Overall - _top_overall_users = CarbonTrackDB.users_coll.find().sort("overall_score", -1).limit(count) - top_overall_users = [] - rank = 1 - for user in _top_overall_users: - obj = User.from_json(user) - user = { - 'rank': rank, - 'name': obj.full_name, - 'footprint': 0, - 'score': obj.overall_score, - } - rank += 1 - top_overall_users.append(user) - - return jsonify({ - 'top_monthly_users': top_monthly_users, - 'top_yearly_users': top_yearly_users, - 'top_overall_users': top_overall_users, - }) - #except CarbonTrackError as e: - # abort(code=400, description=f"{e}") - - -@users.route("/user_email/", methods=['GET']) + # try: + count = request.get_json()["count"] + + # Monthly + _top_monthly_users = ( + CarbonTrackDB.users_coll.find().sort("monthly_score", -1).limit(count) + ) + top_monthly_users = [] + rank = 1 + for user in _top_monthly_users: + obj = User.from_json(user) + user = { + "rank": rank, + "name": obj.full_name, + "footprint": 0, + "score": obj.overall_score, + } + rank += 1 + top_monthly_users.append(user) + + # Yearly + _top_yearly_users = ( + CarbonTrackDB.users_coll.find().sort("yearly_score", -1).limit(count) + ) + top_yearly_users = [] + rank = 1 + for user in _top_yearly_users: + obj = User.from_json(user) + user = { + "rank": rank, + "name": obj.full_name, + "footprint": 0, + "score": obj.overall_score, + } + rank += 1 + top_yearly_users.append(user) + + # Overall + _top_overall_users = ( + CarbonTrackDB.users_coll.find().sort("overall_score", -1).limit(count) + ) + top_overall_users = [] + rank = 1 + for user in _top_overall_users: + obj = User.from_json(user) + user = { + "rank": rank, + "name": obj.full_name, + "footprint": 0, + "score": obj.overall_score, + } + rank += 1 + top_overall_users.append(user) + + return jsonify( + { + "top_monthly_users": top_monthly_users, + "top_yearly_users": top_yearly_users, + "top_overall_users": top_overall_users, + } + ) + + +# except CarbonTrackError as e: +# abort(code=400, description=f"{e}") + + +@users.route("/user_email/", methods=["GET"]) @carbon_auth.auth.login_required def get_user_by_email(user_email: str) -> Response: try: @@ -128,26 +140,26 @@ def get_current_user() -> Response: @users.route("/user", methods=["PUT"]) @carbon_auth.auth.login_required def create_user() -> Response: - #try: - res: dict = request.get_json()["user"] - user = User.from_json(res) - user.email = user.email.lower() + # try: + res: dict = request.get_json()["user"] + user = User.from_json(res) + user.email = user.email.lower() - query = {"email": user.email} - item = CarbonTrackDB.users_coll.find_one(query) - if item is None: - user = user.to_json() - inserted_id = CarbonTrackDB.users_coll.insert_one(user).inserted_id - user = User.from_json( - CarbonTrackDB.users_coll.find_one({"_id": inserted_id}) - ).to_json() - return jsonify({"user": user}) - else: - return jsonify( - {"error": "User Already Exits With Same Email, Please Log In"} - ) - # except CarbonTrackError as e: - # abort(code=400, description=f"{e}") + query = {"email": user.email} + item = CarbonTrackDB.users_coll.find_one(query) + if item is None: + user = user.to_json() + inserted_id = CarbonTrackDB.users_coll.insert_one(user).inserted_id + user = User.from_json( + CarbonTrackDB.users_coll.find_one({"_id": inserted_id}) + ).to_json() + return jsonify({"user": user}) + else: + return jsonify({"error": "User Already Exits With Same Email, Please Log In"}) + + +# except CarbonTrackError as e: +# abort(code=400, description=f"{e}") @users.route("/user/", methods=["DELETE"]) @@ -199,14 +211,15 @@ def update_user_email(uid: str) -> Response: except CarbonTrackError as e: abort(code=400, description=f"{e}") + @users.route("/user/update_name/", methods=["PATCH"]) @carbon_auth.auth.login_required def update_user_name(user_id: str) -> Response: try: new_name = request.get_json().get("newName", "") - + query = {"uid": user_id} - + current_user = carbon_auth.auth.current_user() print(current_user) @@ -219,7 +232,7 @@ def update_user_name(user_id: str) -> Response: return jsonify({"user": item}), 200 except CarbonTrackError as e: abort(code=400, description=f"{e}") - + @users.route("/user/update_province/", methods=["PATCH"]) def update_user_province(user_id: str) -> Response: @@ -228,11 +241,11 @@ def update_user_province(user_id: str) -> Response: new_province = request.get_json().get("newProvince", "") print("Updating province...") query = {"uid": user_id} - + updated_user = CarbonTrackDB.users_coll.find_one_and_update( query, {"$set": {"province": new_province}}, - return_document=ReturnDocument.AFTER + return_document=ReturnDocument.AFTER, ) updated_user = User.from_json(updated_user).to_json() @@ -241,6 +254,28 @@ def update_user_province(user_id: str) -> Response: except CarbonTrackError as e: abort(code=400, description=f"{e}") + +@users.route("/user/update_fuel_efficiency/", methods=["PATCH"]) +def update_user_fuel_efficiency(user_id: str) -> Response: + try: + print("Updating fuel efficiency...") + new_fuel_efficiency = request.get_json().get("newFuelEfficiency", "") + print("Updating province...") + query = {"uid": user_id} + + updated_user = CarbonTrackDB.users_coll.find_one_and_update( + query, + {"$set": {"fuel_efficiency": new_fuel_efficiency}}, + return_document=ReturnDocument.AFTER, + ) + + updated_user = User.from_json(updated_user).to_json() + + return jsonify({"user": updated_user}), 200 + except CarbonTrackError as e: + abort(code=400, description=f"{e}") + + @users.route("/user/update_occupancy/", methods=["PATCH"]) def update_user_occupancy(user_id: str) -> Response: try: @@ -248,13 +283,15 @@ def update_user_occupancy(user_id: str) -> Response: print(request.get_json()) new_occupancy = request.get_json().get("newOccupancy", 0) query = {"uid": user_id} - + current_user = carbon_auth.auth.current_user() print(current_user) print(f"Updating occupancy for user {user_id} to {new_occupancy}") - CarbonTrackDB.users_coll.update_one(query, {"$set": {"household": new_occupancy}}) + CarbonTrackDB.users_coll.update_one( + query, {"$set": {"household": new_occupancy}} + ) item = CarbonTrackDB.users_coll.find_one(query) diff --git a/frontend/src/APIs/UsersAPI.ts b/frontend/src/APIs/UsersAPI.ts index 6d21e7b..e1dd096 100644 --- a/frontend/src/APIs/UsersAPI.ts +++ b/frontend/src/APIs/UsersAPI.ts @@ -34,8 +34,8 @@ export const UsersAPI = { return undefined; } }, - - getTopUsers: async (count: number)=> { + + getTopUsers: async (count: number) => { try { const res = await FLASK_HTTPS.post(routeName + '/get_top_users', { count, @@ -47,7 +47,7 @@ export const UsersAPI = { return undefined; } }, - + getUserByEmail: async (email: string) => { try { const res = await FLASK_HTTPS.get(routeName + '/user_email/' + email); @@ -143,10 +143,9 @@ export const UsersAPI = { }, updateUserName: async (user: User, newName: string) => { try { - const res = await FLASK_HTTPS.patch( - routeName + `/user/update_name/${user.uid.toString()}`, - { newName }, - ); + const res = await FLASK_HTTPS.patch(routeName + `/user/update_name/${user.uid.toString()}`, { + newName, + }); return res.data.user as User; } catch (error) { @@ -158,7 +157,7 @@ export const UsersAPI = { try { const res = await FLASK_HTTPS.patch( routeName + `/user/update_province/${user.uid.toString()}`, - { newProvince }, + { newProvince } ); return res.data.user as User; @@ -171,7 +170,7 @@ export const UsersAPI = { try { const res = await FLASK_HTTPS.patch( routeName + `/user/update_occupancy/${user.uid.toString()}`, - { newOccupancy }, + { newOccupancy } ); return res.data.user as User; @@ -179,5 +178,18 @@ export const UsersAPI = { console.error('UsersAPI(frontend): updateUserOccupancyError:', error); return undefined; } - } + }, + updateUserFuelEfficiency: async (user: User, newFuelEfficiency: GLfloat) => { + try { + const res = await FLASK_HTTPS.patch( + routeName + `/user/update_fuel_efficiency/${user.uid.toString()}`, + { newFuelEfficiency } + ); + + return res.data.user as User; + } catch (error) { + console.error('UsersAPI(frontend): updateUserFuelEfficiencyError:', error); + return undefined; + } + }, }; diff --git a/frontend/src/screens/Energy/energyEntryEdit.tsx b/frontend/src/screens/Energy/energyEntryEdit.tsx index bf011cb..72664cf 100644 --- a/frontend/src/screens/Energy/energyEntryEdit.tsx +++ b/frontend/src/screens/Energy/energyEntryEdit.tsx @@ -9,26 +9,19 @@ import Colors from '../../../assets/colorConstants'; import { SafeAreaView } from 'react-native-safe-area-context'; import { EnergyAPI } from '../../APIs/EnergyAPI'; import { type EnergyEntry } from '../../models/Energy'; +import { UsersAPI } from '../../APIs/UsersAPI'; +import { type User } from '../../models/User'; export type StackNavigation = StackNavigationProp; export default function EnergyEntryEdit(): JSX.Element { - interface SliderData { - id: number; - label: string; - minValue: number; - maxValue: number; - initialValue: number; - } - const [energyEntry, setEnergyEntry] = useState(); - const [slidersData, setSliderData] = useState([]); - const [heatingOilUsage, setHeatingOilUsage] = useState(0); const [naturalGasUsage, setNaturalGasUsage] = useState(0); const [electricityUsage, setElectricityUsage] = useState(0); - const [householdUsage, setHouseholdUsage] = useState(0); + + const [user, setUser] = useState(undefined); const [loaded] = useFonts({ Montserrat: require('../../../assets/fonts/MontserratThinRegular.ttf'), @@ -39,7 +32,7 @@ export default function EnergyEntryEdit(): JSX.Element { const handleSurveySubmit = (): void => { // Process survey responses, e.g., send them to a server - if (energyEntry != null) { + if (energyEntry != null && user != null) { const newEntry: EnergyEntry = { _id: energyEntry._id, user_id: energyEntry.user_id, @@ -48,8 +41,8 @@ export default function EnergyEntryEdit(): JSX.Element { heating_oil: heatingOilUsage, natural_gas: naturalGasUsage, electricity: electricityUsage, - province: energyEntry.province, - household: householdUsage, + province: user.province, + household: user.household, }; void EnergyAPI.updateEnergy(newEntry).then(() => { navigation.navigate('DashBoard'); @@ -58,45 +51,11 @@ export default function EnergyEntryEdit(): JSX.Element { }; useEffect(() => { - if (energyEntry != null) { - setSliderData([ - { - id: 1, - label: 'Heating Oil', - minValue: 0, - maxValue: 800, - initialValue: energyEntry.heating_oil, - }, - { - id: 2, - label: 'Natural Gas', - minValue: 0, - maxValue: 800, - initialValue: energyEntry.natural_gas, - }, - { - id: 3, - label: 'Electricity', - minValue: 0, - maxValue: 800, - initialValue: energyEntry.electricity, - }, - { - id: 4, - label: 'House Hold Members', - minValue: 1, - maxValue: 10, - initialValue: energyEntry.household, - }, - ]); - setHeatingOilUsage(energyEntry.heating_oil); - setNaturalGasUsage(energyEntry.natural_gas); - setElectricityUsage(energyEntry.electricity); - setHouseholdUsage(energyEntry.household); - } - }, [energyEntry]); - - useEffect(() => { + void UsersAPI.GetLoggedInUser().then((res) => { + if (res != null) { + setUser(res); + } + }); void EnergyAPI.getEnergyMetricForToday().then((res) => { if (res != null) { setEnergyEntry(res); @@ -104,7 +63,7 @@ export default function EnergyEntryEdit(): JSX.Element { }); }, [loaded]); - if (!loaded || slidersData.length === 0) { + if (!loaded || user === undefined) { return <>; } diff --git a/frontend/src/screens/Transportation/transportationEntryEdit.tsx b/frontend/src/screens/Transportation/transportationEntryEdit.tsx index a5641ce..4385786 100644 --- a/frontend/src/screens/Transportation/transportationEntryEdit.tsx +++ b/frontend/src/screens/Transportation/transportationEntryEdit.tsx @@ -10,6 +10,8 @@ import { SafeAreaView } from 'react-native-safe-area-context'; import Slider from '@react-native-community/slider'; import { TransportationAPI } from '../../APIs/TransportationAPI'; import { type TransportationEntry } from '../../models/Transportation'; +import { UsersAPI } from '../../APIs/UsersAPI'; +import { type User } from '../../models/User'; export type StackNavigation = StackNavigationProp; @@ -32,6 +34,8 @@ export default function TransportationEntryEdit(): JSX.Element { const [trainTravel, setTrainTravel] = useState(0); const [bikeTravel, setBikeTravel] = useState(0); + const [user, setUser] = useState(undefined); + const onSliderValueChange = (value: number, index: number): void => { slidersData[index].initialValue = value; switch (index) { @@ -64,7 +68,7 @@ export default function TransportationEntryEdit(): JSX.Element { const handleSurveySubmit = (): void => { // Process survey responses, e.g., send them to a server - if (transportationEntry != null) { + if (transportationEntry != null && user != null) { const newEntry: TransportationEntry = { _id: transportationEntry._id, user_id: transportationEntry.user_id, @@ -75,7 +79,7 @@ export default function TransportationEntryEdit(): JSX.Element { gasoline_car: gasolineCarTravel, carbon_emissions: transportationEntry.carbon_emissions, date: transportationEntry.date, - fuel_efficiency: 1, + fuel_efficiency: user.fuel_efficiency, }; void TransportationAPI.updateTransportation(newEntry).then(() => { navigation.navigate('DashBoard'); @@ -125,6 +129,11 @@ export default function TransportationEntryEdit(): JSX.Element { }, [transportationEntry]); useEffect(() => { + void UsersAPI.GetLoggedInUser().then((res) => { + if (res != null) { + setUser(res); + } + }); void TransportationAPI.getTransportationMetricForToday().then((res) => { if (res != null) { setTransportationEntry(res); @@ -132,7 +141,7 @@ export default function TransportationEntryEdit(): JSX.Element { }); }, [loaded]); - if (!loaded || slidersData.length === 0) { + if (!loaded || slidersData.length === 0 || user === undefined) { return <>; } diff --git a/frontend/src/screens/Transportation/transportationForum.tsx b/frontend/src/screens/Transportation/transportationForum.tsx index cee2219..192d87e 100644 --- a/frontend/src/screens/Transportation/transportationForum.tsx +++ b/frontend/src/screens/Transportation/transportationForum.tsx @@ -10,6 +10,8 @@ import { SafeAreaView } from 'react-native-safe-area-context'; import Slider from '@react-native-community/slider'; import { TransportationAPI } from '../../APIs/TransportationAPI'; import { type TransportationEntry } from '../../models/Transportation'; +import { UsersAPI } from '../../APIs/UsersAPI'; +import { type User } from '../../models/User'; export type StackNavigation = StackNavigationProp; @@ -74,9 +76,11 @@ export default function TransportationForum(): JSX.Element { const [trainTravel, setTrainTravel] = useState(0); const [bikeTravel, setBikeTravel] = useState(0); + const [user, setUser] = useState(undefined); + const handleSurveySubmit = (): void => { // Process survey responses, e.g., send them to a server - if (transportationEntry != null) { + if (transportationEntry != null && user != null) { const newEntry: TransportationEntry = { _id: transportationEntry._id, user_id: transportationEntry.user_id, @@ -87,7 +91,7 @@ export default function TransportationForum(): JSX.Element { gasoline_car: gasolineCarTravel, carbon_emissions: transportationEntry.carbon_emissions, date: transportationEntry.date, - fuel_efficiency: 1, + fuel_efficiency: user.fuel_efficiency, }; void TransportationAPI.updateTransportation(newEntry).then(() => { navigation.navigate('FoodForum'); @@ -106,6 +110,11 @@ export default function TransportationForum(): JSX.Element { }, [transportationEntry]); useEffect(() => { + void UsersAPI.GetLoggedInUser().then((res) => { + if (res != null) { + setUser(res); + } + }); void TransportationAPI.getTransportationMetricForToday().then((res) => { if (res != null) { setTransportationEntry(res); @@ -113,7 +122,7 @@ export default function TransportationForum(): JSX.Element { }); }, [loaded]); - if (!loaded) { + if (!loaded || user === undefined) { return <>; } diff --git a/frontend/src/screens/footpringDecomp.tsx b/frontend/src/screens/footpringDecomp.tsx index d1c889b..e4aefdb 100644 --- a/frontend/src/screens/footpringDecomp.tsx +++ b/frontend/src/screens/footpringDecomp.tsx @@ -22,7 +22,6 @@ export default function FootprintDecomp(): JSX.Element { const [foodEntry, setFoodEntry] = useState(); const [energyEntry, setEnergyEntry] = useState(); - const navigation = useNavigation(); const [loaded] = useFonts({ @@ -38,22 +37,28 @@ export default function FootprintDecomp(): JSX.Element { }); void TransportationAPI.getTransportationMetricForToday().then((res) => { if (res != null) { - setTransportationEntry(res) + setTransportationEntry(res); } }); void FoodAPI.getFoodMetricForToday().then((res) => { if (res != null) { - setFoodEntry(res) + setFoodEntry(res); } }); void EnergyAPI.getEnergyMetricForToday().then((res) => { if (res != null) { - setEnergyEntry(res) + setEnergyEntry(res); } }); }, [loaded]); - if (!loaded || user === undefined || transportationEntry === undefined || foodEntry === undefined || energyEntry === undefined) { + if ( + !loaded || + user === undefined || + transportationEntry === undefined || + foodEntry === undefined || + energyEntry === undefined + ) { return <>; } @@ -66,7 +71,10 @@ export default function FootprintDecomp(): JSX.Element { navigation.navigate('TransportationHistory'); }} > - + @@ -76,7 +84,7 @@ export default function FootprintDecomp(): JSX.Element { navigation.navigate('FoodHistory'); }} > - + @@ -88,11 +96,13 @@ export default function FootprintDecomp(): JSX.Element { navigation.navigate('EnergyHistory'); }} > - + - ); } @@ -105,7 +115,7 @@ const styles = StyleSheet.create({ widgetContainer: { flexDirection: 'row', alignContent: 'center', - justifyContent: 'center' + justifyContent: 'center', }, widgetBoarder: { padding: 10, diff --git a/frontend/src/screens/settings/updateHomeScreen.tsx b/frontend/src/screens/settings/updateHomeScreen.tsx index 8b81b02..5e70e23 100644 --- a/frontend/src/screens/settings/updateHomeScreen.tsx +++ b/frontend/src/screens/settings/updateHomeScreen.tsx @@ -1,31 +1,23 @@ import React, { useState, useEffect } from 'react'; -import { - ScrollView, - View, - Text, - StyleSheet, - TouchableOpacity, - TextInput, -} from 'react-native'; +import { ScrollView, View, Text, StyleSheet, TouchableOpacity, TextInput } from 'react-native'; import Colors from '../../../assets/colorConstants'; import { type RootStackParamList } from '../../components/types'; import type { StackNavigationProp } from '@react-navigation/stack'; import { useNavigation } from '@react-navigation/native'; import Ionicons from '@expo/vector-icons/Ionicons'; import { useFonts } from 'expo-font'; -import {type User} from '../../models/User' +import { type User } from '../../models/User'; import { UsersAPI } from '../../APIs/UsersAPI'; import firebaseService from '../../utilities/firebase'; export type StackNavigation = StackNavigationProp; export default function UpdateHomeScreen(): JSX.Element { - const [newProvince, setNewProvince] = useState(''); const [newOccupancy, setNewOccupancy] = useState(0); + const [newFuelEfficiency, setNewFuelEfficiency] = useState(0); const [user, setUser] = useState(undefined); const [userid, setUserid] = useState(''); - const navigation = useNavigation(); const [loaded] = useFonts({ Montserrat: require('../../../assets/fonts/MontserratThinRegular.ttf'), @@ -44,40 +36,57 @@ export default function UpdateHomeScreen(): JSX.Element { }; void fetchUserData(); }, []); - console.log(userid) - + console.log(userid); const handleUpdateHome = async (): Promise => { try { console.log('Updating home info'); - console.log(newProvince) - console.log(newOccupancy) - + console.log(newProvince); + console.log(newOccupancy); + console.log(newFuelEfficiency); + if (newProvince !== '' && user !== undefined) { console.log('Updating province'); const updatedProvincialUser = await UsersAPI.updateUserProvince(user, newProvince); - + console.log('Updated user:', updatedProvincialUser); - + if (updatedProvincialUser != null) { setUser(updatedProvincialUser); console.log('Updated province'); } } - + if (newOccupancy !== undefined && user !== undefined) { console.log('Updating occupancy'); const updatedOccupancyUser = await UsersAPI.updateUserOccupancy(user, newOccupancy); - + console.log('Updated user:', updatedOccupancyUser); - + if (updatedOccupancyUser != null) { setUser(updatedOccupancyUser); console.log('Updated occupancy'); } - + console.log('User household:', updatedOccupancyUser?.household); } + + if (newFuelEfficiency !== undefined && user !== undefined) { + console.log('Updating fuel efficiency'); + const updatedFuelEfficiencyUser = await UsersAPI.updateUserFuelEfficiency( + user, + newFuelEfficiency + ); + + console.log('Updated user:', updatedFuelEfficiencyUser); + + if (updatedFuelEfficiencyUser != null) { + setUser(updatedFuelEfficiencyUser); + console.log('Updated occupancy'); + } + + console.log('User household:', updatedFuelEfficiencyUser?.fuel_efficiency); + } } catch (e) { console.error('Updating Home Info error occurred:', e); } @@ -102,21 +111,32 @@ export default function UpdateHomeScreen(): JSX.Element { How many people live in your home?: setNewOccupancy(parseInt(number))} /> Your Province: setNewProvince(text)} /> + Your fuel efficiency: + setNewFuelEfficiency(parseFloat(float))} + /> - { void handleUpdateHome()}}> + { + void handleUpdateHome(); + }} + > Confirm Update diff --git a/frontend/src/screens/signUpQuestions.tsx b/frontend/src/screens/signUpQuestions.tsx index db488c1..5b146b4 100644 --- a/frontend/src/screens/signUpQuestions.tsx +++ b/frontend/src/screens/signUpQuestions.tsx @@ -68,6 +68,7 @@ export default function SignUpQuestions(): JSX.Element { try { void UsersAPI.updateUserProvince(user, province); void UsersAPI.updateUserOccupancy(user, numOfPpl); + void UsersAPI.updateUserFuelEfficiency(user, fuelEfficiency); } catch (error) { // Handle errors if any of the updates fail console.error(error); diff --git a/frontend/src/screens/yourForms.tsx b/frontend/src/screens/yourForms.tsx index 51d0724..aac7490 100644 --- a/frontend/src/screens/yourForms.tsx +++ b/frontend/src/screens/yourForms.tsx @@ -98,7 +98,7 @@ export default function YourForms(): JSX.Element { }} > - This Week's Food Entry: {foodEntry.carbon_emissions.toString()} + This Week's Food Entry: {Math.round(foodEntry.carbon_emissions).toString()} - This Week's Transportation Entry: {transportationEntry.carbon_emissions.toString()} + This Week's Transportation Entry:{' '} + {Math.round(transportationEntry.carbon_emissions).toString()} - This Week's Energy Entry: {energyEntry.carbon_emissions.toString()} + This Week's Energy Entry: {Math.round(energyEntry.carbon_emissions).toString()} From 97be938a6430c4c85f017483b324be5633e379d2 Mon Sep 17 00:00:00 2001 From: Ishav Sohal Date: Sat, 16 Dec 2023 18:07:36 -0500 Subject: [PATCH 5/5] uncommented try except --- backend/routes/transportation.py | 6 +- backend/routes/users.py | 170 +++++++++++++++---------------- 2 files changed, 88 insertions(+), 88 deletions(-) diff --git a/backend/routes/transportation.py b/backend/routes/transportation.py index a3473fa..9e809ac 100644 --- a/backend/routes/transportation.py +++ b/backend/routes/transportation.py @@ -52,7 +52,7 @@ def get_transportation_entries_for_user_using_date_range() -> Response: @transportation_service.route("/get_transportation_metric_for_today", methods=['GET']) @carbon_auth.auth.login_required def get_transportation_metric_for_today() -> Response: - #try: + try: user = FirebaseAPI.get_user(flask.request.headers.get('Authorization').split()[1]) query = {"user_id": ObjectId(user.oid), "date": weekly_metric_reset(datetime.now())} item = CarbonTrackDB.transportation_coll.find_one(query) @@ -62,8 +62,8 @@ def get_transportation_metric_for_today() -> Response: else: item = TransportationEntry.from_json(item).to_json() return jsonify({'transportation': item}) - #except CarbonTrackError as e: - # abort(code=400, description=f"{e}") + except CarbonTrackError as e: + abort(code=400, description=f"{e}") @carbon_auth.auth.login_required diff --git a/backend/routes/users.py b/backend/routes/users.py index 6888a40..e6a0d6c 100644 --- a/backend/routes/users.py +++ b/backend/routes/users.py @@ -26,71 +26,71 @@ def get_user(user_id: str) -> Response: @users.route("/get_top_users", methods=["POST"]) @carbon_auth.auth.login_required def get_top_users() -> Response: - # try: - count = request.get_json()["count"] - - # Monthly - _top_monthly_users = ( - CarbonTrackDB.users_coll.find().sort("monthly_score", -1).limit(count) - ) - top_monthly_users = [] - rank = 1 - for user in _top_monthly_users: - obj = User.from_json(user) - user = { - "rank": rank, - "name": obj.full_name, - "footprint": 0, - "score": obj.overall_score, - } - rank += 1 - top_monthly_users.append(user) - - # Yearly - _top_yearly_users = ( - CarbonTrackDB.users_coll.find().sort("yearly_score", -1).limit(count) - ) - top_yearly_users = [] - rank = 1 - for user in _top_yearly_users: - obj = User.from_json(user) - user = { - "rank": rank, - "name": obj.full_name, - "footprint": 0, - "score": obj.overall_score, - } - rank += 1 - top_yearly_users.append(user) - - # Overall - _top_overall_users = ( - CarbonTrackDB.users_coll.find().sort("overall_score", -1).limit(count) - ) - top_overall_users = [] - rank = 1 - for user in _top_overall_users: - obj = User.from_json(user) - user = { - "rank": rank, - "name": obj.full_name, - "footprint": 0, - "score": obj.overall_score, - } - rank += 1 - top_overall_users.append(user) - - return jsonify( - { - "top_monthly_users": top_monthly_users, - "top_yearly_users": top_yearly_users, - "top_overall_users": top_overall_users, - } - ) - - -# except CarbonTrackError as e: -# abort(code=400, description=f"{e}") + try: + count = request.get_json()["count"] + + # Monthly + _top_monthly_users = ( + CarbonTrackDB.users_coll.find().sort("monthly_score", -1).limit(count) + ) + top_monthly_users = [] + rank = 1 + for user in _top_monthly_users: + obj = User.from_json(user) + user = { + "rank": rank, + "name": obj.full_name, + "footprint": 0, + "score": obj.overall_score, + } + rank += 1 + top_monthly_users.append(user) + + # Yearly + _top_yearly_users = ( + CarbonTrackDB.users_coll.find().sort("yearly_score", -1).limit(count) + ) + top_yearly_users = [] + rank = 1 + for user in _top_yearly_users: + obj = User.from_json(user) + user = { + "rank": rank, + "name": obj.full_name, + "footprint": 0, + "score": obj.overall_score, + } + rank += 1 + top_yearly_users.append(user) + + # Overall + _top_overall_users = ( + CarbonTrackDB.users_coll.find().sort("overall_score", -1).limit(count) + ) + top_overall_users = [] + rank = 1 + for user in _top_overall_users: + obj = User.from_json(user) + user = { + "rank": rank, + "name": obj.full_name, + "footprint": 0, + "score": obj.overall_score, + } + rank += 1 + top_overall_users.append(user) + + return jsonify( + { + "top_monthly_users": top_monthly_users, + "top_yearly_users": top_yearly_users, + "top_overall_users": top_overall_users, + } + ) + + + except CarbonTrackError as e: + abort(code=400, description=f"{e}") @users.route("/user_email/", methods=["GET"]) @@ -140,26 +140,26 @@ def get_current_user() -> Response: @users.route("/user", methods=["PUT"]) @carbon_auth.auth.login_required def create_user() -> Response: - # try: - res: dict = request.get_json()["user"] - user = User.from_json(res) - user.email = user.email.lower() - - query = {"email": user.email} - item = CarbonTrackDB.users_coll.find_one(query) - if item is None: - user = user.to_json() - inserted_id = CarbonTrackDB.users_coll.insert_one(user).inserted_id - user = User.from_json( - CarbonTrackDB.users_coll.find_one({"_id": inserted_id}) - ).to_json() - return jsonify({"user": user}) - else: - return jsonify({"error": "User Already Exits With Same Email, Please Log In"}) - - -# except CarbonTrackError as e: -# abort(code=400, description=f"{e}") + try: + res: dict = request.get_json()["user"] + user = User.from_json(res) + user.email = user.email.lower() + + query = {"email": user.email} + item = CarbonTrackDB.users_coll.find_one(query) + if item is None: + user = user.to_json() + inserted_id = CarbonTrackDB.users_coll.insert_one(user).inserted_id + user = User.from_json( + CarbonTrackDB.users_coll.find_one({"_id": inserted_id}) + ).to_json() + return jsonify({"user": user}) + else: + return jsonify({"error": "User Already Exits With Same Email, Please Log In"}) + + + except CarbonTrackError as e: + abort(code=400, description=f"{e}") @users.route("/user/", methods=["DELETE"])