Batch 1: dashboard, maps, segments rewrite, health, sync UX
Fixes:
- Dashboard: featured most-recent activity card with map + stats
- Maps default to Street; preferCanvas + larger tile buffer for smoother pan/zoom
- Running cadence as colour-banded dots + 165 spm guide line
- Routes: inline row expansion, rename (PATCH /routes/{id}), podium + deltas, tiled map
- Records: remove reversed pace Y-axis
- Profile: remove resting HR; add goal weight
- Health: snapshot weight carry-forward; VO2 trend axis 30-70;
weight goal line + kg/st-lb toggle + axis max; sleep 8h/avg lines
- Garmin sync progress moved to global store with persistent floating bar
Features:
- Speed-coloured activity route (default) with Speed/Solid toggle
- GPS-geometry segments: draw on map, match across all activities,
1st/2nd/3rd leaderboard + podium badges (replaces old distance segments)
- Lap bests: best time per lap across a route + delta column
- Body Battery: highlight activity time windows
Schema: users.goal_weight_kg ALTER; new segments/segment_efforts tables.
Removes RouteSegment, the Segments page, and segment-bests endpoints.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@ class ProfileUpdate(BaseModel):
|
||||
birth_year: Optional[int] = None
|
||||
height_cm: Optional[float] = None
|
||||
biological_sex: Optional[str] = None
|
||||
goal_weight_kg: Optional[float] = None
|
||||
|
||||
|
||||
class ProfileOut(BaseModel):
|
||||
@@ -31,6 +32,7 @@ class ProfileOut(BaseModel):
|
||||
birth_year: Optional[int]
|
||||
height_cm: Optional[float]
|
||||
biological_sex: Optional[str]
|
||||
goal_weight_kg: Optional[float]
|
||||
estimated_max_hr: Optional[int]
|
||||
is_admin: bool
|
||||
|
||||
@@ -78,6 +80,10 @@ async def update_profile(
|
||||
if body.biological_sex not in ('male', 'female', ''):
|
||||
raise HTTPException(400, "biological_sex must be 'male' or 'female'")
|
||||
current_user.biological_sex = body.biological_sex or None
|
||||
if body.goal_weight_kg is not None:
|
||||
if body.goal_weight_kg and not (20 <= body.goal_weight_kg <= 500):
|
||||
raise HTTPException(400, "Goal weight must be 20–500 kg")
|
||||
current_user.goal_weight_kg = body.goal_weight_kg or None
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(current_user)
|
||||
|
||||
Reference in New Issue
Block a user