-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Implement the ability to categorize exercises (e.g., "yoga", "bodyweight", "pilates") and allow users to filter by these categories when generating workouts or browsing the exercise library.
Background
Currently, our application organizes exercises by muscle groups and equipment, but lacks a way to categorize exercises by workout type. Users should be able to easily filter exercises based on categories like yoga, bodyweight, pilates, etc. Some exercises may belong to multiple categories (e.g., plank can be found in bodyweight, yoga, and pilates).
Technical Requirements
1. Data Model Updates
Add a new ExerciseCategory enum to the existing enums:
/**
* ExerciseCategory represents different types of exercise categories
* that can be used to organize and filter exercises.
*/
export enum ExerciseCategory {
Yoga = 'yoga',
Bodyweight = 'bodyweight',
Pilates = 'pilates',
Strength = 'strength',
Cardio = 'cardio',
HIIT = 'hiit',
Stretching = 'stretching',
Mobility = 'mobility',
}Update the ExerciseDetails interface in types.ts to include categories:
export interface ExerciseDetails {
id?: string;
title: string;
muscles: Muscles[];
joints?: Joints[];
equipment?: Equipment[];
categories?: ExerciseCategory[]; // New field for categorization
description?: string;
tips?: string[];
variants?: string[];
metrics: ExerciseMetrics;
}2. Exercise Data Updates
- Update existing exercise data files (yoga.ts, etc.) to include category information
- Handle exercises that span multiple categories
- Ensure consistent categorization across similar exercises
3. Exercise Service Implementation
Create a service to handle exercise categorization and filtering:
import type { ExerciseDetails } from '../types';
import { ExerciseCategory } from '../enums';
import { bodyweightExercises } from '../exercise_data/bodyweight';
import { yogaPoses } from '../exercise_data/yoga';
// Import other exercise collections
// Get all exercises with deduplication
export const getAllExercises = (): ExerciseDetails[] => {
const exerciseMap = new Map<string, ExerciseDetails>();
[...bodyweightExercises, ...yogaPoses].forEach(exercise => {
if (!exercise.id) return;
if (exerciseMap.has(exercise.id)) {
// Merge categories for exercises that appear in multiple collections
const existing = exerciseMap.get(exercise.id)!;
const mergedCategories = [
...(existing.categories || []),
...(exercise.categories || [])
].filter((v, i, a) => a.indexOf(v) === i); // Remove duplicates
exerciseMap.set(exercise.id, {
...existing,
categories: mergedCategories
});
} else {
exerciseMap.set(exercise.id, exercise);
}
});
return Array.from(exerciseMap.values());
};
// Get all available categories
export const getAllCategories = (): ExerciseCategory[] => {
const categories = new Set<ExerciseCategory>();
getAllExercises().forEach(exercise => {
if (exercise.categories) {
exercise.categories.forEach(cat => categories.add(cat));
}
});
return Array.from(categories);
};
// Filter exercises by categories
export const filterByCategories = (
categories: ExerciseCategory[]
): ExerciseDetails[] => {
if (!categories.length) return getAllExercises();
return getAllExercises().filter(exercise =>
exercise.categories?.some(cat => categories.includes(cat))
);
};UI Requirements
-
Multi-select Filter Component:
- Create a reusable component for category selection
- Support for selecting multiple categories
- Visual indication of selected categories
-
Exercise Library Updates:
- Add category filter to the exercise library view
- Show category tags on exercise cards
- Update exercise detail view to display categories
-
Workout Generation Flow:
- Integrate category filtering into workout generation
- Allow users to filter by category before or during workout creation
- Preserve category filters between sessions (localStorage)
-
UX Considerations:
- Ensure filtering is dynamic (updates as user selects/deselects)
- Provide clear visual feedback when filters are applied
- Include a "clear filters" option for easy reset
Performance Considerations
- Implement memoization for filtered results to prevent unnecessary recalculations
- Consider virtualized lists for large datasets
- Implement lazy loading if exercise library becomes very large
- Ensure filter operations are optimized for performance
Acceptance Criteria
- Users can view which categories each exercise belongs to
- Users can filter exercises by one or more categories
- Exercises can belong to multiple categories
- Filtering works in both the exercise library and workout generation flows
- UI is responsive and performs well with the complete exercise library
- Category filters persist between sessions if desired
- Unit tests verify filtering logic works correctly
Implementation Notes
- Start by updating the data model and a sample set of exercises
- Implement the service layer with tests before working on UI components
- Consider adding a migration helper if we need to update existing user data
- Design UI to accommodate future category additions
Suggested Approach
- Update enums.ts with the new ExerciseCategory enum
- Modify the ExerciseDetails interface in types.ts
- Update a subset of exercises with category data as proof of concept
- Implement and test the exercise service
- Create UI components for filtering
- Integrate with existing views
- Extend categorization to all exercises
Related Work
- Exercise data structure (#XX)
- Exercise library view (#XX)
- Workout generation flow (#XX)