Enhance workout recovery and auto-save logic to prevent saving comple…#76
Conversation
There was a problem hiding this comment.
Pull request overview
This PR tightens workout session recovery and auto-save behavior to avoid persisting/recovering completed workouts, aiming to prevent “resuming” a finished session.
Changes:
- Prevent auto-save from running when a workout is marked
completed. - Clear
activeWorkoutin localStorage earlier during workout completion flow. - Update
recoverActiveWorkout()to ignore (and delete) completed workouts found in localStorage.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/hooks/useWorkoutSession.ts | Adds guards around auto-save for completed workouts and changes when auto-saved state is cleared during endWorkout. |
| src/db/service.ts | Ensures recovery ignores completed workouts and clears localStorage when they are encountered. |
| // Clear auto-saved data FIRST to prevent any race conditions | ||
| clearAutoSavedWorkout(); | ||
|
|
||
| const duration = Math.round( |
There was a problem hiding this comment.
In endWorkout, clearAutoSavedWorkout() is called before the DB write. If createWorkout/updateWorkout throws, the user loses the only recovery copy in localStorage (data loss). Also, clearing localStorage here doesn’t stop the existing auto-save interval, which can immediately re-write activeWorkout while the async DB write is in progress. Consider stopping the interval first (clear autoSaveTimerRef), performing the DB save in a try/catch, and only clearing activeWorkout after a successful save (or leaving it intact on failure).
| const save = () => { | ||
| autoSaveWorkout(workout); | ||
| // Double-check before saving | ||
| if (workout && isActive && !workout.completed) { | ||
| autoSaveWorkout(workout); | ||
| } |
There was a problem hiding this comment.
The “double-check” inside save() doesn’t actually validate current state because workout/isActive are captured by the effect closure; if isActive is set to false, there’s a window before the effect cleanup runs where the interval can still fire and this check will still see the old isActive === true. If the goal is to prevent saves after ending/canceling, clear the interval synchronously in endWorkout/cancelWorkout and/or read workout/isActive from refs updated on render.
| // Don't recover completed workouts - they should be cleared | ||
| if (workout.completed) { | ||
| localStorage.removeItem('activeWorkout'); | ||
| return null; | ||
| } | ||
|
|
||
| return workout; |
There was a problem hiding this comment.
recoverActiveWorkout() assumes the parsed JSON is a non-null object. If localStorage contains 'null' (or another non-object JSON value), workout.completed will throw. Add a guard after JSON.parse to validate the shape (e.g., if (!workout || typeof workout !== 'object') { ... }) before reading properties, and consider clearing the bad activeWorkout entry.
| // Don't recover completed workouts - they should be cleared | |
| if (workout.completed) { | |
| localStorage.removeItem('activeWorkout'); | |
| return null; | |
| } | |
| return workout; | |
| // If the parsed value is not a non-null object, treat as corrupted data | |
| if (!workout || typeof workout !== 'object') { | |
| localStorage.removeItem('activeWorkout'); | |
| return null; | |
| } | |
| // Don't recover completed workouts - they should be cleared | |
| if ((workout as import('../types/models').Workout).completed) { | |
| localStorage.removeItem('activeWorkout'); | |
| return null; | |
| } | |
| return workout as import('../types/models').Workout; |
| @@ -626,6 +627,12 @@ export function recoverActiveWorkout(): | |||
| return value; | |||
| }); | |||
|
|
|||
| // Don't recover completed workouts - they should be cleared | |||
| if (workout.completed) { | |||
| localStorage.removeItem('activeWorkout'); | |||
| return null; | |||
| } | |||
There was a problem hiding this comment.
This new recovery behavior (auto-clearing activeWorkout when completed is true) isn’t covered by tests. Since src/db/service.test.ts exists, add unit tests for recoverActiveWorkout() covering: missing key, malformed JSON/non-object JSON, completed workout (clears + returns null), and incomplete workout (returns revived Dates).
|
@copilot open a new pull request to apply changes based on the comments in this thread |
Co-authored-by: wulfland <5276337+wulfland@users.noreply.github.com>
Co-authored-by: wulfland <5276337+wulfland@users.noreply.github.com>
Fix workout recovery race conditions and add validation for corrupted state
…ted workouts