diff --git a/app/routes/logging.py b/app/routes/logging.py index 146f562..c80327c 100644 --- a/app/routes/logging.py +++ b/app/routes/logging.py @@ -23,6 +23,30 @@ logger = structlog.get_logger(__name__) router = APIRouter(prefix="/log", tags=["logging"]) +def _get_prefill_values( + logs: list, + session: Session, + profile_id: int, + exercise_id: int, +) -> tuple: + """Get pre-fill values for the next set form. + + If sets have already been logged this session, use the last logged + set's values (users typically repeat the same reps/weight across sets). + Otherwise, use the progression engine's suggestion. + + Returns: + (suggested_reps, suggested_weight) tuple. + """ + if logs: + last = logs[-1] + return last.reps_completed, last.weight_used + + progression = ProgressionService(session) + suggestion = progression.get_suggestion(profile_id, exercise_id) + return suggestion.get("suggested_reps"), suggestion.get("suggested_weight") + + @router.post("", response_class=HTMLResponse) async def log_set( request: Request, @@ -80,10 +104,9 @@ async def log_set( # Return updated logs for this exercise logs = log_service.list_logs_for_exercise(ws.id, exercise_id) next_set = len(logs) + 1 - - # Fetch suggestion for pre-filling the next set form - progression = ProgressionService(session) - suggestion = progression.get_suggestion(active_profile_id, exercise_id) + suggested_reps, suggested_weight = _get_prefill_values( + logs, session, active_profile_id, exercise_id, + ) templates = request.app.state.templates return templates.TemplateResponse("partials/log_entry.html", { @@ -93,8 +116,8 @@ async def log_set( "workout_day_id": workout_day_id, "next_set": next_set, "session_id": ws.id, - "suggested_reps": suggestion.get("suggested_reps"), - "suggested_weight": suggestion.get("suggested_weight"), + "suggested_reps": suggested_reps, + "suggested_weight": suggested_weight, }) @@ -131,12 +154,12 @@ async def edit_log( logs = log_service.list_logs_for_exercise(log.session_id, log.exercise_id) next_set = len(logs) + 1 - # Fetch suggestion for pre-filling the next set form active_profile_id = get_active_profile_id(request) - suggestion = {} + suggested_reps, suggested_weight = None, None if active_profile_id: - progression = ProgressionService(session) - suggestion = progression.get_suggestion(active_profile_id, log.exercise_id) + suggested_reps, suggested_weight = _get_prefill_values( + logs, session, active_profile_id, log.exercise_id, + ) templates = request.app.state.templates return templates.TemplateResponse("partials/log_entry.html", { @@ -146,8 +169,8 @@ async def edit_log( "workout_day_id": 0, "next_set": next_set, "session_id": log.session_id, - "suggested_reps": suggestion.get("suggested_reps"), - "suggested_weight": suggestion.get("suggested_weight"), + "suggested_reps": suggested_reps, + "suggested_weight": suggested_weight, }) @@ -180,12 +203,12 @@ async def delete_log( logs = log_service.list_logs_for_exercise(session_id, exercise_id) next_set = len(logs) + 1 - # Fetch suggestion for pre-filling the next set form active_profile_id = get_active_profile_id(request) - suggestion = {} + suggested_reps, suggested_weight = None, None if active_profile_id: - progression = ProgressionService(session) - suggestion = progression.get_suggestion(active_profile_id, exercise_id) + suggested_reps, suggested_weight = _get_prefill_values( + logs, session, active_profile_id, exercise_id, + ) templates = request.app.state.templates return templates.TemplateResponse("partials/log_entry.html", { @@ -195,8 +218,8 @@ async def delete_log( "workout_day_id": 0, "next_set": next_set, "session_id": session_id, - "suggested_reps": suggestion.get("suggested_reps"), - "suggested_weight": suggestion.get("suggested_weight"), + "suggested_reps": suggested_reps, + "suggested_weight": suggested_weight, }) return HTMLResponse("") diff --git a/app/services/log_service.py b/app/services/log_service.py index b8a753b..6ff0b83 100644 --- a/app/services/log_service.py +++ b/app/services/log_service.py @@ -149,7 +149,8 @@ class LogService: def delete_log(self, log_id: int) -> None: """Delete a log entry. - Removes the log and cleans up the parent session if no logs remain. + Removes the log, renumbers remaining sets, and cleans up the + parent session if no logs remain. Args: log_id: The log entry ID. @@ -162,15 +163,32 @@ class LogService: raise ValueError(f"WorkoutLog with id {log_id} not found") session_id = log.session_id + exercise_id = log.exercise_id self._session.delete(log) self._session.commit() logger.info("log_deleted", log_id=log_id) - # Clean up orphaned session if no logs remain + # Renumber remaining sets so they stay sequential (1, 2, 3...) remaining = self._session.exec( + select(WorkoutLog) + .where( + WorkoutLog.session_id == session_id, + WorkoutLog.exercise_id == exercise_id, + ) + .order_by(WorkoutLog.set_number) + ).all() + for i, remaining_log in enumerate(remaining, start=1): + if remaining_log.set_number != i: + remaining_log.set_number = i + self._session.add(remaining_log) + if remaining: + self._session.commit() + + # Clean up orphaned session if no logs remain for ANY exercise + any_remaining = self._session.exec( select(WorkoutLog).where(WorkoutLog.session_id == session_id) ).first() - if remaining is None: + if any_remaining is None: ws = self._session.get(WorkoutSession, session_id) if ws: self._session.delete(ws)