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': [] } if row['topset_id']: 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