Granular Gains: Implementing Per-Set Workout Logging in GymFlow
The Problem
Traditional workout logging often aggregates performance data per exercise, providing a summary but obscuring the nuanced details of individual sets. For users of the gymflow application, this meant they couldn't easily track subtle improvements or regressions in specific sets over time. Seeing how the first set's reps or weight compared to the last, or how performance varied across different sets within a single exercise, was a significant challenge. Our goal was to empower users with deeper insights into their training by enabling granular, per-set data capture.
The Approach
We undertook a phased approach to integrate per-set workout logging and detailed progress tracking into gymflow.
Phase 1: Evolving the Data Model with JSONB
The cornerstone of this feature was a flexible database schema capable of storing structured yet dynamic per-set data. We leveraged Supabase's PostgreSQL capabilities by introducing a sets_data column of type JSONB to our routine_exercises (or similar logging) table. This allowed us to store an array of objects, where each object represents a single set with properties like reps, weight, and potentially rpe (Rate of Perceived Exertion) or duration. This approach offers immense flexibility without requiring schema migrations for every minor change to set attributes.
ALTER TABLE routine_exercises
ADD COLUMN sets_data JSONB DEFAULT '[]'::jsonb;
-- Example of inserting data
UPDATE workout_logs
SET sets_data = '[{"set": 1, "reps": 10, "weight": 60.0}, {"set": 2, "reps": 8, "weight": 65.0}]'
WHERE workout_log_id = 123;
This schema update provided the foundation for capturing the detailed information needed for per-set analysis.
Phase 2: Building the Per-Set Editor UI
With the backend ready, the next step involved overhauling the user interface within Routines.tsx and Rutina.tsx to facilitate per-set data entry. We implemented a dynamic editor that allows users to toggle between exercises and see individual sets. For desktop users, this meant sub-rows expanding beneath each exercise, while mobile users benefited from collapsible sections. This design ensures an intuitive and efficient data entry experience.
// Simplified example of a React component for set input
function SetInput({ set, index, onUpdate }) {
return (
<div key={index} style={{ display: 'flex', gap: '8px', marginBottom: '4px' }}>
<span>Set {index + 1}:</span>
<input
type="number"
value={set.reps || ''}
onChange={(e) => onUpdate(index, { ...set, reps: parseInt(e.target.value) || 0 })}
placeholder="Reps"
style={{ width: '60px' }}
/>
<input
type="number"
value={set.weight || ''}
onChange={(e) => onUpdate(index, { ...set, weight: parseFloat(e.target.value) || 0 })}
placeholder="Weight"
style={{ width: '80px' }}
/>
</div>
);
}
// Usage in a parent component (e.g., Rutina.tsx)
// <SetInput set={currentSet} index={i} onUpdate={handleSetUpdate} />
This interactive UI ensures that users can accurately log the specifics of each set as they perform their workout.
Phase 3: Visualizing Daily Progress
Finally, to make this granular data actionable, we enhanced the Progreso.tsx component. A new "Por día" (By Day) tab was introduced, allowing users to compare their per-set performance for a given exercise across different workout days. This visualization capability helps users identify trends, track progress, and make informed adjustments to their training programs based on concrete, detailed data.
Key Insight
The ability to log and compare individual sets transforms how users perceive their progress. Instead of just seeing overall volume or a single best set, they can now pinpoint exactly where improvements are being made or where more focus is needed. This granular data tracking fosters a deeper understanding of performance, enabling more effective and personalized training decisions.
Generated with Gitvlg.com