Refactor calendar (month and year view), switching to vertical slice arch. Also in progress of refactoring of stats so they are retreived after inital page load for performance sake
This commit is contained in:
141
features/calendar.py
Normal file
141
features/calendar.py
Normal file
@@ -0,0 +1,141 @@
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import pandas as pd
|
||||
|
||||
class Calendar:
|
||||
def __init__(self, db_connection_method):
|
||||
self.execute = db_connection_method
|
||||
|
||||
def fetch_workouts_for_person(self, person_id, date, view):
|
||||
prev_date, next_date = None, None
|
||||
if view == 'month':
|
||||
first_day_of_month = date.replace(day=1)
|
||||
days_to_subtract = (first_day_of_month.weekday() + 1) % 7
|
||||
start_date = first_day_of_month - timedelta(days=days_to_subtract)
|
||||
end_date = start_date + timedelta(days=6 * 7 - 1)
|
||||
prev_date = first_day_of_month - relativedelta(months=1)
|
||||
next_date = first_day_of_month + relativedelta(months=1)
|
||||
elif view == 'year':
|
||||
start_date = date.replace(month=1, day=1)
|
||||
end_date = date.replace(year=date.year + 1, month=1, day=1) - timedelta(days=1)
|
||||
prev_date = date - relativedelta(years=1)
|
||||
next_date = date + relativedelta(years=1)
|
||||
else:
|
||||
raise ValueError('Invalid view')
|
||||
|
||||
query = """
|
||||
SELECT
|
||||
w.workout_id,
|
||||
w.start_date,
|
||||
t.topset_id,
|
||||
t.repetitions,
|
||||
t.weight,
|
||||
e.name AS exercise_name,
|
||||
p.name AS person_name
|
||||
FROM
|
||||
person p
|
||||
LEFT JOIN workout w ON p.person_id = w.person_id AND w.start_date BETWEEN %s AND %s
|
||||
LEFT JOIN topset t ON w.workout_id = t.workout_id
|
||||
LEFT JOIN exercise e ON t.exercise_id = e.exercise_id
|
||||
WHERE
|
||||
p.person_id = %s
|
||||
ORDER BY
|
||||
w.start_date,
|
||||
t.topset_id;
|
||||
"""
|
||||
workouts_data = self.execute(query, [start_date, end_date, person_id])
|
||||
|
||||
# Assuming person_name is the same for all rows as we filter by person_id
|
||||
person_name = workouts_data[0]['person_name'] if workouts_data else 'Unknown'
|
||||
|
||||
calendar_view = {'prev_date': prev_date, 'next_date': next_date, 'person_id': person_id, 'person_name': person_name, 'view': view, 'date': date}
|
||||
|
||||
if view == 'month':
|
||||
calendar_view['days'] = []
|
||||
workouts_by_date = {}
|
||||
|
||||
for row in workouts_data:
|
||||
if row['workout_id'] is None:
|
||||
continue # Skip rows that don't have workout data
|
||||
|
||||
workout_date_str = row['start_date'].strftime("%Y-%m-%d")
|
||||
workout_id = row['workout_id']
|
||||
|
||||
if workout_date_str not in workouts_by_date:
|
||||
workouts_by_date[workout_date_str] = {}
|
||||
|
||||
if workout_id not in workouts_by_date[workout_date_str]:
|
||||
workouts_by_date[workout_date_str][workout_id] = {
|
||||
'workout_id': workout_id,
|
||||
'start_date': row['start_date'],
|
||||
'sets': []
|
||||
}
|
||||
|
||||
workouts_by_date[workout_date_str][workout_id]['sets'].append({
|
||||
'repetitions': row['repetitions'],
|
||||
'weight': row['weight'],
|
||||
'exercise_name': row['exercise_name']
|
||||
})
|
||||
|
||||
for current_date in pd.date_range(start_date, end_date, freq='D'):
|
||||
date_str = current_date.strftime("%Y-%m-%d")
|
||||
day_workouts = workouts_by_date.get(date_str, {})
|
||||
today = datetime.today().date()
|
||||
|
||||
calendar_view['days'].append({
|
||||
'day': current_date.day,
|
||||
'is_today': current_date == today,
|
||||
'is_in_current_month': current_date.month == date.month, # Ensure it compares with the selected month
|
||||
'has_workouts': len(day_workouts) > 0,
|
||||
'workouts': list(day_workouts.values())
|
||||
})
|
||||
|
||||
|
||||
elif view == 'year':
|
||||
calendar_view['months'] = []
|
||||
workouts_by_date = {}
|
||||
for row in workouts_data:
|
||||
if row['start_date'] is None:
|
||||
continue # Skip rows that don't have workout data
|
||||
workout_date_str = row['start_date'].strftime("%Y-%m-%d")
|
||||
if workout_date_str not in workouts_by_date:
|
||||
workouts_by_date[workout_date_str] = []
|
||||
|
||||
workouts_by_date[workout_date_str].append({
|
||||
'workout_id': row['workout_id'],
|
||||
'start_date': row['start_date'],
|
||||
'topset_id': row['topset_id'],
|
||||
'repetitions': row['repetitions'],
|
||||
'weight': row['weight'],
|
||||
'exercise_name': row['exercise_name']
|
||||
})
|
||||
|
||||
|
||||
for month in range(1, 13):
|
||||
first_day_of_month = date.replace(month=month, day=1)
|
||||
days_to_subtract = (first_day_of_month.weekday() + 1) % 7
|
||||
start_date = first_day_of_month - timedelta(days=days_to_subtract)
|
||||
end_date = start_date + timedelta(days=6 * 7 - 1)
|
||||
|
||||
month_data = {'name': first_day_of_month.strftime('%B'), 'first_day_of_month': first_day_of_month, 'days': []}
|
||||
|
||||
current_day = start_date
|
||||
while current_day <= end_date:
|
||||
day_workouts = workouts_by_date.get(current_day.strftime('%Y-%m-%d'), [])
|
||||
has_workouts = len(day_workouts) > 0
|
||||
first_workout_id = day_workouts[0]['workout_id'] if has_workouts else None
|
||||
|
||||
day_data = {
|
||||
'day': current_day.day,
|
||||
'is_today': current_day == datetime.today().date(),
|
||||
'is_in_current_month': current_day.month == month,
|
||||
'workouts': day_workouts,
|
||||
'has_workouts': has_workouts,
|
||||
'first_workout_id': first_workout_id
|
||||
}
|
||||
month_data['days'].append(day_data)
|
||||
current_day += timedelta(days=1)
|
||||
|
||||
calendar_view['months'].append(month_data)
|
||||
|
||||
return calendar_view
|
||||
85
features/stats.py
Normal file
85
features/stats.py
Normal file
@@ -0,0 +1,85 @@
|
||||
from collections import Counter
|
||||
from datetime import date
|
||||
|
||||
class Stats:
|
||||
def __init__(self, db_connection_method):
|
||||
self.execute = db_connection_method
|
||||
|
||||
def get_stats_from_topsets(self, topsets):
|
||||
if not topsets:
|
||||
return []
|
||||
|
||||
# Extracting necessary fields
|
||||
workout_ids = [t['WorkoutId'] for t in topsets if t['WorkoutId']]
|
||||
person_ids = [t['PersonId'] for t in topsets if t['PersonId']]
|
||||
start_dates = [t['StartDate'] for t in topsets if t['StartDate']]
|
||||
|
||||
workout_count = len(set(workout_ids))
|
||||
people_count = len(set(person_ids))
|
||||
total_sets = len(topsets)
|
||||
stats = [
|
||||
{"Text": "Total Workouts", "Value": workout_count},
|
||||
{"Text": "Total Sets", "Value": total_sets}
|
||||
]
|
||||
|
||||
if people_count > 1:
|
||||
stats.append({"Text": "People tracked", "Value": people_count})
|
||||
|
||||
if workout_count > 0:
|
||||
first_workout_date = min(start_dates)
|
||||
last_workout_date = max(start_dates)
|
||||
current_date = date.today()
|
||||
|
||||
stats.append({"Text": "Days Since First Workout",
|
||||
"Value": (current_date - first_workout_date).days})
|
||||
|
||||
if workout_count >= 2:
|
||||
stats.append({"Text": "Days Since Last Workout",
|
||||
"Value": (current_date - last_workout_date).days})
|
||||
|
||||
average_sets_per_workout = round(total_sets / workout_count, 1)
|
||||
stats.append({"Text": "Average sets per workout",
|
||||
"Value": average_sets_per_workout})
|
||||
|
||||
training_duration = last_workout_date - first_workout_date
|
||||
if training_duration.days > 0:
|
||||
average_workouts_per_week = round(
|
||||
workout_count / (training_duration.days / 7), 1)
|
||||
stats.append({"Text": "Average Workouts Per Week",
|
||||
"Value": average_workouts_per_week})
|
||||
|
||||
return stats
|
||||
|
||||
|
||||
def fetch_stats_for_person(self, person_id):
|
||||
query = """
|
||||
SELECT
|
||||
t.workout_id AS "WorkoutId",
|
||||
w.person_id AS "PersonId",
|
||||
w.start_date AS "StartDate"
|
||||
FROM
|
||||
topset t
|
||||
JOIN workout w ON t.workout_id = w.workout_id
|
||||
JOIN person p ON w.person_id = p.person_id
|
||||
WHERE p.person_id = %s
|
||||
"""
|
||||
workouts_data = self.execute(query, [person_id])
|
||||
|
||||
person_stats = self.get_stats_from_topsets(workouts_data)
|
||||
return person_stats
|
||||
|
||||
def fetch_all_stats(self):
|
||||
query = """
|
||||
SELECT
|
||||
t.workout_id AS "WorkoutId",
|
||||
w.person_id AS "PersonId",
|
||||
w.start_date AS "StartDate"
|
||||
FROM
|
||||
topset t
|
||||
JOIN workout w ON t.workout_id = w.workout_id
|
||||
JOIN person p ON w.person_id = p.person_id;
|
||||
"""
|
||||
workouts_data = self.execute(query, [])
|
||||
|
||||
person_stats = self.get_stats_from_topsets(workouts_data)
|
||||
return person_stats
|
||||
Reference in New Issue
Block a user