119 lines
3.4 KiB
Python
119 lines
3.4 KiB
Python
from flask import Blueprint, render_template
|
|
from app.auth import login_required, get_current_user
|
|
from app.db import query, query_one
|
|
from app import SYDNEY_TZ
|
|
from datetime import datetime, timezone, timedelta
|
|
|
|
bp = Blueprint("dashboard", __name__)
|
|
|
|
|
|
def calculate_streak(user_id):
|
|
"""Calculate current and best consecutive-day check-in streaks."""
|
|
rows = query(
|
|
"""SELECT DISTINCT (checked_in_at AT TIME ZONE 'UTC' AT TIME ZONE 'Australia/Sydney')::date AS d
|
|
FROM checkins WHERE user_id = %s ORDER BY d DESC""",
|
|
(user_id,),
|
|
)
|
|
if not rows:
|
|
return {"current": 0, "best": 0}
|
|
|
|
days = [r["d"] for r in rows]
|
|
today = datetime.now(SYDNEY_TZ).date()
|
|
|
|
# Current streak: must include today or yesterday to count
|
|
current = 0
|
|
expected = today
|
|
if days[0] == today or days[0] == today - timedelta(days=1):
|
|
expected = days[0]
|
|
for d in days:
|
|
if d == expected:
|
|
current += 1
|
|
expected -= timedelta(days=1)
|
|
else:
|
|
break
|
|
|
|
# Best streak
|
|
best = 1
|
|
run = 1
|
|
for i in range(1, len(days)):
|
|
if days[i] == days[i - 1] - timedelta(days=1):
|
|
run += 1
|
|
best = max(best, run)
|
|
else:
|
|
run = 1
|
|
|
|
best = max(best, current)
|
|
return {"current": current, "best": best}
|
|
|
|
|
|
@bp.route("/")
|
|
@login_required
|
|
def index():
|
|
user = get_current_user()
|
|
|
|
# Get latest check-in
|
|
latest = query_one(
|
|
"SELECT * FROM checkins WHERE user_id = %s ORDER BY checked_in_at DESC LIMIT 1",
|
|
(user["id"],),
|
|
)
|
|
|
|
# Get check-in count
|
|
stats = query_one(
|
|
"SELECT COUNT(*) as total_checkins FROM checkins WHERE user_id = %s",
|
|
(user["id"],),
|
|
)
|
|
|
|
# Calculate weight change
|
|
first_checkin = query_one(
|
|
"SELECT weight_kg FROM checkins WHERE user_id = %s ORDER BY checked_in_at ASC LIMIT 1",
|
|
(user["id"],),
|
|
)
|
|
|
|
weight_change = None
|
|
weight_change_pct = None
|
|
if latest and first_checkin:
|
|
start_w = float(first_checkin["weight_kg"])
|
|
current_w = float(latest["weight_kg"])
|
|
weight_change = round(current_w - start_w, 1)
|
|
if start_w > 0:
|
|
weight_change_pct = round((weight_change / start_w) * 100, 1)
|
|
|
|
# Recent check-ins (last 5)
|
|
recent_checkins = query(
|
|
"SELECT * FROM checkins WHERE user_id = %s ORDER BY checked_in_at DESC LIMIT 5",
|
|
(user["id"],),
|
|
)
|
|
|
|
# Activity feed (recent check-ins from all users)
|
|
activity = query("""
|
|
SELECT c.*, u.display_name, u.username
|
|
FROM checkins c
|
|
JOIN users u ON c.user_id = u.id
|
|
WHERE u.is_private = FALSE OR u.id = %s
|
|
ORDER BY c.checked_in_at DESC
|
|
LIMIT 10
|
|
""", (user["id"],))
|
|
|
|
# Milestones
|
|
milestones = query(
|
|
"SELECT * FROM milestones WHERE user_id = %s ORDER BY achieved_at DESC",
|
|
(user["id"],),
|
|
)
|
|
|
|
# Streak
|
|
streak = calculate_streak(user["id"])
|
|
|
|
return render_template(
|
|
"dashboard.html",
|
|
user=user,
|
|
latest=latest,
|
|
stats=stats,
|
|
weight_change=weight_change,
|
|
weight_change_pct=weight_change_pct,
|
|
recent_checkins=recent_checkins,
|
|
activity=activity,
|
|
milestones=milestones,
|
|
streak=streak,
|
|
)
|
|
|