Repository navigation
feat(workout): set UX overhaul -- checkbox confirm, swipe delete, gym picker fix, rest minimize - #109
Merged
Merged
Conversation
Add a "Done with this exercise" affordance so athletes can skip remaining sets on a strength block and advance focus to the next exercise. Also dim the trailing auto-populated set row so its unconfirmed state is visually unambiguous. - active-workout-store: add skippedActivityIds (Set<string>) + skipActivity action; resets automatically on finish/discard via initialState spread - exercise-block: add onSkipExercise prop + DONE button below set list; add isPending to SetRowData; pass isPending to SetRow for pending rows - set-row: add isPending prop -- opacity-40 on row + placeholder in STATUS column instead of confirm button - log.$workoutId: pull skippedActivityIds from store; activeFocusId memo treats skipped activities as done; skip guard on render; wire onSkipExercise with confirmedSets.length > 0 guard; mark trailing row isPending: true
Removes the hard-focus filter that prevented non-active exercises from rendering. All exercises now display with their set rows and controls. "Add set" is accessible on every exercise block to support ad-hoc pre-population. "Done/Skip" remains active-only as a progression signal. Closes B007
- SetRow gains left-swipe gesture to reveal a DEL button (64 px threshold); snaps open when threshold is reached, snaps closed on partial swipe or tap - Adds deleteSet and removeActivity actions to active-workout-store - Removes set-level notes (notes / noteTags) from the LoggedSet domain type, both adapters (Supabase + Tauri), and the store's setSetNote action - Drops loggedSetId prop and NoteAffordance from SetRow; removes set-note display from WorkoutDetailExercises and ManualWorkoutForm - Adds Supabase + SQLite migrations to DROP notes / note_tags from logged_sets
…backlog - Adds Coding Guidelines section to CLAUDE.md (5 rules: think, read, simplify, surgical changes, goal-driven execution) - /commit command gains Step 4: QuickPlan archive prompt after each commit - /quick command Step 5: enforce archive move instead of suggesting it - Backlog: adds B007 (multi-exercise display), B008 (gym selector persistence), and "frequently used exercises" idea
Replace the confirm checkmark + done badge/icon trio with a unified checkbox metaphor. Empty checkbox (ember) to confirm; filled checkbox to unconfirm. Variance coloring is preserved via the filled checkbox: green for met, amber for under, neutral for no prescription. Unconfirming a set now marks it completed=false (updateLoggedSet) rather than deleting it, so actual weight and reps are preserved in the row for re-editing.
- Require reps on all confirms (weight optional): change confirm button disabled condition from weight||reps to reps-only gate - Fix reps=0 coercing to null: parse reps with >= 0 (not > 0) and use non-null check instead of falsy check, preventing a logged_sets_completed_check constraint violation for failed sets - Suppress spurious pending row on unconfirm: guard pending row insertion with hasUncompletedSets so un-confirming a set doesn't produce a duplicate editable row alongside the existing one
Replaced the `firstWorkoutCompleted`-gated branching logic in all three workout-start handlers with a single `readLastGymChoice() ?? openGymPicker()` expression. The onboarding flag was the wrong gate -- it caused the picker to appear on every start until the first workout was fully completed, regardless of whether a gym had already been saved to localStorage. Fixes B008. Removes unused `useOnboardingStore` subscription from library.tsx.
Adds a minimize affordance to the full-page rest view. Tapping the chevron collapses the rest timer to a compact sticky strip (RestTimerBanner) at the bottom of the screen, exposing the exercise log so athletes can review sets or add notes while the countdown runs in the background. - RestPanel: optional `onMinimize` prop renders a ChevronDown button top-right - RestView: threads `onMinimize` through to RestPanel - RestTimerBanner: new component -- ember progress bar + REST label + countdown + Expand + Skip buttons, sticky bottom z-40 - log.$workoutId.tsx: `restMinimized` state; minimized path renders banner alongside the exercise log; minimize state resets when rest timer ends
- Update .claude/commands/* to latest skill wrappers; add spec-init command - Mark B008 resolved in Bugs.md - Archive completed QuickPlans: undo-set-done-status, b008-gym-picker-every-start
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
P18-001/002: add coordinated deleteSet and removeActivity bridge
functions in use-active-workout.ts that await DB deletion before
updating the Zustand store; wire onDeleteSet and onRemoveExercise
through them in log.$workoutId.tsx so swipe-delete and exercise
removal are now persisted
P18-003: add [workout-logs] prefixed onError handlers to
useDeleteLoggedSet, useDeleteLoggedActivity, and
useDeleteLoggedActivityGroup in use-workout-logs.ts
P18-004: update set-row.test.tsx confirmed-state assertion from
getByText('DONE') to getByLabelText('Undo set 1') to match the
checkbox icon button introduced in this PR
P18-005: remove duplicate console.error calls from unconfirmSet
catch in use-active-workout.ts and handleUnconfirmSet catch in
log.$workoutId.tsx -- mutation hook onError is the single log owner
P18-006: handleFinish and handleConfirmSet guard clauses now log
[workout-page] prefix and call setPageError instead of silently
returning
P18-007: add setIsSwiping(false) alongside setSwipeX(0) in DEL
button onClick in set-row.tsx
P18-008: move setStartingTemplateId inside try/finally in
library.tsx so the spinner always clears even if openGymPicker throws
P18-009: call storeClearUndo() in undoSet catch block so the expiry
timer does not silently clear an already-failed undo
P18-013/014: add inline comments to active-workout-store.ts
explaining the private-mode no-op and ephemeral field reset
Review: Context/Reviews/0018-pr109-workout-set-ux-2026-04-13.md
Add Wave 7 to Feature 018 Steps.md with S051-S054 capturing the four [TASK] findings from the PR #109 review: - S051: tests for new store actions (deleteSet, unconfirmSet, etc.) - S052: component test for swipe-to-delete DEL button - S053: regression test for B008 gym picker fix - S054: tests for RestTimerBanner component Mark review 0018-pr109-workout-set-ux-2026-04-13.md as partially resolved with resolution summary. Review: Context/Reviews/0018-pr109-workout-set-ux-2026-04-13.md
S051 -- active-workout-store: 14 new cases covering deleteSet, unconfirmSet, removeActivity (undo-clearing side effect), and skipActivity (Set reference isolation after finishWorkout reset) S052 -- set-row: 3 new cases for swipe-to-delete DEL button (renders with onDelete, absent without, click fires callback) S053 -- start-workout-flow: 2 B008 regression cases (saved gym skips picker, no saved gym opens picker); also fixes the 4 pre-existing tests which were broken by the B008 change (readLastGymChoice was not mocked, causing failures at the new call site) S054 -- rest-timer-banner: new test file, 11 cases covering progress bar clamping, total=0 guard, Expand/Skip callbacks, and countdown text rendering 127 test files, 2307 tests passing Review: Context/Reviews/0018-pr109-workout-set-ux-2026-04-13.md
Remove three try/catch wrappers in use-active-workout.ts whose catch
blocks only re-threw -- errors now propagate naturally to callers.
Replace useEffect(() => { if (!restTimer) setRestMinimized(false) }) with
a direct setRestMinimized(false) call inside handleConfirmSet, ensuring
each new rest timer starts expanded without triggering the
setState-in-effect lint rule.
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
firstWorkoutCompletedgate withreadLastGymChoice() ?? openGymPicker()Test plan