diff --git a/app/routes/auth.py b/app/routes/auth.py index df5a482..10ea0be 100644 --- a/app/routes/auth.py +++ b/app/routes/auth.py @@ -35,5 +35,4 @@ def login(): def logout(): logout_user() # Logs out the current user flash('You have been logged out.', 'success') - return redirect(url_for('auth.login')) # Redirect to login page or home page - + return redirect(url_for('auth.login')) # Redirect to login page or home page \ No newline at end of file diff --git a/app/routes/main.py b/app/routes/main.py index b7fac83..976aea6 100644 --- a/app/routes/main.py +++ b/app/routes/main.py @@ -23,132 +23,6 @@ def health(): @main.route('/dashboard', methods=['GET', 'POST']) @login_required def dashboard(): - # Helper function to get first and last reading timestamps - def get_reading_date_range(user_id): - result = ( - db.session.query( - func.min(Reading.timestamp).label('first'), - func.max(Reading.timestamp).label('last') - ) - .filter(Reading.user_id == user_id) - .first() - ) - return result.first, result.last - - # Helper function to calculate weekly summary averages - def calculate_weekly_summary(readings): - one_week_ago = datetime.now() - timedelta(days=7) - weekly_readings = [r for r in readings if r.timestamp >= one_week_ago] - if weekly_readings: - systolic_avg = round(sum(r.systolic for r in weekly_readings) / len(weekly_readings), 1) - diastolic_avg = round(sum(r.diastolic for r in weekly_readings) / len(weekly_readings), 1) - heart_rate_avg = round(sum(r.heart_rate for r in weekly_readings) / len(weekly_readings), 1) - else: - systolic_avg = diastolic_avg = heart_rate_avg = 0 - return systolic_avg, diastolic_avg, heart_rate_avg - - # Helper function to calculate progress badges - def calculate_progress_badges(readings): - """Calculate badges based on user reading activity.""" - badges = [] - now = datetime.utcnow().date() - - # Prepare sorted readings by timestamp - sorted_readings = sorted(readings, key=lambda r: r.timestamp) - - # Incremental milestone badge - def highest_milestone(total_readings, milestones): - """Determine the highest milestone achieved.""" - for milestone in reversed(milestones): - if total_readings >= milestone: - return f"{milestone} Readings Logged" - return None - - highest_milestone_badge = highest_milestone(len(readings), [10, 50, 100, 500, 1000, 5000, 10000]) - if highest_milestone_badge: - badges.append(highest_milestone_badge) - - # Streaks and calendar month badges - if sorted_readings: - streak_count = 1 - daily_streak = True - monthly_tracker = defaultdict(int) - - # Start with the first reading - previous_date = sorted_readings[0].timestamp.date() - - for reading in sorted_readings[1:]: - current_date = reading.timestamp.date() - - # Check for consecutive daily streaks - if (current_date - previous_date).days == 1: - streak_count += 1 - elif (current_date - previous_date).days > 1: - daily_streak = False - - # Track monthly activity - monthly_tracker[current_date.strftime('%Y-%m')] += 1 - - previous_date = current_date - - # Add streak badges - if daily_streak and streak_count >= 1: - badges.append(f"Current Streak: {streak_count} Days") - if daily_streak and streak_count >= 7: - badges.append("Logged Every Day for a Week") - - if daily_streak and streak_count >= 30 and previous_date == now: - badges.append("Monthly Streak") - - # Add calendar month streak badges - for month, count in monthly_tracker.items(): - if count >= 30: - badges.append(f"Full Month of Logging: {month}") - - # Time-specific badges (morning/night logging) - def is_morning(reading_time): - return 5 <= reading_time.hour < 12 - - def is_night(reading_time): - return 18 <= reading_time.hour <= 23 - - if all(is_morning(r.timestamp) for r in sorted_readings[-7:]): - badges.append("Morning Riser: Logged Readings Every Morning for a Week") - - if all(is_night(r.timestamp) for r in sorted_readings[-7:]): - badges.append("Night Owl: Logged Readings Every Night for a Week") - - return badges - - def generate_monthly_calendar(readings, selected_date, local_timezone): - # Convert selected date to user's timezone and extract the start/end dates - today = datetime.now(local_timezone).date() - date = selected_date.astimezone(local_timezone).date() - 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) - - # Group readings by day - readings_by_day = {} - for reading in readings: - local_date = reading.timestamp.astimezone(local_timezone).date() - readings_by_day.setdefault(local_date, []).append(reading) - - # Build calendar days - calendar = [] - current_date = start_date - while current_date <= end_date: - calendar.append({ - 'day': current_date.day, - 'is_today': current_date == today, - 'is_in_current_month': current_date.month == date.month, - 'readings': readings_by_day.get(current_date, []), - }) - current_date += timedelta(days=1) - - return calendar - # Get the first and last reading timestamps first_reading_timestamp, last_reading_timestamp = get_reading_date_range(current_user.id) @@ -220,4 +94,130 @@ def dashboard(): month = month_view, date=date, timedelta=timedelta - ) \ No newline at end of file + ) + +# Helper function to get first and last reading timestamps +def get_reading_date_range(user_id): + result = ( + db.session.query( + func.min(Reading.timestamp).label('first'), + func.max(Reading.timestamp).label('last') + ) + .filter(Reading.user_id == user_id) + .first() + ) + return result.first, result.last + +# Helper function to calculate weekly summary averages +def calculate_weekly_summary(readings): + one_week_ago = datetime.now() - timedelta(days=7) + weekly_readings = [r for r in readings if r.timestamp >= one_week_ago] + if weekly_readings: + systolic_avg = round(sum(r.systolic for r in weekly_readings) / len(weekly_readings), 1) + diastolic_avg = round(sum(r.diastolic for r in weekly_readings) / len(weekly_readings), 1) + heart_rate_avg = round(sum(r.heart_rate for r in weekly_readings) / len(weekly_readings), 1) + else: + systolic_avg = diastolic_avg = heart_rate_avg = 0 + return systolic_avg, diastolic_avg, heart_rate_avg + +def generate_monthly_calendar(readings, selected_date, local_timezone): + # Convert selected date to user's timezone and extract the start/end dates + today = datetime.now(local_timezone).date() + date = selected_date.astimezone(local_timezone).date() + 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) + + # Group readings by day + readings_by_day = {} + for reading in readings: + local_date = reading.timestamp.astimezone(local_timezone).date() + readings_by_day.setdefault(local_date, []).append(reading) + + # Build calendar days + calendar = [] + current_date = start_date + while current_date <= end_date: + calendar.append({ + 'day': current_date.day, + 'is_today': current_date == today, + 'is_in_current_month': current_date.month == date.month, + 'readings': readings_by_day.get(current_date, []), + }) + current_date += timedelta(days=1) + + return calendar + + # Helper function to calculate progress badges +def calculate_progress_badges(readings): + """Calculate badges based on user reading activity.""" + badges = [] + now = datetime.utcnow().date() + + # Prepare sorted readings by timestamp + sorted_readings = sorted(readings, key=lambda r: r.timestamp) + + # Incremental milestone badge + def highest_milestone(total_readings, milestones): + """Determine the highest milestone achieved.""" + for milestone in reversed(milestones): + if total_readings >= milestone: + return f"{milestone} Readings Logged" + return None + + highest_milestone_badge = highest_milestone(len(readings), [10, 50, 100, 500, 1000, 5000, 10000]) + if highest_milestone_badge: + badges.append(highest_milestone_badge) + + # Streaks and calendar month badges + if sorted_readings: + streak_count = 1 + daily_streak = True + monthly_tracker = defaultdict(int) + + # Start with the first reading + previous_date = sorted_readings[0].timestamp.date() + + for reading in sorted_readings[1:]: + current_date = reading.timestamp.date() + + # Check for consecutive daily streaks + if (current_date - previous_date).days == 1: + streak_count += 1 + elif (current_date - previous_date).days > 1: + daily_streak = False + + # Track monthly activity + monthly_tracker[current_date.strftime('%Y-%m')] += 1 + + previous_date = current_date + + # Add streak badges + if daily_streak and streak_count >= 1: + badges.append(f"Current Streak: {streak_count} Days") + if daily_streak and streak_count >= 7: + badges.append("Logged Every Day for a Week") + + if daily_streak and streak_count >= 30 and previous_date == now: + badges.append("Monthly Streak") + + # Add calendar month streak badges + for month, count in monthly_tracker.items(): + if count >= 30: + badges.append(f"Full Month of Logging: {month}") + + # Time-specific badges (morning/night logging) + def is_morning(reading_time): + return 5 <= reading_time.hour < 12 + + def is_night(reading_time): + return 18 <= reading_time.hour <= 23 + + if all(is_morning(r.timestamp) for r in sorted_readings[-7:]): + badges.append("Morning Riser: Logged Readings Every Morning for a Week") + + if all(is_night(r.timestamp) for r in sorted_readings[-7:]): + badges.append("Night Owl: Logged Readings Every Night for a Week") + + return badges \ No newline at end of file diff --git a/app/routes/reading.py b/app/routes/reading.py index dc7faaa..0931f65 100644 --- a/app/routes/reading.py +++ b/app/routes/reading.py @@ -1,12 +1,10 @@ -from collections import defaultdict from flask import Blueprint, render_template, redirect, request, url_for, flash -import humanize from pytz import timezone, utc -from sqlalchemy import func from app.models import Reading, db -from app.forms import DeleteForm, ReadingForm +from app.forms import ReadingForm from flask_login import login_required, current_user -from datetime import date, datetime, timedelta +from datetime import datetime + reading = Blueprint('reading', __name__) @reading.route('/add', methods=['GET', 'POST'])