From cd03256245d2ecac28fdb3c1bcdd189793a1aca3 Mon Sep 17 00:00:00 2001 From: Peter Stockings Date: Fri, 13 Oct 2023 17:27:06 +1100 Subject: [PATCH] Allow user to browse next/prev month on calendar --- app.py | 139 +++++++++++++++++-------------- templates/partials/calendar.html | 16 ++-- templates/workouts_list.html | 2 +- 3 files changed, 89 insertions(+), 68 deletions(-) diff --git a/app.py b/app.py index bee7c23..076041b 100644 --- a/app.py +++ b/app.py @@ -279,6 +279,14 @@ def update_users_bike(user_id): return jsonify({'error': 'User or bike not found.'}), 404 +@ app.route('/user//calendar', methods=['GET']) +def calendar_view(user_id): + workouts = get_workouts_for_user(user_id) + date = request.args.get('date', default=datetime.now().date(), type=toDate) + calendar_month = generate_calendar_monthly_view(workouts, date) + return render_template('partials/calendar.html', calendar_month=calendar_month, user_id=user_id) + + def render_users_and_workouts(): users = User.query.all() users_data = [] @@ -327,67 +335,6 @@ def render_users_and_workouts(): duration_sparkline = sparklines.sparklines( [int(w['duration_minutes']) for w in workouts])[0] - # Generate a monthly calendar view of the workouts - def get_month_bounds(dt): - # First day of the month - first_day_of_month = dt.replace(day=1) - - # Last day of the month - next_month = first_day_of_month + relativedelta(months=1) - last_day_of_month = next_month - timedelta(days=1) - - start = dict( - [(6, 0), (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) - start_date = first_day_of_month - \ - timedelta(days=start[first_day_of_month.weekday()]) - - end = dict([(6, 6), (0, 5), (1, 4), - (2, 3), (3, 2), (4, 1), (5, 0)]) - end_date = last_day_of_month + \ - timedelta(days=end[last_day_of_month.weekday()]) - - return start_date, end_date - - def date_range(start_date, end_date): - current_date = start_date - while current_date <= end_date: - yield current_date - current_date += timedelta(days=1) - - def get_workout_for_date(workouts, date): - for w in workouts: - if w['start_time_date'].date() == date: - return w - return None - - current_date = datetime.now().date() - start_date, end_date = get_month_bounds(current_date) - monthly_workouts = [w for w in workouts if start_date <= - w['start_time_date'].date() <= end_date] - - days_of_month = [ - { - 'date': single_date, - 'day_of_month': single_date.day, - 'is_workout': bool(workout), - 'workout': workout if workout else None, - 'is_current_date': single_date == current_date, - 'is_current_month': single_date.month == current_date.month and single_date.year == current_date.year - } - for single_date in date_range(start_date, end_date) - for workout in [get_workout_for_date(monthly_workouts, single_date)] - ] - - next_month_date = current_date + relativedelta(months=1) - previous_month_date = current_date - relativedelta(months=1) - - calendar_month = { - 'month_year': current_date.strftime('%B, %Y'), - 'days_of_month': days_of_month, - 'next_month': next_month_date, - 'previous_month': previous_month_date, - } - user_data = { 'id': user.id, 'name': user.name, @@ -399,7 +346,7 @@ def render_users_and_workouts(): 'num_days': num_days, 'workout_counts_sparkline': workout_counts_sparkline, 'duration_sparkline': duration_sparkline, - 'calendar_month': calendar_month + 'calendar_month': generate_calendar_monthly_view(workouts, datetime.now().date()) } users_data.append(user_data) @@ -502,6 +449,74 @@ def format_duration(duration): return f"{minutes}m" +def generate_calendar_monthly_view(workouts, selected_date): + # Generate a monthly calendar view of the workouts + def get_month_bounds(dt): + # First day of the month + first_day_of_month = dt.replace(day=1) + + # Last day of the month + next_month = first_day_of_month + relativedelta(months=1) + last_day_of_month = next_month - timedelta(days=1) + + start = dict( + [(6, 0), (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]) + start_date = first_day_of_month - \ + timedelta(days=start[first_day_of_month.weekday()]) + + end = dict([(6, 6), (0, 5), (1, 4), + (2, 3), (3, 2), (4, 1), (5, 0)]) + end_date = last_day_of_month + \ + timedelta(days=end[last_day_of_month.weekday()]) + + return start_date, end_date + + def date_range(start_date, end_date): + current_date = start_date + while current_date <= end_date: + yield current_date + current_date += timedelta(days=1) + + def get_workout_for_date(workouts, date): + for w in workouts: + if w['start_time_date'].date() == date: + return w + return None + + start_date, end_date = get_month_bounds(selected_date) + monthly_workouts = [w for w in workouts if start_date <= + w['start_time_date'].date() <= end_date] + + current_date = datetime.now().date() + days_of_month = [ + { + 'date': single_date, + 'day_of_month': single_date.day, + 'is_workout': bool(workout), + 'workout': workout if workout else None, + 'is_current_date': single_date == current_date, + 'is_current_month': single_date.month == selected_date.month and single_date.year == selected_date.year + } + for single_date in date_range(start_date, end_date) + for workout in [get_workout_for_date(monthly_workouts, single_date)] + ] + + next_month_date = selected_date + relativedelta(months=1) + previous_month_date = selected_date - relativedelta(months=1) + + calendar_month = { + 'month_year': selected_date.strftime('%B, %Y'), + 'days_of_month': days_of_month, + 'next_month': next_month_date, + 'previous_month': previous_month_date, + } + return calendar_month + + +def toDate(dateString): + return datetime.strptime(dateString, "%Y-%m-%d").date() + + if __name__ == '__main__': # Bind to PORT if defined, otherwise default to 5000. port = int(os.environ.get('PORT', 5000)) diff --git a/templates/partials/calendar.html b/templates/partials/calendar.html index 431d9c4..02a1cf5 100644 --- a/templates/partials/calendar.html +++ b/templates/partials/calendar.html @@ -1,10 +1,13 @@ -
+
- October - 2020 + {{ + calendar_month.month_year }}