Skip to content

Commit

Permalink
Added Metrics Hisotry
Browse files Browse the repository at this point in the history
  • Loading branch information
Yazan10x committed Nov 22, 2023
1 parent cad419e commit 562bede
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 76 deletions.
50 changes: 47 additions & 3 deletions backend/models/transportation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
"""

from __future__ import annotations
from typing import Union
import json
from datetime import datetime
from datetime import datetime, timezone, timedelta
from models.abstract_db_model import DB_MODEL
from bson import ObjectId
from bson import json_util
Expand All @@ -22,7 +23,7 @@ class TransportationEntry(DB_MODEL):
date: datetime

def __init__(self, oid: ObjectId, user_id: ObjectId, bus: int, train: int, motorbike: int,
electric_car: int, gasoline_car: int, carbon_emissions: float, date: datetime) -> None:
electric_car: int, gasoline_car: int, carbon_emissions: float, date: Union[str, datetime]) -> None:
super().__init__(oid)
self.user_id = ObjectId(user_id)
self.bus = bus
Expand All @@ -31,7 +32,10 @@ def __init__(self, oid: ObjectId, user_id: ObjectId, bus: int, train: int, motor
self.electric_car = electric_car
self.gasoline_car = gasoline_car
self.carbon_emissions = carbon_emissions
self.date = date
if isinstance(date, datetime):
self.date = date
else:
self.date = datetime.fromisoformat(date)

def to_json(self, for_mongodb: bool = False) -> json:
res = {
Expand Down Expand Up @@ -72,5 +76,45 @@ def calculate_carbon_emissions(self) -> float:
return sum([bus_carbon_emissions, train_carbon_emissions, motorbike_carbon_emissions,
electric_car_carbon_emissions, gasoline_car_carbon_emissions])

@staticmethod
def get_monthly_view(start: datetime, end: datetime,
transportationEntries: list[TransportationEntry]) -> list[dict[str, Union[list[float], str]]]:
monthly_data = []

# Make start date offset-aware (assuming UTC for simplicity)
start = start.replace(tzinfo=timezone.utc)

current_month = start
while current_month <= end:
# Add the current month to the list
monthly_data.append({
'month': current_month.strftime('%B'),
'year': current_month.strftime('%Y'),
'data': [0, 0, 0, 0]
})

# Move to the next month
if current_month.month == 12:
current_month = datetime(current_month.year + 1, 1, 1, tzinfo=timezone.utc)
else:
current_month = datetime(current_month.year, current_month.month + 1, 1, tzinfo=timezone.utc)

for transportation_entry in transportationEntries:
for monthly_entry in monthly_data:
if transportation_entry.date.strftime('%B') == monthly_entry['month'] \
and transportation_entry.date.strftime('%Y') == monthly_entry['year']:
if transportation_entry.date.day < 7:
monthly_entry['data'][0] = transportation_entry.calculate_carbon_emissions()
elif transportation_entry.date.day < 14:
monthly_entry['data'][1] = transportation_entry.calculate_carbon_emissions()
elif transportation_entry.date.day < 21:
monthly_entry['data'][2] = transportation_entry.calculate_carbon_emissions()
elif transportation_entry.date.day < 28:
monthly_entry['data'][3] += transportation_entry.calculate_carbon_emissions()
else: # If a Month has 5 sunday, we add them to the fourth week
monthly_entry['data'][3] += transportation_entry.calculate_carbon_emissions()

return monthly_data

def __repr__(self) -> str:
return f'Transportation ID: {self.oid.__str__()}'
30 changes: 19 additions & 11 deletions backend/routes/transportation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
from datetime import datetime
from bson import ObjectId
from flask import Blueprint, Response, jsonify, request
import flask

from models.transportation import TransportationEntry
from mongodb_api.carbon_track_db import CarbonTrackDB
from routes import carbon_auth
from utils.metric_resets import weekly_metric_reset, get_1_day_range
from utils.metric_resets import weekly_metric_reset
from utils.FirebaseAPI import FirebaseAPI

transportation_service = Blueprint('/transportation', __name__)

Expand All @@ -20,27 +22,31 @@ def get_transportation(oid: str) -> Response:
return jsonify({'transportation': item})


@transportation_service.route("/get_transportations_entries_for_user_using_data_range/<user_id>", methods=['POST'])
@transportation_service.route("/get_transportations_entries_for_user_using_data_range", methods=['POST'])
@carbon_auth.auth.login_required
def get_transportations_entries_for_user_using_date_range(user_id: str) -> Response[list[TransportationEntry]]:
def get_transportations_entries_for_user_using_date_range() -> Response:
user = FirebaseAPI.get_user(flask.request.headers.get('Authorization').split()[1])
data = request.get_json()
start = data.get('start')
end = data.get('end')
start = datetime.fromisoformat(data.get('start'))
end = datetime.fromisoformat(data.get('end'))
# Validate that both start and end dates are provided
if not start or not end:
return jsonify({'error': 'Both start and end dates are required'})

query = {"user_id": ObjectId(user_id), "date": {"$gte": start, "$lte": end}}
query = {"user_id": ObjectId(user.oid), "date": {"$gte": start, "$lte": end}}
items = list(CarbonTrackDB.transportation_coll.find(query))
items = [TransportationEntry.from_json(item).to_json() for item in items]
return jsonify({'transportations': items})
transportation_items: list[TransportationEntry] = [TransportationEntry.from_json(item) for item in items]
json_items = [item.to_json() for item in transportation_items]
return jsonify({
'transportationEntries': json_items,
'monthlyData': TransportationEntry.get_monthly_view(start, end, transportation_items)
})


@transportation_service.route("/get_transportation_metric_for_today/<user_id>", methods=['GET'])
@carbon_auth.auth.login_required
def get_transportation_metric_for_today(user_id: str) -> Response:
start_of_day, end_of_day = get_1_day_range(datetime.now())
query = {"user_id": ObjectId(user_id), "date": {"$gte": start_of_day, "$lte": end_of_day}}
query = {"user_id": ObjectId(user_id), "date": weekly_metric_reset(datetime.now())}
item = CarbonTrackDB.transportation_coll.find_one(query)
if item is None:
create_transportation(ObjectId(user_id))
Expand All @@ -64,7 +70,9 @@ def create_transportation(user_id: ObjectId) -> Response:
@carbon_auth.auth.login_required
def update_transportation(oid: str) -> Response:
query = {"_id": ObjectId(oid)}
transportation = TransportationEntry.from_json(request.get_json()['transportation']).to_json(for_mongodb=True)
transportation: dict = TransportationEntry.from_json(request.get_json()['transportation']).to_json(for_mongodb=True)
del transportation['date']
del transportation['user_id']
CarbonTrackDB.transportation_coll.update_one(query, {'$set': transportation})
item = CarbonTrackDB.transportation_coll.find_one(query)
item = TransportationEntry.from_json(item).to_json()
Expand Down
7 changes: 0 additions & 7 deletions backend/utils/metric_resets.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,3 @@ def weekly_metric_reset(d: datetime) -> datetime:
previous_sunday = d - timedelta(days=days_until_sunday)
date = datetime(year=previous_sunday.year, month=previous_sunday.month, day=previous_sunday.day)
return date


def get_1_day_range(d: datetime) -> tuple[datetime, datetime]:
d = weekly_metric_reset(d)
end = datetime(year=d.year, month=d.month, day=d.day) + timedelta(days=1)
start = datetime(year=d.year, month=d.month, day=d.day) - timedelta(days=1)
return start, end
98 changes: 51 additions & 47 deletions frontend/src/APIs/TransportationAPI.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,58 @@
import FLASK_HTTPS from './FLASK_API';
import type ObjectID from 'bson-objectid';
import type { Transportation } from '../models/Transportation';
import type { Transportation, TransportationRes } from '../models/Transportation';

const routeName = '/transportation';

export const getTransportation = async (transportationID: ObjectID): Promise<undefined | Transportation> => {
try {
const res = await FLASK_HTTPS.get(routeName + '/transportation/' + transportationID.str);
return res.data.transportation as Transportation;
} catch (error) {
console.error('Error fetching transportation from Flask BE: ', error);
console.error('Temp tip: have you started the backend?: ');
return undefined;
}
};

export const getTransportationsEntriesForUserUsingDataRange = async (userID: ObjectID, start: Date, end: Date): Promise<undefined | Transportation[]> => {
try {
const res = await FLASK_HTTPS.post(routeName + '/get_transportations_entries_for_user_using_data_range/' + userID.str, {
start,
end
});
return res.data.transportation as Transportation[];
} catch (error) {
console.error('Error fetching transportation from Flask BE: ', error);
console.error('Temp tip: have you started the backend?: ');
return undefined;
}
};

export const getTransportationMetricForToday = async (userID: ObjectID): Promise<undefined | Transportation> => {
try {
const res = await FLASK_HTTPS.get(routeName + '/get_transportation_metric_for_today/' + userID.str);
return res.data.transportation as Transportation;
} catch (error) {
console.error('Error fetching transportation from Flask BE: ', error);
console.error('Temp tip: have you started the backend?: ');
return undefined;
}
};
export const TransportationAPI = {

export const updateTransportation = async (transportation: Transportation): Promise<undefined | Transportation> => {
try {
const res = await FLASK_HTTPS.patch(routeName + '/transportation/' + transportation._id.str, {
transportation,
});
return res.data.transportation as Transportation;
} catch (error) {
console.error('Error fetching transportation from Flask BE: ', error);
console.error('Temp tip: have you started the backend?: ');
return undefined;
getTransportation: async (transportationID: ObjectID) => {
try {
const res = await FLASK_HTTPS.get(routeName + '/transportation/' + transportationID.str);
return res.data.transportation as Transportation;
} catch (error) {
console.error('Error fetching transportation from Flask BE: ', error);
console.error('Temp tip: have you started the backend?: ');
return undefined;
}
},

getTransportationsEntriesForUserUsingDataRange: async (start: Date, end: Date) => {
try {
const res = await FLASK_HTTPS.post(routeName + '/get_transportations_entries_for_user_using_data_range', {
start,
end
});
console.log("Yazan")
return res.data.transportation as TransportationRes;
} catch (error) {
console.error('Error fetching transportation from Flask BE: ', error);
console.error('Temp tip: have you started the backend?: ');
return undefined;
}
},

getTransportationMetricForToday: async (userID: ObjectID): Promise<undefined | Transportation> => {
try {
const res = await FLASK_HTTPS.get(routeName + '/get_transportation_metric_for_today/' + userID.str);
return res.data.transportation as Transportation;
} catch (error) {
console.error('Error fetching transportation from Flask BE: ', error);
console.error('Temp tip: have you started the backend?: ');
return undefined;
}
},

updateTransportation: async (transportation: Transportation): Promise<undefined | Transportation> => {
try {
const res = await FLASK_HTTPS.patch(routeName + '/transportation/' + transportation._id.str, {
transportation,
});
return res.data.transportation as Transportation;
} catch (error) {
console.error('Error fetching transportation from Flask BE: ', error);
console.error('Temp tip: have you started the backend?: ');
return undefined;
}
}
};
}
11 changes: 11 additions & 0 deletions frontend/src/models/Transportation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,15 @@ export interface Transportation {
gasoline_car: number
carbon_emmisions: number
date: Date
}

export interface MonthlyEntry {
'data': number[]
'month': string
'year': string
}

export interface TransportationRes {
transportationEntries: []
monthlyData: []
}
28 changes: 20 additions & 8 deletions frontend/src/screens/transportationHistory.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import { View, Text, TouchableOpacity, StyleSheet, SafeAreaView, ScrollView } from 'react-native';
import Colors from '../../assets/colorConstants';
import { useFonts } from 'expo-font';
import { BarChart } from 'react-native-chart-kit';
import { TransportationAPI } from '../APIs/TransportationAPI';
import { type MonthlyEntry } from '../models/Transportation';


export default function TransportationHistory(): JSX.Element {
const monthlyData = [
{ month: 'September', data: [20, 25, 30, 22] },
{ month: 'November', data: [18, 24, 16, 4] },
// Add data for other months...
];

const [expandedStates, setExpandedStates] = useState(Array(monthlyData.length).fill(false));
const [expandedStates, setExpandedStates] = useState(Array(100).fill(false));
const [monthlyData, setMonthlyData] = useState<MonthlyEntry[]>();

const toggleExpanded = (index: number): void => {
const updatedStates = [...expandedStates];
Expand All @@ -27,7 +26,20 @@ export default function TransportationHistory(): JSX.Element {
Montserrat: require('../../assets/fonts/MontserratThinRegular.ttf'),
Josefin: require('../../assets/fonts/JosefinSansThinRegular.ttf'),
});
if (!loaded) {

useEffect(() => {
void TransportationAPI.getTransportationsEntriesForUserUsingDataRange(new Date(2023, 1, 1), new Date(2023, 12, 1)).then((res) => {
if (res != null) {
if (res.monthlyData != null) {
setMonthlyData(res.monthlyData)
console.log(res)
}
}
console.log(res)
});
}, [loaded])

if (!loaded || monthlyData === undefined) {
return <></>;
}

Expand Down

0 comments on commit 562bede

Please sign in to comment.