Clean up main route

This commit is contained in:
Peter Stockings
2024-12-29 23:21:16 +11:00
parent 6291c37820
commit ea0ad126ab

View File

@@ -12,9 +12,7 @@ main = Blueprint('main', __name__)
@main.route('/', methods=['GET']) @main.route('/', methods=['GET'])
def landing(): def landing():
if current_user.is_authenticated: return redirect(url_for('main.dashboard')) if current_user.is_authenticated else render_template('landing.html')
return redirect(url_for('main.dashboard'))
return render_template('landing.html')
@main.route('/health') @main.route('/health')
def health(): def health():
@@ -23,58 +21,31 @@ def health():
@main.route('/dashboard', methods=['GET', 'POST']) @main.route('/dashboard', methods=['GET', 'POST'])
@login_required @login_required
def dashboard(): def dashboard():
# Get the first and last reading timestamps """Render the dashboard with readings, stats, and calendar views."""
first_reading_timestamp, last_reading_timestamp = get_reading_date_range(current_user.id) user_tz = timezone(current_user.profile.timezone or 'UTC')
# Set default start and end dates # Get date range for readings
start_date = first_reading_timestamp.strftime('%Y-%m-%d') if first_reading_timestamp else None first_reading, last_reading = get_reading_date_range(current_user.id)
end_date = last_reading_timestamp.strftime('%Y-%m-%d') if last_reading_timestamp else None start_date = request.form.get('start_date') or (first_reading and first_reading.strftime('%Y-%m-%d'))
end_date = request.form.get('end_date') or (last_reading and last_reading.strftime('%Y-%m-%d'))
# Handle filtering for POST request # Fetch filtered readings
readings_query = Reading.query.filter_by(user_id=current_user.id) readings = fetch_readings(current_user.id, start_date, end_date)
if request.method == 'POST':
start_date = request.form.get('start_date') or start_date
end_date = request.form.get('end_date') or end_date
if start_date and end_date:
readings_query = readings_query.filter(
Reading.timestamp >= datetime.strptime(start_date, '%Y-%m-%d'),
Reading.timestamp <= datetime.strptime(end_date, '%Y-%m-%d')
)
# Fetch readings
readings = readings_query.order_by(Reading.timestamp.desc()).all()
# Fetch the user's timezone (default to 'UTC' if none is set)
user_timezone = current_user.profile.timezone if current_user.profile and current_user.profile.timezone else 'UTC'
local_tz = timezone(user_timezone)
# Add relative & local timestamps to readings
now = datetime.utcnow() now = datetime.utcnow()
for reading in readings:
reading.relative_timestamp = humanize.naturaltime(now - reading.timestamp)
reading.local_timestamp = utc.localize(reading.timestamp).astimezone(local_tz)
month_view = generate_monthly_calendar(readings, now, local_tz) # Annotate readings with relative and localized timestamps
annotate_readings(readings, now, user_tz)
# Calculate weekly summary and progress badges # Generate calendar view
month_view = generate_monthly_calendar(readings, datetime.now(user_tz), user_tz)
# Calculate stats and badges
systolic_avg, diastolic_avg, heart_rate_avg = calculate_weekly_summary(readings) systolic_avg, diastolic_avg, heart_rate_avg = calculate_weekly_summary(readings)
badges = calculate_progress_badges(readings) badges = calculate_progress_badges(readings)
# Prepare graph data # Prepare graph data
timestamps = [reading.timestamp.strftime('%b %d') for reading in readings] graph_data = prepare_graph_data(readings)
systolic = [reading.systolic for reading in readings]
diastolic = [reading.diastolic for reading in readings]
heart_rate = [reading.heart_rate for reading in readings]
# Group readings by date
readings_by_date = {}
for reading in readings:
date_key = reading.timestamp.date()
if date_key not in readings_by_date:
readings_by_date[date_key] = []
readings_by_date[date_key].append(reading)
# Render template
return render_template( return render_template(
'dashboard.html', 'dashboard.html',
readings=readings, readings=readings,
@@ -84,140 +55,139 @@ def dashboard():
diastolic_avg=diastolic_avg, diastolic_avg=diastolic_avg,
heart_rate_avg=heart_rate_avg, heart_rate_avg=heart_rate_avg,
delete_form=DeleteForm(), delete_form=DeleteForm(),
timestamps=timestamps,
systolic=systolic,
diastolic=diastolic,
heart_rate=heart_rate,
start_date=start_date, start_date=start_date,
end_date=end_date, end_date=end_date,
readings_by_date=readings_by_date, month=month_view,
month = month_view,
date=date, date=date,
timedelta=timedelta timedelta=timedelta,
**graph_data
) )
# Helper function to get first and last reading timestamps
def get_reading_date_range(user_id): def get_reading_date_range(user_id):
result = ( """Fetch the earliest and latest reading timestamps for a user."""
db.session.query( result = db.session.query(
func.min(Reading.timestamp).label('first'), func.min(Reading.timestamp).label('first'),
func.max(Reading.timestamp).label('last') func.max(Reading.timestamp).label('last')
) ).filter(Reading.user_id == user_id).first()
.filter(Reading.user_id == user_id)
.first()
)
return result.first, result.last return result.first, result.last
# Helper function to calculate weekly summary averages def fetch_readings(user_id, start_date, end_date):
"""Retrieve readings filtered by date range."""
query = Reading.query.filter_by(user_id=user_id)
if start_date and end_date:
query = query.filter(
Reading.timestamp >= datetime.strptime(start_date, '%Y-%m-%d'),
Reading.timestamp <= datetime.strptime(end_date, '%Y-%m-%d')
)
return query.order_by(Reading.timestamp.desc()).all()
def annotate_readings(readings, now, user_tz):
"""Add relative and localized timestamps to readings."""
for reading in readings:
reading.relative_timestamp = humanize.naturaltime(now - reading.timestamp)
reading.local_timestamp = utc.localize(reading.timestamp).astimezone(user_tz)
def calculate_weekly_summary(readings): def calculate_weekly_summary(readings):
one_week_ago = datetime.now() - timedelta(days=7) """Calculate averages for the past week."""
one_week_ago = datetime.utcnow() - timedelta(days=7)
weekly_readings = [r for r in readings if r.timestamp >= one_week_ago] weekly_readings = [r for r in readings if r.timestamp >= one_week_ago]
if weekly_readings: if weekly_readings:
systolic_avg = round(sum(r.systolic for r in weekly_readings) / len(weekly_readings), 1) return (
diastolic_avg = round(sum(r.diastolic for r in weekly_readings) / len(weekly_readings), 1) round(sum(r.systolic 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) round(sum(r.diastolic for r in weekly_readings) / len(weekly_readings), 1),
else: round(sum(r.heart_rate for r in weekly_readings) / len(weekly_readings), 1),
systolic_avg = diastolic_avg = heart_rate_avg = 0 )
return systolic_avg, diastolic_avg, heart_rate_avg return 0, 0, 0
def generate_monthly_calendar(readings, selected_date, local_timezone): def generate_monthly_calendar(readings, selected_date, local_tz):
# Convert selected date to user's timezone and extract the start/end dates """Generate a monthly calendar view."""
today = datetime.now(local_timezone).date() today = datetime.now(local_tz).date()
date = selected_date.astimezone(local_timezone).date() first_day = selected_date.replace(day=1)
first_day_of_month = date.replace(day=1) start_date = first_day - timedelta(days=(first_day.weekday() + 1) % 7)
days_to_subtract = (first_day_of_month.weekday() + 1) % 7 end_date = start_date + timedelta(days=41)
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 = defaultdict(list)
readings_by_day = {}
for reading in readings: for reading in readings:
local_date = reading.timestamp.astimezone(local_timezone).date() local_date = reading.timestamp.astimezone(local_tz).date()
readings_by_day.setdefault(local_date, []).append(reading) readings_by_day[local_date].append(reading)
# Build calendar days return [
calendar = [] {
current_date = start_date
while current_date <= end_date:
calendar.append({
'day': current_date.day, 'day': current_date.day,
'is_today': current_date == today, 'is_today': current_date == today,
'is_in_current_month': current_date.month == date.month, 'is_in_current_month': current_date.month == selected_date.month,
'readings': readings_by_day.get(current_date, []), 'readings': readings_by_day.get(current_date, []),
}) }
current_date += timedelta(days=1) for current_date in (start_date + timedelta(days=i) for i in range((end_date - start_date).days + 1))
]
return calendar def prepare_graph_data(readings):
"""Prepare data for graph rendering."""
return {
'timestamps': [r.timestamp.strftime('%b %d') for r in readings],
'systolic': [r.systolic for r in readings],
'diastolic': [r.diastolic for r in readings],
'heart_rate': [r.heart_rate for r in readings],
}
# Helper function to calculate progress badges
def calculate_progress_badges(readings): def calculate_progress_badges(readings):
"""Calculate badges based on user reading activity.""" """Generate badges based on user activity and milestones."""
badges = []
now = datetime.utcnow().date() now = datetime.utcnow().date()
streak_count, badges = 1, []
# Prepare sorted readings by timestamp if not readings:
sorted_readings = sorted(readings, key=lambda r: r.timestamp) return badges
# Incremental milestone badge sorted_readings = sorted(readings, key=lambda r: r.timestamp.date())
def highest_milestone(total_readings, milestones): streak_count = 1
"""Determine the highest milestone achieved.""" daily_streak = True
for milestone in reversed(milestones): monthly_tracker = defaultdict(int)
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]) # Start with the first reading
if highest_milestone_badge: previous_date = sorted_readings[0].timestamp.date()
badges.append(highest_milestone_badge)
# Streaks and calendar month badges for reading in sorted_readings[1:]:
if sorted_readings: current_date = reading.timestamp.date()
streak_count = 1
daily_streak = True
monthly_tracker = defaultdict(int)
# Start with the first reading # Check for consecutive daily streaks
previous_date = sorted_readings[0].timestamp.date() if (current_date - previous_date).days == 1:
streak_count += 1
elif (current_date - previous_date).days > 1:
daily_streak = False
for reading in sorted_readings[1:]: # Track monthly activity
current_date = reading.timestamp.date() monthly_tracker[current_date.strftime('%Y-%m')] += 1
# Check for consecutive daily streaks previous_date = current_date
if (current_date - previous_date).days == 1:
streak_count += 1
elif (current_date - previous_date).days > 1:
daily_streak = False
# Track monthly activity # Add streak badges
monthly_tracker[current_date.strftime('%Y-%m')] += 1 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")
previous_date = current_date if daily_streak and streak_count >= 30 and previous_date == now:
badges.append("Monthly Streak")
# Add streak badges # Add calendar month streak badges
if daily_streak and streak_count >= 1: for month, count in monthly_tracker.items():
badges.append(f"Current Streak: {streak_count} Days") if count >= 30:
if daily_streak and streak_count >= 7: badges.append(f"Full Month of Logging: {month}")
badges.append("Logged Every Day for a Week")
if daily_streak and streak_count >= 30 and previous_date == now: if streak_count >= 7:
badges.append("Monthly Streak") badges.append("Logged Every Day for a Week")
if streak_count >= 30 and previous_date == now:
badges.append("Monthly Streak")
# Add calendar month streak badges if all(5 <= r.timestamp.hour < 12 for r in sorted_readings[-7:]):
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") badges.append("Morning Riser: Logged Readings Every Morning for a Week")
if all(is_night(r.timestamp) for r in sorted_readings[-7:]): if all(18 <= r.timestamp.hour <= 23 for r in sorted_readings[-7:]):
badges.append("Night Owl: Logged Readings Every Night for a Week") badges.append("Night Owl: Logged Readings Every Night for a Week")
milestones = [10, 50, 100, 500, 1000, 5000, 10000]
highest_milestone = max((m for m in milestones if len(readings) >= m), default=None)
if highest_milestone:
badges.append(f"{highest_milestone} Readings Logged")
return badges return badges