fix(templates): preserve exercise IDs during template creation

- Modified NewTemplateSheet to store full exercise objects
- Updated handleAddTemplate to use original exercise IDs
- Fixed type definitions to support enhanced template exercises
This commit is contained in:
DocNR 2025-03-22 20:14:19 -04:00
parent 6a8589662d
commit 329154fc3d
3 changed files with 56 additions and 9 deletions

View File

@ -24,6 +24,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Optimized rendering for long lists with virtualized FlatList - Optimized rendering for long lists with virtualized FlatList
- Added scrollToTop functionality for new content - Added scrollToTop functionality for new content
## Fixed
- Template creation issue: preserved original exercise IDs when creating templates to ensure proper exercise references
- Modified NewTemplateSheet to store full exercise objects
- Updated handleAddTemplate to use original exercise IDs
- Fixed type definitions to support enhanced template exercises
# Changelog - March 19, 2025 # Changelog - March 19, 2025
## Added ## Added
@ -456,4 +462,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Initial repository setup - Initial repository setup
- Basic project structure - Basic project structure
- Development environment configuration - Development environment configuration
- Documentation templates - Documentation templates

View File

@ -15,8 +15,22 @@ import { Button } from '@/components/ui/button';
import { import {
Template, Template,
TemplateCategory, TemplateCategory,
TemplateExerciseConfig,
TemplateExerciseDisplay,
toWorkoutTemplate toWorkoutTemplate
} from '@/types/templates'; } from '@/types/templates';
import { generateId } from '@/utils/ids';
import { ExerciseDisplay } from '@/types/exercise';
// Enhanced template exercise display that includes the original exercise object
interface EnhancedTemplateExerciseDisplay {
title: string;
targetSets: number;
targetReps: number;
equipment?: string;
notes?: string;
exercise: ExerciseDisplay;
}
import { useWorkoutStore } from '@/stores/workoutStore'; import { useWorkoutStore } from '@/stores/workoutStore';
import { useTemplates } from '@/lib/hooks/useTemplates'; import { useTemplates } from '@/lib/hooks/useTemplates';
import { useIconColor } from '@/lib/theme/iconUtils'; import { useIconColor } from '@/lib/theme/iconUtils';
@ -165,8 +179,28 @@ export default function TemplatesScreen() {
}; };
const handleAddTemplate = (template: Template) => { const handleAddTemplate = (template: Template) => {
// Convert UI Template to WorkoutTemplate // The template exercises should already have the exercise property from NewTemplateSheet
const workoutTemplate = toWorkoutTemplate(template); // We know the exercises have the exercise property because we modified NewTemplateSheet
const enhancedExercises = template.exercises as unknown as EnhancedTemplateExerciseDisplay[];
// Convert UI Template to WorkoutTemplate, but preserve exercise IDs
const baseWorkoutTemplate = toWorkoutTemplate(template);
// Modify the exercises to use the original exercise objects with their IDs
const workoutTemplate = {
...baseWorkoutTemplate,
exercises: enhancedExercises.map(ex => {
// Create a proper TemplateExerciseConfig object
const config: TemplateExerciseConfig = {
id: generateId(), // ID for the template_exercise relationship
exercise: ex.exercise, // Use the original exercise object with its ID
targetSets: ex.targetSets,
targetReps: ex.targetReps,
notes: ex.notes
};
return config;
})
};
// Create the template // Create the template
createTemplate(workoutTemplate); createTemplate(workoutTemplate);
@ -332,4 +366,4 @@ export default function TemplatesScreen() {
/> />
</View> </View>
); );
} }

View File

@ -31,6 +31,11 @@ type CreationStep = 'type' | 'info' | 'exercises' | 'config' | 'review';
// Purple color used throughout the app // Purple color used throughout the app
const purpleColor = 'hsl(261, 90%, 66%)'; const purpleColor = 'hsl(261, 90%, 66%)';
// Enhanced template exercise display that includes the original exercise object
interface EnhancedTemplateExerciseDisplay extends TemplateExerciseDisplay {
exercise: ExerciseDisplay;
}
// Step 0: Workout Type Selection // Step 0: Workout Type Selection
interface WorkoutTypeStepProps { interface WorkoutTypeStepProps {
onSelectType: (type: TemplateType) => void; onSelectType: (type: TemplateType) => void;
@ -234,6 +239,7 @@ function ExerciseSelectionStep({
}; };
const handleContinue = () => { const handleContinue = () => {
// Get the full exercise objects with their original IDs
const selected = exercises.filter(e => selectedIds.includes(e.id)); const selected = exercises.filter(e => selectedIds.includes(e.id));
onExercisesSelected(selected); onExercisesSelected(selected);
}; };
@ -322,7 +328,7 @@ function ExerciseSelectionStep({
// Step 3: Exercise Configuration // Step 3: Exercise Configuration
interface ExerciseConfigStepProps { interface ExerciseConfigStepProps {
exercises: ExerciseDisplay[]; exercises: ExerciseDisplay[];
config: TemplateExerciseDisplay[]; config: EnhancedTemplateExerciseDisplay[];
onUpdateConfig: (index: number, sets: number, reps: number) => void; onUpdateConfig: (index: number, sets: number, reps: number) => void;
onNext: () => void; onNext: () => void;
onBack: () => void; onBack: () => void;
@ -397,7 +403,7 @@ interface ReviewStepProps {
description: string; description: string;
category: TemplateCategory; category: TemplateCategory;
type: TemplateType; type: TemplateType;
exercises: Template['exercises']; exercises: EnhancedTemplateExerciseDisplay[];
onSubmit: () => void; onSubmit: () => void;
onBack: () => void; onBack: () => void;
} }
@ -469,7 +475,7 @@ export function NewTemplateSheet({ isOpen, onClose, onSubmit }: NewTemplateSheet
const [workoutType, setWorkoutType] = useState<TemplateType>('strength'); const [workoutType, setWorkoutType] = useState<TemplateType>('strength');
const [exercises, setExercises] = useState<ExerciseDisplay[]>([]); const [exercises, setExercises] = useState<ExerciseDisplay[]>([]);
const [selectedExercises, setSelectedExercises] = useState<ExerciseDisplay[]>([]); const [selectedExercises, setSelectedExercises] = useState<ExerciseDisplay[]>([]);
const [configuredExercises, setConfiguredExercises] = useState<Template['exercises']>([]); const [configuredExercises, setConfiguredExercises] = useState<EnhancedTemplateExerciseDisplay[]>([]);
const { isDarkColorScheme } = useColorScheme(); const { isDarkColorScheme } = useColorScheme();
// Template info // Template info
@ -544,9 +550,10 @@ export function NewTemplateSheet({ isOpen, onClose, onSubmit }: NewTemplateSheet
const handleSelectExercises = (selected: ExerciseDisplay[]) => { const handleSelectExercises = (selected: ExerciseDisplay[]) => {
setSelectedExercises(selected); setSelectedExercises(selected);
// Pre-populate configured exercises // Pre-populate configured exercises with full exercise objects
const initialConfig = selected.map(exercise => ({ const initialConfig = selected.map(exercise => ({
title: exercise.title, title: exercise.title,
exercise: exercise, // Store the complete exercise object with its original ID
targetSets: 0, targetSets: 0,
targetReps: 0 targetReps: 0
})); }));
@ -706,4 +713,4 @@ export function NewTemplateSheet({ isOpen, onClose, onSubmit }: NewTemplateSheet
</View> </View>
</Modal> </Modal>
); );
} }