diff --git a/src/shared/data/achievements.ts b/src/shared/data/achievements.ts deleted file mode 100644 index a4f2a2e..0000000 --- a/src/shared/data/achievements.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * TabataFit Achievement Definitions - */ - -import { Achievement } from '../types' - -export const ACHIEVEMENTS: Achievement[] = [ - { - id: 'first-burn', - title: 'First Burn', - description: 'Complete your first workout', - icon: 'flame', - requirement: 1, - type: 'workouts', - }, - { - id: 'week-warrior', - title: 'Week Warrior', - description: '7 day streak', - icon: 'calendar', - requirement: 7, - type: 'streak', - }, - { - id: 'century-club', - title: 'Century Club', - description: 'Burn 100 calories total', - icon: 'flame', - requirement: 100, - type: 'calories', - }, - { - id: 'iron-will', - title: 'Iron Will', - description: 'Complete 10 workouts', - icon: 'trophy', - requirement: 10, - type: 'workouts', - }, - { - id: 'tabata-master', - title: 'Tabata Master', - description: 'Complete 50 workouts', - icon: 'star', - requirement: 50, - type: 'workouts', - }, - { - id: 'marathon-burner', - title: 'Marathon Burner', - description: 'Exercise for 100 minutes total', - icon: 'time', - requirement: 100, - type: 'minutes', - }, - { - id: 'unstoppable', - title: 'Unstoppable', - description: '30 day streak', - icon: 'rocket', - requirement: 30, - type: 'streak', - }, - { - id: 'calorie-crusher', - title: 'Calorie Crusher', - description: 'Burn 1000 calories total', - icon: 'flame', - requirement: 1000, - type: 'calories', - }, -] diff --git a/src/shared/data/collections.ts b/src/shared/data/collections.ts deleted file mode 100644 index 66a76a5..0000000 --- a/src/shared/data/collections.ts +++ /dev/null @@ -1,7 +0,0 @@ -/** - * TabataFit Collections - * Collections are fetched from Supabase at runtime. - * Seed data lives in supabase/seed.ts. - */ - -export const FEATURED_COLLECTION_ID = '7-day-burn' diff --git a/src/shared/data/dataService.ts b/src/shared/data/dataService.ts deleted file mode 100644 index 3e0efea..0000000 --- a/src/shared/data/dataService.ts +++ /dev/null @@ -1,265 +0,0 @@ -import { supabase, isSupabaseConfigured } from '../supabase' -import { logger } from '../utils/logger' -import { WORKOUTS, TRAINERS, PROGRAMS, ACHIEVEMENTS } from './index' -import type { Workout, Trainer, Collection, Program, ProgramId } from '../types' -import type { Database } from '../supabase/database.types' - -type WorkoutRow = Database['public']['Tables']['workouts']['Row'] -type TrainerRow = Database['public']['Tables']['trainers']['Row'] -type CollectionRow = Database['public']['Tables']['collections']['Row'] -type CollectionWorkoutRow = Database['public']['Tables']['collection_workouts']['Row'] - -function mapWorkoutFromDB(row: WorkoutRow): Workout { - return { - id: row.id, - title: row.title, - trainerId: row.trainer_id, - category: row.category, - level: row.level, - duration: row.duration as 4 | 8 | 12 | 20, - calories: row.calories, - rounds: row.rounds, - prepTime: row.prep_time, - workTime: row.work_time, - restTime: row.rest_time, - equipment: row.equipment, - musicVibe: row.music_vibe, - exercises: row.exercises, - thumbnailUrl: row.thumbnail_url ?? undefined, - videoUrl: row.video_url ?? undefined, - isFeatured: row.is_featured, - } -} - -function mapTrainerFromDB(row: TrainerRow): Trainer { - return { - id: row.id, - name: row.name, - specialty: row.specialty, - color: row.color, - avatarUrl: row.avatar_url ?? undefined, - workoutCount: row.workout_count, - } -} - -function mapCollectionFromDB( - row: CollectionRow, - workoutIds: string[] -): Collection { - return { - id: row.id, - title: row.title, - description: row.description, - icon: row.icon, - workoutIds, - gradient: row.gradient ? (row.gradient as [string, string]) : undefined, - } -} - -class SupabaseDataService { - async getAllWorkouts(): Promise { - if (!isSupabaseConfigured()) { - return WORKOUTS - } - - const { data, error } = await supabase - .from('workouts') - .select('*') - .order('created_at', { ascending: false }) - - if (error) { - logger.error('Error fetching workouts:', error) - return WORKOUTS - } - - return data?.map(mapWorkoutFromDB) ?? WORKOUTS - } - - async getWorkoutById(id: string): Promise { - if (!isSupabaseConfigured()) { - return WORKOUTS.find((w: Workout) => w.id === id) - } - - const { data, error } = await supabase - .from('workouts') - .select('*') - .eq('id', id) - .single() - - if (error || !data) { - logger.error('Error fetching workout:', error) - return WORKOUTS.find((w: Workout) => w.id === id) - } - - return mapWorkoutFromDB(data) - } - - async getWorkoutsByCategory(category: string): Promise { - if (!isSupabaseConfigured()) { - return WORKOUTS.filter((w: Workout) => w.category === category) - } - - const { data, error } = await supabase - .from('workouts') - .select('*') - .eq('category', category) - - if (error) { - logger.error('Error fetching workouts by category:', error) - return WORKOUTS.filter((w: Workout) => w.category === category) - } - - return data?.map(mapWorkoutFromDB) ?? WORKOUTS.filter((w: Workout) => w.category === category) - } - - async getWorkoutsByTrainer(trainerId: string): Promise { - if (!isSupabaseConfigured()) { - return WORKOUTS.filter((w: Workout) => w.trainerId === trainerId) - } - - const { data, error } = await supabase - .from('workouts') - .select('*') - .eq('trainer_id', trainerId) - - if (error) { - logger.error('Error fetching workouts by trainer:', error) - return WORKOUTS.filter((w: Workout) => w.trainerId === trainerId) - } - - return data?.map(mapWorkoutFromDB) ?? WORKOUTS.filter((w: Workout) => w.trainerId === trainerId) - } - - async getFeaturedWorkouts(): Promise { - if (!isSupabaseConfigured()) { - return WORKOUTS.filter((w: Workout) => w.isFeatured) - } - - const { data, error } = await supabase - .from('workouts') - .select('*') - .eq('is_featured', true) - - if (error) { - logger.error('Error fetching featured workouts:', error) - return WORKOUTS.filter((w: Workout) => w.isFeatured) - } - - return data?.map(mapWorkoutFromDB) ?? WORKOUTS.filter((w: Workout) => w.isFeatured) - } - - async getAllTrainers(): Promise { - if (!isSupabaseConfigured()) { - return TRAINERS - } - - const { data, error } = await supabase - .from('trainers') - .select('*') - - if (error) { - logger.error('Error fetching trainers:', error) - return TRAINERS - } - - return data?.map(mapTrainerFromDB) ?? TRAINERS - } - - async getTrainerById(id: string): Promise { - if (!isSupabaseConfigured()) { - return TRAINERS.find((t: Trainer) => t.id === id) - } - - const { data, error } = await supabase - .from('trainers') - .select('*') - .eq('id', id) - .single() - - if (error || !data) { - logger.error('Error fetching trainer:', error) - return TRAINERS.find((t: Trainer) => t.id === id) - } - - return mapTrainerFromDB(data) - } - - async getAllCollections(): Promise { - if (!isSupabaseConfigured()) { - return [] - } - - const { data: collectionsData, error: collectionsError } = await supabase - .from('collections') - .select('*') - - if (collectionsError) { - logger.error('Error fetching collections:', collectionsError) - return [] - } - - const { data: workoutLinks, error: linksError } = await supabase - .from('collection_workouts') - .select('*') - .order('sort_order') - - if (linksError) { - logger.error('Error fetching collection workouts:', linksError) - return [] - } - - const workoutIdsByCollection: Record = {} - workoutLinks?.forEach((link: CollectionWorkoutRow) => { - if (!workoutIdsByCollection[link.collection_id]) { - workoutIdsByCollection[link.collection_id] = [] - } - workoutIdsByCollection[link.collection_id].push(link.workout_id) - }) - - return collectionsData?.map((row: CollectionRow) => - mapCollectionFromDB(row, workoutIdsByCollection[row.id] || []) - ) ?? [] - } - - async getCollectionById(id: string): Promise { - if (!isSupabaseConfigured()) { - return undefined - } - - const { data: collection, error: collectionError } = await supabase - .from('collections') - .select('*') - .eq('id', id) - .single() - - if (collectionError || !collection) { - logger.error('Error fetching collection:', collectionError) - return undefined - } - - const { data: workoutLinks, error: linksError } = await supabase - .from('collection_workouts') - .select('workout_id') - .eq('collection_id', id) - .order('sort_order') - - if (linksError) { - logger.error('Error fetching collection workouts:', linksError) - return undefined - } - - const workoutIds = workoutLinks?.map((link: { workout_id: string }) => link.workout_id) || [] - return mapCollectionFromDB(collection, workoutIds) - } - - async getAllPrograms(): Promise { - // Legacy programs are local only — new workout programs use workoutPrograms.ts - return Object.values(PROGRAMS) - } - - async getAchievements() { - return ACHIEVEMENTS - } -} - -export const dataService = new SupabaseDataService() diff --git a/src/shared/data/programs.ts b/src/shared/data/programs.ts deleted file mode 100644 index 6c70ab7..0000000 --- a/src/shared/data/programs.ts +++ /dev/null @@ -1,1742 +0,0 @@ -/** - * TabataFit Program Workouts - * 3 Programs × 4 Weeks × 5 Workouts = 60 physiotherapist-designed workouts - * All workouts: 8 exercises × 20s work / 10s rest = 4 minutes - */ - -import { Program, Assessment, ProgramId, WeekNumber, Week, ProgramWorkout } from '../types/program' -import type { WorkoutLevel, WorkoutCategory, MusicVibe } from '../types/workout' - -type ProgramWorkoutInput = { - id: string - week: 1 | 2 | 3 | 4 - order: number - title: string - description: string - exercises: string[] - equipment: string[] - focus: string[] - tips: string[] -} - -type BuiltProgramWorkout = ProgramWorkout & { - level: WorkoutLevel - category: WorkoutCategory - trainerId: string - calories: number - rounds: number - prepTime: number - workTime: number - restTime: number - musicVibe: MusicVibe - isFeatured: boolean - thumbnailUrl?: string - videoUrl?: string -} - -/** Derive difficulty level from the week number in a progressive program */ -function getLevelFromWeek(week: number): WorkoutLevel { - if (week <= 2) return 'Beginner' - if (week === 3) return 'Intermediate' - return 'Advanced' -} - -// Helper to create exercises with consistent structure -const createExercise = (name: string, modification?: string, progression?: string) => ({ - name, - duration: 20 as const, - modification, - progression, -}) - -// ═══════════════════════════════════════════════════════════════════════════ -// UPPER BODY PROGRAM -// ═══════════════════════════════════════════════════════════════════════════ - -const upperBodyWorkouts: ProgramWorkoutInput[] = [ - // WEEK 1: Foundation - { - id: 'ub-w1-d1', - week: 1, - order: 1, - title: 'Posture Perfect', - description: 'Build foundational shoulder stability and correct rounded posture', - exercises: [ - 'Wall Angels', - 'Scapular Push-ups', - 'Arm Circles Forward', - 'Arm Circles Backward', - 'Doorway Chest Opens', - 'Band Pull-Aparts', - 'Wall Push-ups', - 'Shoulder Blade Squeezes', - ], - equipment: ['Resistance band', 'Wall'], - focus: ['Posture', 'Shoulder Mobility', 'Scapular Control'], - tips: [ - 'Keep movements slow and controlled', - 'Focus on feeling shoulder blades move', - 'Breathe deeply throughout', - ], - }, - { - id: 'ub-w1-d2', - week: 1, - order: 2, - title: 'Shoulder Stability', - description: 'Strengthen the rotator cuff and stabilize shoulder joints', - exercises: [ - 'Y-T-W Raises', - 'Arm Hugs', - 'Band External Rotation L', - 'Band External Rotation R', - 'Plank to Down Dog', - 'Band Face Pulls', - 'Incline Push-ups', - 'Dead Bug Hold', - ], - equipment: ['Resistance band', 'Wall or elevated surface'], - focus: ['Rotator Cuff', 'Shoulder Stability', 'Core'], - tips: [ - 'Keep elbows at 90° for rotations', - 'Move with intention, not speed', - 'Stop if you feel any pinching', - ], - }, - { - id: 'ub-w1-d3', - week: 1, - order: 3, - title: 'Chest & Back Balance', - description: 'Create muscular balance between pushing and pulling muscles', - exercises: [ - 'Standing Band Rows', - 'Push-up Plank Hold', - 'Band Chest Opens', - 'Wall Slide Holds', - 'Renegade Row Prep', - 'Modified Push-ups', - 'Band Reverse Flyes', - 'Prone Y Raises', - ], - equipment: ['Resistance band', 'Wall'], - focus: ['Chest', 'Back', 'Postural Balance'], - tips: [ - 'Squeeze shoulder blades on rows', - 'Keep core engaged throughout', - 'Quality over quantity', - ], - }, - { - id: 'ub-w1-d4', - week: 1, - order: 4, - title: 'Arm Foundations', - description: 'Build arm strength with joint-friendly movements', - exercises: [ - 'Wall Push-ups', - 'Tricep Wall Dips', - 'Band Bicep Curls', - 'Plank Shoulder Taps', - 'Push-up Hold Low', - 'Tricep Kickbacks', - 'Hammer Curls with Band', - 'Arm Circles Combo', - ], - equipment: ['Resistance band', 'Wall'], - focus: ['Arms', 'Biceps', 'Triceps'], - tips: [ - 'Control the lowering phase', - 'Full range of motion', - 'Keep elbows close on tricep work', - ], - }, - { - id: 'ub-w1-d5', - week: 1, - order: 5, - title: 'Full Upper Mobility', - description: 'Improve range of motion and movement quality', - exercises: [ - 'Arm Swings Forward', - 'Arm Swings Backward', - 'Shoulder Rolls', - 'Neck Mobility Flow', - 'Thoracic Spine Rotations', - 'Chest Openers Dynamic', - 'Scapular Push-ups', - 'Child\'s Pose to Up Dog', - ], - equipment: ['None'], - focus: ['Mobility', 'Flexibility', 'Recovery'], - tips: [ - 'Move through full range', - 'Gentle and controlled', - 'Focus on breathing', - ], - }, - - // WEEK 2: Building - { - id: 'ub-w2-d1', - week: 2, - order: 1, - title: 'Dynamic Shoulders', - description: 'Increase shoulder strength with dynamic movements', - exercises: [ - 'Band Overhead Press', - 'Push-ups with Rotation', - 'Band Lateral Raises', - 'Commando Planks', - 'Band Front Raises', - 'Spiderman Push-ups', - 'Band Upright Rows', - 'Plank Up-Downs', - ], - equipment: ['Resistance band'], - focus: ['Shoulders', 'Dynamic Strength', 'Stability'], - tips: [ - 'Keep core tight during rotations', - 'Full extension on presses', - 'Control the movement', - ], - }, - { - id: 'ub-w2-d2', - week: 2, - order: 2, - title: 'Push Power', - description: 'Develop pushing strength with progressive variations', - exercises: [ - 'Incline Push-ups', - 'Decline Push-ups', - 'Wide Push-ups', - 'Diamond Push-ups', - 'Push-up Hold Mid', - 'Pike Push-ups', - 'Push-up to Side Plank', - 'Chest Tap Push-ups', - ], - equipment: ['Elevated surface'], - focus: ['Chest', 'Triceps', 'Pushing Strength'], - tips: [ - 'Modify on knees if needed', - 'Keep body in straight line', - 'Lower with control', - ], - }, - { - id: 'ub-w2-d3', - week: 2, - order: 3, - title: 'Pull & Row Strength', - description: 'Strengthen back muscles with pulling movements', - exercises: [ - 'Band Rows', - 'Superman Holds', - 'Band Reverse Flyes', - 'Prone W Raises', - 'Band Face Pulls', - 'Reverse Snow Angels', - 'Single Arm Band Row L', - 'Single Arm Band Row R', - ], - equipment: ['Resistance band'], - focus: ['Back', 'Rhomboids', 'Posture'], - tips: [ - 'Pull shoulder blades together', - 'Keep shoulders down and back', - 'Squeeze at the end range', - ], - }, - { - id: 'ub-w2-d4', - week: 2, - order: 4, - title: 'Arm Sculptor', - description: 'Intensive arm training with band resistance', - exercises: [ - 'Band Bicep Curls', - 'Band Tricep Extensions', - 'Hammer Curls Band', - 'Overhead Tricep Band', - 'Concentration Curls', - 'Tricep Dips', - 'Zottman Curls Band', - 'Diamond Push-ups', - ], - equipment: ['Resistance band', 'Chair or bench'], - focus: ['Biceps', 'Triceps', 'Arm Definition'], - tips: [ - 'Full range of motion', - 'Control both up and down', - 'Keep tension on the band', - ], - }, - { - id: 'ub-w2-d5', - week: 2, - order: 5, - title: 'Core Integration', - description: 'Connect upper body movements with core stability', - exercises: [ - 'Plank to Push-up', - 'Renegade Rows', - 'Push-up to T-Rotation', - 'Plank Jacks', - 'Shoulder Tap Push-ups', - 'Plank Up-Downs', - 'Walkout to Push-up', - 'Plank Hold', - ], - equipment: ['None'], - focus: ['Core', 'Shoulders', 'Integration'], - tips: [ - 'Keep hips stable', - 'No rocking side to side', - 'Breathe steadily', - ], - }, - - // WEEK 3: Challenge - { - id: 'ub-w3-d1', - week: 3, - order: 1, - title: 'Explosive Upper', - description: 'Add power and explosiveness to upper body movements', - exercises: [ - 'Clap Push-ups (or fast)', - 'Plyo Push-ups', - 'Explosive Band Press', - 'Medicine Ball Slams (or band)', - 'Push-up Burpees', - 'Band Snatch', - 'Power Push-ups', - 'Mountain Climber Push-ups', - ], - equipment: ['Resistance band', 'Optional: light weights'], - focus: ['Power', 'Explosiveness', 'Speed'], - tips: [ - 'Land softly on joints', - 'Modify if joints feel stressed', - 'Maximum effort each rep', - ], - }, - { - id: 'ub-w3-d2', - week: 3, - order: 2, - title: 'Endurance Push', - description: 'Build muscular endurance with higher volume patterns', - exercises: [ - 'Fast Push-ups', - 'Band Press Burnout', - 'Dive Bombers', - 'Pike Push-ups', - 'Close Grip Push-ups', - 'Hindu Push-ups', - 'Archer Push-ups L', - 'Archer Push-ups R', - ], - equipment: ['Resistance band'], - focus: ['Endurance', 'Pushing', 'Volume'], - tips: [ - 'Maintain form as you fatigue', - 'Take mini breaks if needed', - 'Focus on continuous movement', - ], - }, - { - id: 'ub-w3-d3', - week: 3, - order: 3, - title: 'Back & Core Blast', - description: 'Intensive back workout with core integration', - exercises: [ - 'Pull-up Progression', - 'Band Rows Fast', - 'Superman to Plank', - 'Reverse Flyes Pulse', - 'Band High Rows', - 'Prone Cobras Hold', - 'Single Arm Rows Fast L', - 'Single Arm Rows Fast R', - ], - equipment: ['Resistance band', 'Pull-up bar optional'], - focus: ['Back', 'Lats', 'Core Connection'], - tips: [ - 'Engage lats on every pull', - 'Keep movements explosive', - 'Mind-muscle connection', - ], - }, - { - id: 'ub-w3-d4', - week: 3, - order: 4, - title: 'Arm Intensity', - description: 'High-intensity arm training with compound movements', - exercises: [ - 'Commando Curls', - 'Tricep Burnout Set', - '21s Bicep Curls', - 'Close to Wide Push-ups', - 'Band Hammer Curls Fast', - 'Tricep Extension Burnout', - 'Slow Negative Curls', - 'Fast Tricep Dips', - ], - equipment: ['Resistance band', 'Chair'], - focus: ['Arms', 'Intensity', 'Muscle Fatigue'], - tips: [ - 'Push through the burn', - 'Maintain form on fatigue', - 'Control the negatives', - ], - }, - { - id: 'ub-w3-d5', - week: 3, - order: 5, - title: 'Total Upper Challenge', - description: 'Complete upper body challenge combining all elements', - exercises: [ - 'Burpee Push-ups', - 'Renegade Row Push-ups', - 'Plank to Down Dog', - 'Shoulder Complex', - 'T Push-ups', - 'Walkout Push-ups', - 'Plank Rotation Reach', - 'Final Push-up Burnout', - ], - equipment: ['Resistance band'], - focus: ['Total Upper Body', 'Challenge', 'Integration'], - tips: [ - 'This is tough - pace yourself', - 'Modify push-ups on knees if needed', - 'Finish strong!', - ], - }, - - // WEEK 4: Peak Performance - { - id: 'ub-w4-d1', - week: 4, - order: 1, - title: 'Peak Power', - description: 'Maximum intensity power and strength movements', - exercises: [ - 'Explosive Push-ups Max', - 'Band Clean & Press', - 'Power Rows', - 'Plyo Push-up Variations', - 'Snatch Band Power', - 'Clap Push-ups', - 'Thrusters Band', - 'Max Effort Push-ups', - ], - equipment: ['Resistance band'], - focus: ['Peak Power', 'Max Effort', 'Strength'], - tips: [ - 'Give 100% every rep', - 'Full explosive range', - 'Recover between if needed', - ], - }, - { - id: 'ub-w4-d2', - week: 4, - order: 2, - title: 'Strength Peak', - description: 'Maximum strength challenge with slow tempos', - exercises: [ - 'Slow Push-ups (5s down)', - 'Max Hold Plank Push', - 'Slow Rows (5s squeeze)', - 'Isometric Push-up Holds', - 'Eccentric-Only Push-ups', - 'Max Tension Band Rows', - 'Pike Push-up Holds', - 'Final Burnout Set', - ], - equipment: ['Resistance band'], - focus: ['Max Strength', 'Time Under Tension', 'Control'], - tips: [ - 'Embrace the slow burn', - 'Maximum muscle engagement', - 'Quality over speed', - ], - }, - { - id: 'ub-w4-d3', - week: 4, - order: 3, - title: 'Endurance Elite', - description: 'Elite-level endurance challenge - push your limits', - exercises: [ - '100 Rep Challenge Style', - 'Continuous Push-ups', - 'Band Press Endurance', - 'Pyramid Push-ups', - 'Ladder Challenge', - 'Non-Stop Flow', - 'Max Rep Test', - 'Final Push', - ], - equipment: ['Resistance band'], - focus: ['Elite Endurance', 'Mental Toughness', 'Stamina'], - tips: [ - 'This is the ultimate test', - 'Break through mental barriers', - 'You\'ve trained for this!', - ], - }, - { - id: 'ub-w4-d4', - week: 4, - order: 4, - title: 'Arm Mastery', - description: 'Complete arm mastery with all techniques combined', - exercises: [ - 'Giant Set Curls', - 'Tricep Death Set', - 'Drop Set Simulation', - 'Rest-Pause Curls', - 'Burnout Extensions', - '21s Method', - 'Max Tension Curls', - 'Final Arm Blast', - ], - equipment: ['Resistance band'], - focus: ['Arm Mastery', 'Advanced Techniques', 'Complete Fatigue'], - tips: [ - 'Use every technique learned', - 'Push to true failure', - 'You\'ve earned this strength', - ], - }, - { - id: 'ub-w4-d5', - week: 4, - order: 5, - title: 'Upper Body Final Challenge', - description: 'The ultimate upper body test - combine everything', - exercises: [ - 'Complex 1: Push-Pull-Push', - 'Complex 2: Row-Press-Row', - 'Complex 3: Curl-Extension-Curl', - 'Complex 4: Power Flow', - 'Complex 5: Endurance Burn', - 'Complex 6: Max Strength', - 'Complex 7: Speed & Power', - 'Victory Lap: Celebration Flow', - ], - equipment: ['Resistance band'], - focus: ['Ultimate Challenge', 'Program Completion', 'Mastery'], - tips: [ - 'This is your victory lap', - 'Showcase your 4 weeks of progress', - 'Be proud of how far you\'ve come!', - ], - }, -] - -// ═══════════════════════════════════════════════════════════════════════════ -// LOWER BODY PROGRAM -// ═══════════════════════════════════════════════════════════════════════════ - -const lowerBodyWorkouts: ProgramWorkoutInput[] = [ - // WEEK 1: Foundation - { - id: 'lb-w1-d1', - week: 1, - order: 1, - title: 'Glute Activation', - description: 'Wake up dormant glutes and establish hip stability', - exercises: [ - 'Glute Bridges', - 'Clamshells', - 'Donkey Kicks L', - 'Donkey Kicks R', - 'Fire Hydrants L', - 'Fire Hydrants R', - 'Glute Bridge Holds', - 'Banded Side Steps', - ], - equipment: ['Resistance band optional'], - focus: ['Glutes', 'Hip Stability', 'Activation'], - tips: [ - 'Squeeze glutes at the top', - 'Focus on muscle contraction', - 'Quality over speed', - ], - }, - { - id: 'lb-w1-d2', - week: 1, - order: 2, - title: 'Squat Foundation', - description: 'Master proper squat mechanics and knee tracking', - exercises: [ - 'Air Squats', - 'Wall Sits', - 'Box Squats', - 'Sit to Stand', - 'Goblet Squat Pattern', - 'Squat Holds', - 'Mini Squats', - 'Squat Mobility Flow', - ], - equipment: ['Chair or bench'], - focus: ['Squat Pattern', 'Knee Health', 'Mobility'], - tips: [ - 'Knees track over toes', - 'Keep chest up', - 'Weight in heels', - ], - }, - { - id: 'lb-w1-d3', - week: 1, - order: 3, - title: 'Lunge Mechanics', - description: 'Learn proper lunge form for knee-friendly movement', - exercises: [ - 'Reverse Lunges', - 'Static Lunges L', - 'Static Lunges R', - 'Side Lunges', - 'Curtsy Lunges', - 'Lunge Holds', - 'Step-ups Low', - 'Calf Raises', - ], - equipment: ['Step or low platform'], - focus: ['Lunges', 'Single Leg', 'Knee Health'], - tips: [ - 'Step back to reduce knee stress', - 'Front knee stays over ankle', - 'Control the lowering', - ], - }, - { - id: 'lb-w1-d4', - week: 1, - order: 4, - title: 'Hip & Ankle Mobility', - description: 'Improve mobility for better movement quality', - exercises: [ - 'Hip Circles L', - 'Hip Circles R', - 'Ankle Circles L', - 'Ankle Circles R', - 'Deep Squat Hold', - 'Cossack Squats Light', - '90-90 Hip Switches', - 'World\'s Greatest Stretch', - ], - equipment: ['None'], - focus: ['Mobility', 'Flexibility', 'Joint Health'], - tips: [ - 'Move through full range', - 'Gentle and controlled', - 'Focus on problem areas', - ], - }, - { - id: 'lb-w1-d5', - week: 1, - order: 5, - title: 'Leg Foundation Flow', - description: 'Integrate all lower body movements with proper form', - exercises: [ - 'Bodyweight Squats', - 'Glute Bridges', - 'Reverse Lunges', - 'Calf Raises', - 'Lateral Steps', - 'Hip Hinge Practice', - 'Balance Work L', - 'Balance Work R', - ], - equipment: ['None'], - focus: ['Integration', 'Balance', 'Coordination'], - tips: [ - 'Apply what you learned', - 'Focus on movement quality', - 'Celebrate your progress!', - ], - }, - - // WEEK 2: Building - { - id: 'lb-w2-d1', - week: 2, - order: 1, - title: 'Glute Builder', - description: 'Strengthen glutes with progressive loading', - exercises: [ - 'Single Leg Glute Bridges L', - 'Single Leg Glute Bridges R', - 'Banded Hip Thrusts', - 'Banded Glute Bridges', - 'Fire Hydrant with Band', - 'Donkey Kicks with Band', - 'Glute Bridge March', - 'Side Plank Clamshells', - ], - equipment: ['Resistance band'], - focus: ['Glutes', 'Hip Strength', 'Stability'], - tips: [ - 'Drive through the heel', - 'Squeeze at the top', - 'Keep hips level on single leg', - ], - }, - { - id: 'lb-w2-d2', - week: 2, - order: 2, - title: 'Squat Strength', - description: 'Build squat strength with variations', - exercises: [ - 'Jump Squats', - 'Pause Squats', - 'Pulse Squats', - 'Sumo Squats', - 'Narrow Squats', - 'Squat Hold Challenge', - 'Prisoner Squats', - 'Frog Jumps', - ], - equipment: ['None'], - focus: ['Squat Strength', 'Power', 'Endurance'], - tips: [ - 'Land softly on jumps', - 'Maintain form throughout', - 'Embrace the burn', - ], - }, - { - id: 'lb-w2-d3', - week: 2, - order: 3, - title: 'Lunge Power', - description: 'Develop single-leg strength and stability', - exercises: [ - 'Walking Lunges', - 'Jumping Lunges', - 'Reverse to Forward Lunges', - 'Lateral Lunges Deep', - 'Curtsy Lunges with Hop', - 'Step-ups High', - 'Split Squats L', - 'Split Squats R', - ], - equipment: ['Higher step or bench'], - focus: ['Lunge Power', 'Single Leg', 'Explosiveness'], - tips: [ - 'Stay controlled on jumps', - 'Full range on step-ups', - 'Keep front knee stable', - ], - }, - { - id: 'lb-w2-d4', - week: 2, - order: 4, - title: 'Calf & Ankle Strength', - description: 'Build resilient calves and ankle stability', - exercises: [ - 'Double Leg Calf Raises', - 'Single Leg Calf Raises L', - 'Single Leg Calf Raises R', - 'Calf Raise Holds', - 'Eccentric Calf Lowers', - 'Jump Rope Simulation', - 'Tibialis Raises', - 'Ankle Stability Holds', - ], - equipment: ['Step edge optional'], - focus: ['Calves', 'Ankles', 'Lower Leg'], - tips: [ - 'Full range of motion', - 'Pause at the top', - 'Control the lowering', - ], - }, - { - id: 'lb-w2-d5', - week: 2, - order: 5, - title: 'Leg Integration', - description: 'Combine all lower body patterns', - exercises: [ - 'Squat to Lunge Combo', - 'Glute Bridge to March', - 'Lateral to Reverse Lunge', - 'Calf Raise Complex', - 'Single Leg Flow L', - 'Single Leg Flow R', - 'Plyo Base Moves', - 'Recovery Flow', - ], - equipment: ['Resistance band optional'], - focus: ['Integration', 'Flow', 'Coordination'], - tips: [ - 'Smooth transitions', - 'Maintain form', - 'Breathe through the work', - ], - }, - - // WEEK 3: Challenge - { - id: 'lb-w3-d1', - week: 3, - order: 1, - title: 'Glute Challenge', - description: 'Intensive glute-focused challenge workout', - exercises: [ - 'Hip Thrust Burnout', - 'Banded Glute Burnout', - 'Single Leg Hip Thrust L', - 'Single Leg Hip Thrust R', - 'Glute Bridge Walkouts', - 'Banded Lateral Walks', - 'Glute March Challenge', - 'Final Glute Squeeze', - ], - equipment: ['Resistance band'], - focus: ['Glute Challenge', 'Burnout', 'Strength'], - tips: [ - 'Push through the burn', - 'Maximum glute contraction', - 'You\'re getting stronger!', - ], - }, - { - id: 'lb-w3-d2', - week: 3, - order: 2, - title: 'Plyo Legs', - description: 'Explosive leg power with plyometric movements', - exercises: [ - 'Broad Jumps', - 'Box Jumps or Step-ups Fast', - 'Jump Squats Max Height', - 'Split Jump Lunges', - 'Tuck Jumps', - 'Lateral Bounds', - 'Depth Jumps Modified', - 'Plyo Finisher', - ], - equipment: ['Box or step'], - focus: ['Plyometrics', 'Power', 'Explosiveness'], - tips: [ - 'Land soft and quiet', - 'Explode up with power', - 'Modify if joints hurt', - ], - }, - { - id: 'lb-w3-d3', - week: 3, - order: 3, - title: 'Lunge Intensity', - description: 'High-intensity lunge variations', - exercises: [ - 'Jump Lunge Switch', - 'Lunge Complex L', - 'Lunge Complex R', - 'Walking Lunge Burnout', - 'Pulse Lunge Challenge', - 'Explosive Step-ups', - 'Lateral Lunge Jumps', - 'Lunge Ladder', - ], - equipment: ['Step or bench'], - focus: ['Lunge Intensity', 'Endurance', 'Power'], - tips: [ - 'Maximum intensity', - 'Control on landings', - 'Push through fatigue', - ], - }, - { - id: 'lb-w3-d4', - week: 3, - order: 4, - title: 'Leg Endurance', - description: 'Build leg endurance with continuous work', - exercises: [ - '100 Rep Squat Challenge', - 'Continuous Lunges', - 'Squat Hold Endurance', - 'Wall Sit Challenge', - 'Calf Raise Marathon', - 'Balance Challenge L', - 'Balance Challenge R', - 'Final Burnout Set', - ], - equipment: ['Wall'], - focus: ['Endurance', 'Mental Toughness', 'Stamina'], - tips: [ - 'Embrace the challenge', - 'Break mental barriers', - 'You can do this!', - ], - }, - { - id: 'lb-w3-d5', - week: 3, - order: 5, - title: 'Total Leg Challenge', - description: 'Complete lower body challenge', - exercises: [ - 'Leg Complex 1', - 'Leg Complex 2', - 'Leg Complex 3', - 'Leg Complex 4', - 'Leg Complex 5', - 'Leg Complex 6', - 'Leg Complex 7', - 'Leg Complex 8', - ], - equipment: ['Resistance band', 'Step'], - focus: ['Total Legs', 'Challenge', 'Integration'], - tips: [ - 'Maximum effort', - 'Form over speed', - 'You\'re in beast mode!', - ], - }, - - // WEEK 4: Peak Performance - { - id: 'lb-w4-d1', - week: 4, - order: 1, - title: 'Peak Glute Power', - description: 'Maximum glute strength and power', - exercises: [ - 'Max Band Hip Thrusts', - 'Explosive Glute Bridges', - 'Single Leg Power L', - 'Single Leg Power R', - 'Glute Bridge Burnout', - 'Banded Walk Challenge', - 'Power Glute Squeeze', - 'Final Glute Push', - ], - equipment: ['Resistance band'], - focus: ['Peak Power', 'Max Strength', 'Glutes'], - tips: [ - 'Give it everything', - 'Maximum contraction', - 'You\'ve built this strength!', - ], - }, - { - id: 'lb-w4-d2', - week: 4, - order: 2, - title: 'Ultimate Squat Challenge', - description: 'The ultimate squat test', - exercises: [ - 'Max Rep Squats', - 'Explosive Squat Challenge', - 'Pause Squat Holds', - 'Jump Squat Max', - 'Squat Ladder', - 'Single Leg Squat Prep L', - 'Single Leg Squat Prep R', - 'Squat Victory Set', - ], - equipment: ['None'], - focus: ['Ultimate Squat', 'Peak Performance', 'Mastery'], - tips: [ - 'Showcase your strength', - 'Perfect form throughout', - 'You\'re a squat master!', - ], - }, - { - id: 'lb-w4-d3', - week: 4, - order: 3, - title: 'Lunge Mastery', - description: 'Complete lunge mastery challenge', - exercises: [ - 'Lunge Mastery L', - 'Lunge Mastery R', - 'Jump Lunge Challenge', - 'Complex Lunge Flow', - 'Endurance Lunge Test', - 'Power Lunge Sets', - 'Balance Lunge Challenge', - 'Victory Lunges', - ], - equipment: ['Step optional'], - focus: ['Lunge Mastery', 'Complete Challenge', 'Perfection'], - tips: [ - 'Nail every rep', - 'Maximum control', - 'You\'ve mastered lunges!', - ], - }, - { - id: 'lb-w4-d4', - week: 4, - order: 4, - title: 'Leg Power Peak', - description: 'Maximum leg power and explosiveness', - exercises: [ - 'Max Height Jumps', - 'Broad Jump Challenge', - 'Explosive Combo 1', - 'Explosive Combo 2', - 'Speed Squats', - 'Power Lunges', - 'Jump Challenge', - 'Power Finish', - ], - equipment: ['Box or step'], - focus: ['Peak Power', 'Explosiveness', 'Athleticism'], - tips: [ - 'Maximum height on jumps', - 'Explode with power', - 'Show your athleticism!', - ], - }, - { - id: 'lb-w4-d5', - week: 4, - order: 5, - title: 'Lower Body Final Challenge', - description: 'The ultimate lower body test and celebration', - exercises: [ - 'Victory Complex 1', - 'Victory Complex 2', - 'Victory Complex 3', - 'Victory Complex 4', - 'Victory Complex 5', - 'Victory Complex 6', - 'Victory Complex 7', - 'Victory Lap Celebration', - ], - equipment: ['Resistance band', 'Step'], - focus: ['Ultimate Challenge', 'Program Complete', 'Celebration'], - tips: [ - 'This is YOUR moment', - 'Showcase 4 weeks of gains', - 'Be incredibly proud!', - ], - }, -] - -// ═══════════════════════════════════════════════════════════════════════════ -// FULL BODY PROGRAM -// ═══════════════════════════════════════════════════════════════════════════ - -const fullBodyWorkouts: ProgramWorkoutInput[] = [ - // WEEK 1: Foundation - { - id: 'fb-w1-d1', - week: 1, - order: 1, - title: 'Movement Basics', - description: 'Learn fundamental movement patterns with proper form', - exercises: [ - 'Air Squats', - 'Incline Push-ups', - 'Glute Bridges', - 'Plank Hold', - 'Reverse Lunges', - 'Arm Circles', - 'High Knees March', - 'Cat-Cow Stretch', - ], - equipment: ['Wall or elevated surface'], - focus: ['Movement Patterns', 'Form', 'Foundation'], - tips: [ - 'Focus on quality movement', - 'Learn each pattern well', - 'This is your foundation', - ], - }, - { - id: 'fb-w1-d2', - week: 1, - order: 2, - title: 'Push & Pull Basics', - description: 'Master pushing and pulling fundamentals', - exercises: [ - 'Wall Push-ups', - 'Doorway Rows', - 'Knee Push-ups', - 'Superman Holds', - 'Incline Push-ups', - 'Band Pulls', - 'Push-up Plank', - 'Prone Cobra', - ], - equipment: ['Wall', 'Resistance band optional'], - focus: ['Push', 'Pull', 'Upper Foundation'], - tips: [ - 'Feel the right muscles working', - 'Control both directions', - 'Build the mind-muscle connection', - ], - }, - { - id: 'fb-w1-d3', - week: 1, - order: 3, - title: 'Hinge & Squat', - description: 'Learn hip hinge and squat patterns safely', - exercises: [ - 'Bodyweight Squats', - 'Good Mornings', - 'Glute Bridges', - 'Wall Sit', - 'Hip Hinge Practice', - 'Box Squats', - 'Bird Dog', - 'Dead Bug', - ], - equipment: ['Wall', 'Chair'], - focus: ['Hinge', 'Squat', 'Posterior Chain'], - tips: [ - 'Feel your hips hinge', - 'Keep back neutral', - 'Knees track properly', - ], - }, - { - id: 'fb-w1-d4', - week: 1, - order: 4, - title: 'Core & Stability', - description: 'Build core stability for all movements', - exercises: [ - 'Forearm Plank', - 'Side Plank L', - 'Side Plank R', - 'Glute Bridge March', - 'Dead Bug Slow', - 'Bird Dog Holds', - 'Plank Shoulder Taps', - 'Hollow Body Hold', - ], - equipment: ['None'], - focus: ['Core', 'Stability', 'Control'], - tips: [ - 'Keep core engaged throughout', - 'No sagging or arching', - 'Breathe steadily', - ], - }, - { - id: 'fb-w1-d5', - week: 1, - order: 5, - title: 'Full Body Integration', - description: 'Combine all movement patterns together', - exercises: [ - 'Squat to Push-up Flow', - 'Lunge to Rotation', - 'Plank Walkout', - 'Glute Bridge to Reach', - 'Inchworm', - 'Bear Crawl Hold', - 'Sun Salutation', - 'Recovery Flow', - ], - equipment: ['None'], - focus: ['Integration', 'Flow', 'Coordination'], - tips: [ - 'Smooth transitions', - 'Apply what you learned', - 'You\'re building great habits!', - ], - }, - - // WEEK 2: Building - { - id: 'fb-w2-d1', - week: 2, - order: 1, - title: 'Dynamic Full Body', - description: 'Add dynamic movement to your foundation', - exercises: [ - 'Jump Squats', - 'Push-up to T-Rotation', - 'Reverse Lunges with Twist', - 'Plank Jacks', - 'Glute Bridge Walkouts', - 'Mountain Climbers Slow', - 'Lateral Lunges', - 'Thread the Needle', - ], - equipment: ['None'], - focus: ['Dynamic Movement', 'Coordination', 'Flow'], - tips: [ - 'Control the dynamic moves', - 'Land softly on jumps', - 'Rotate from the mid-back', - ], - }, - { - id: 'fb-w2-d2', - week: 2, - order: 2, - title: 'Strength Builder', - description: 'Build strength with compound movements', - exercises: [ - 'Push-ups', - 'Air Squats Tempo', - 'Renegade Rows', - 'Reverse Lunges', - 'Plank to Push-up', - 'Glute Bridges Single Leg', - 'Tricep Dips', - 'Calf Raises', - ], - equipment: ['None'], - focus: ['Strength', 'Compound Moves', 'Power'], - tips: [ - 'Full range of motion', - 'Control the tempo', - 'You\'re getting stronger!', - ], - }, - { - id: 'fb-w2-d3', - week: 2, - order: 3, - title: 'Cardio & Core', - description: 'Elevate heart rate while building core strength', - exercises: [ - 'High Knees', - 'Plank Hold', - 'Jumping Jacks', - 'Side Plank L', - 'Butt Kicks', - 'Side Plank R', - 'Speed Skaters', - 'Dead Bug', - ], - equipment: ['None'], - focus: ['Cardio', 'Core', 'Endurance'], - tips: [ - 'Keep core tight during cardio', - 'Find your rhythm', - 'Push the pace safely', - ], - }, - { - id: 'fb-w2-d4', - week: 2, - order: 4, - title: 'Power & Explosiveness', - description: 'Develop power with explosive bodyweight movements', - exercises: [ - 'Broad Jumps', - 'Explosive Push-ups', - 'Jump Lunges', - 'Plyo Squats', - 'Tuck Jumps', - 'Push-up Burpees', - 'Lateral Bounds', - 'High Knee Sprint', - ], - equipment: ['None'], - focus: ['Power', 'Explosiveness', 'Athleticism'], - tips: [ - 'Maximum explosive effort', - 'Land soft and controlled', - 'Modify if joints hurt', - ], - }, - { - id: 'fb-w2-d5', - week: 2, - order: 5, - title: 'Full Body Flow', - description: 'Smooth flowing full body movements', - exercises: [ - 'Squat to Stand to Reach', - 'Plank to Down Dog', - 'Lunge Flow Complex', - 'Push-up Walkout', - 'Glute Bridge Complex', - 'Bear Crawl', - 'Inchworm Push-up', - 'Flow Finisher', - ], - equipment: ['None'], - focus: ['Flow', 'Mobility', 'Integration'], - tips: [ - 'One smooth motion to next', - 'Connect your breath', - 'Enjoy the movement', - ], - }, - - // WEEK 3: Challenge - { - id: 'fb-w3-d1', - week: 3, - order: 1, - title: 'Challenge Complex 1', - description: 'High-intensity complex combining strength and cardio', - exercises: [ - 'Burpees', - 'Jump Squats', - 'Push-ups', - 'Mountain Climbers', - 'Reverse Lunges', - 'High Knees Sprint', - 'Plank Hold', - 'Recovery Breathing', - ], - equipment: ['None'], - focus: ['Complex Training', 'High Intensity', 'Challenge'], - tips: [ - 'This is challenging - pace yourself', - 'Maintain form as you fatigue', - 'Push through mentally!', - ], - }, - { - id: 'fb-w3-d2', - week: 3, - order: 2, - title: 'Challenge Complex 2', - description: 'Second high-intensity challenge workout', - exercises: [ - 'Jump Lunges', - 'Push-up T-Rotation', - 'Tuck Jumps', - 'Renegade Rows', - 'Broad Jumps', - 'Plank Jacks', - 'Speed Skaters', - 'Glute Bridge Hold', - ], - equipment: ['None'], - focus: ['Complex Training', 'Explosive Power', 'Endurance'], - tips: [ - 'Explosive and powerful', - 'Maximum effort each rep', - 'You\'re building serious fitness!', - ], - }, - { - id: 'fb-w3-d3', - week: 3, - order: 3, - title: 'Core Intensive', - description: 'Intense core-focused full body workout', - exercises: [ - 'Plank Hold Challenge', - 'Bicycle Crunches', - 'Side Plank Rotations L', - 'Side Plank Rotations R', - 'V-ups', - 'Plank to Push-up Fast', - 'Russian Twists', - 'Hollow Body Rocks', - ], - equipment: ['None'], - focus: ['Core Intensity', 'Abs', 'Stability'], - tips: [ - 'Feel the core burn', - 'Keep movements controlled', - 'This builds serious core strength', - ], - }, - { - id: 'fb-w3-d4', - week: 3, - order: 4, - title: 'Endurance Challenge', - description: 'Test your endurance with continuous work', - exercises: [ - 'Continuous Squats', - 'Push-up Challenge Set', - 'Lunge Walk', - 'Plank Challenge Hold', - 'High Knees Endurance', - 'Glute Bridge Burnout', - 'Mountain Climber Endurance', - 'Final Push Set', - ], - equipment: ['None'], - focus: ['Endurance', 'Mental Toughness', 'Stamina'], - tips: [ - 'Embrace the challenge', - 'Break mental barriers', - 'You\'re an endurance machine!', - ], - }, - { - id: 'fb-w3-d5', - week: 3, - order: 5, - title: 'Full Body Power Hour', - description: 'Maximum intensity full body challenge', - exercises: [ - 'Burpee Variations', - 'Jump Squat Variations', - 'Push-up Variations', - 'Lunge Variations', - 'Plank Variations', - 'Plyo Combinations', - 'Power Combinations', - 'Max Effort Finisher', - ], - equipment: ['None'], - focus: ['Maximum Intensity', 'Full Body Power', 'Challenge'], - tips: [ - 'Maximum effort everything', - 'Show your strength', - 'Beast mode activated!', - ], - }, - - // WEEK 4: Peak Performance - { - id: 'fb-w4-d1', - week: 4, - order: 1, - title: 'Peak Complex 1', - description: 'Peak performance full body complex', - exercises: [ - 'Explosive Burpees', - 'Power Squats', - 'Max Push-ups', - 'Speed Mountain Climbers', - 'Jump Lunges Power', - 'Sprint High Knees', - 'Plank Power Hold', - 'Recovery Set', - ], - equipment: ['None'], - focus: ['Peak Performance', 'Max Power', 'Elite Level'], - tips: [ - 'This is peak week!', - 'Maximum intensity always', - 'You\'ve earned this strength!', - ], - }, - { - id: 'fb-w4-d2', - week: 4, - order: 2, - title: 'Peak Complex 2', - description: 'Second peak performance challenge', - exercises: [ - 'Max Height Tuck Jumps', - 'Explosive Push-ups', - 'Power Lunges', - 'Broad Jumps Max', - 'Plyo Push-ups', - 'Lateral Bounds Power', - 'Burpee Tuck Jumps', - 'Power Finish', - ], - equipment: ['None'], - focus: ['Peak Power', 'Explosiveness', 'Athletic Peak'], - tips: [ - 'Maximum height and power', - 'Show your explosiveness', - 'You\'re an athlete!', - ], - }, - { - id: 'fb-w4-d3', - week: 4, - order: 3, - title: 'Peak Core Challenge', - description: 'Ultimate core strength challenge', - exercises: [ - 'Extended Plank Hold', - 'V-up Challenge', - 'Plank Complex L', - 'Plank Complex R', - 'Bicycle Crunch Challenge', - 'Hollow Body Challenge', - 'Russian Twist Challenge', - 'Core Victory Set', - ], - equipment: ['None'], - focus: ['Peak Core', 'Ultimate Challenge', 'Mastery'], - tips: [ - 'This is your core mastery test', - 'Show your stability', - 'You have a steel core!', - ], - }, - { - id: 'fb-w4-d4', - week: 4, - order: 4, - title: 'Peak Endurance', - description: 'Ultimate endurance and stamina test', - exercises: [ - 'Endurance Squat Challenge', - 'Endurance Push Challenge', - 'Endurance Lunge Challenge', - 'Endurance Plank Challenge', - 'Endurance Cardio Challenge', - 'Endurance Core Challenge', - 'Endurance Flow Challenge', - 'Victory Endurance Set', - ], - equipment: ['None'], - focus: ['Peak Endurance', 'Stamina Test', 'Mental Victory'], - tips: [ - 'This is the ultimate test', - 'Push beyond limits', - 'You\'re unstoppable!', - ], - }, - { - id: 'fb-w4-d5', - week: 4, - order: 5, - title: 'Full Body Final Challenge', - description: 'The ultimate celebration of your 4-week journey', - exercises: [ - 'Victory Complex 1: Foundation', - 'Victory Complex 2: Strength', - 'Victory Complex 3: Power', - 'Victory Complex 4: Endurance', - 'Victory Complex 5: Flow', - 'Victory Complex 6: Integration', - 'Victory Complex 7: Mastery', - 'Victory Lap: Celebration', - ], - equipment: ['None'], - focus: ['Ultimate Challenge', 'Journey Complete', 'Celebration'], - tips: [ - 'CELEBRATE YOUR JOURNEY!', - 'Showcase everything you learned', - 'You transformed in 4 weeks!', - ], - }, -] - -// ═══════════════════════════════════════════════════════════════════════════ -// ASSESSMENT WORKOUT -// ═══════════════════════════════════════════════════════════════════════════ - -export const ASSESSMENT_WORKOUT: Assessment = { - id: 'initial-assessment', - title: 'Movement Assessment', - description: 'A quick 4-minute check to understand your current movement patterns and recommend the best starting point.', - duration: 4, - exercises: [ - { - name: 'Squat Test', - duration: 20, - purpose: 'Check squat depth and form', - }, - { - name: 'Push-up Test', - duration: 20, - purpose: 'Assess upper body strength', - }, - { - name: 'Plank Test', - duration: 20, - purpose: 'Check core stability', - }, - { - name: 'Single Leg Balance L', - duration: 20, - purpose: 'Test balance and hip stability', - }, - { - name: 'Single Leg Balance R', - duration: 20, - purpose: 'Test balance and hip stability', - }, - { - name: 'Hip Hinge Test', - duration: 20, - purpose: 'Check posterior chain mobility', - }, - { - name: 'Overhead Reach', - duration: 20, - purpose: 'Assess shoulder mobility', - }, - { - name: 'Lunge Test', - duration: 20, - purpose: 'Check single leg strength', - }, - ], - tips: [ - 'Move at your own pace', - 'Focus on form, not speed', - 'This helps us recommend the best program', - 'No judgment - just a starting point!', - ], -} - -// ═══════════════════════════════════════════════════════════════════════════ -// PROGRAM BUILDER -// ═══════════════════════════════════════════════════════════════════════════ - -function buildProgramWorkouts(inputs: ProgramWorkoutInput[], category: WorkoutCategory): BuiltProgramWorkout[] { - return inputs.map((input) => ({ - ...input, - exercises: input.exercises.map((name) => - createExercise(name) - ), - duration: 4 as const, - // Workout-compatible fields so screens don't crash - level: getLevelFromWeek(input.week), - category, - trainerId: '', - calories: 50, - rounds: input.exercises.length, - prepTime: 10, - workTime: 20, - restTime: 10, - musicVibe: 'electronic' as MusicVibe, - isFeatured: false, - })) -} - -function buildWeeks(workouts: BuiltProgramWorkout[]): Week[] { - const weeks: Week[] = [] - - for (let weekNum = 1; weekNum <= 4; weekNum++) { - const weekWorkouts = workouts.filter((w) => w.week === weekNum) - - weeks.push({ - weekNumber: weekNum as WeekNumber, - title: getWeekTitle(weekNum), - description: getWeekDescription(weekNum), - focus: getWeekFocus(weekNum), - workouts: weekWorkouts.sort((a, b) => a.order - b.order), - }) - } - - return weeks -} - -function getWeekTitle(week: number): string { - switch (week) { - case 1: - return 'Foundation' - case 2: - return 'Building' - case 3: - return 'Challenge' - case 4: - return 'Peak Performance' - default: - return `Week ${week}` - } -} - -function getWeekDescription(week: number): string { - switch (week) { - case 1: - return 'Master the fundamentals with perfect form' - case 2: - return 'Build strength and increase intensity' - case 3: - return 'Push your limits with challenging workouts' - case 4: - return 'Achieve peak performance and celebrate your progress' - default: - return `Week ${week} of your journey` - } -} - -function getWeekFocus(week: number): string { - switch (week) { - case 1: - return 'Form & Foundation' - case 2: - return 'Strength Building' - case 3: - return 'Intensity & Challenge' - case 4: - return 'Peak Performance' - default: - return 'General Fitness' - } -} - -// ═══════════════════════════════════════════════════════════════════════════ -// EXPORT PROGRAMS -// ═══════════════════════════════════════════════════════════════════════════ - -export const PROGRAMS: Record = { - 'upper-body': { - id: 'upper-body', - title: 'Upper Body', - description: 'Build strong shoulders, chest, back, and arms with physiotherapist-designed progressions', - durationWeeks: 4, - workoutsPerWeek: 5, - totalWorkouts: 20, - equipment: { - required: ['Resistance band'], - optional: ['Wall', 'Elevated surface'], - }, - focusAreas: ['Shoulders', 'Chest', 'Back', 'Arms', 'Posture'], - weeks: buildWeeks(buildProgramWorkouts(upperBodyWorkouts, 'upper-body')), - }, - 'lower-body': { - id: 'lower-body', - title: 'Lower Body', - description: 'Develop powerful legs, glutes, and hips with joint-friendly movements', - durationWeeks: 4, - workoutsPerWeek: 5, - totalWorkouts: 20, - equipment: { - required: ['Resistance band'], - optional: ['Step or bench', 'Wall'], - }, - focusAreas: ['Legs', 'Glutes', 'Hips', 'Calves', 'Knee Health'], - weeks: buildWeeks(buildProgramWorkouts(lowerBodyWorkouts, 'lower-body')), - }, - 'full-body': { - id: 'full-body', - title: 'Full Body', - description: 'Complete total body transformation using only your bodyweight', - durationWeeks: 4, - workoutsPerWeek: 5, - totalWorkouts: 20, - equipment: { - required: [], - optional: ['Wall', 'Elevated surface'], - }, - focusAreas: ['Total Body', 'Core', 'Cardio', 'Functional Fitness'], - weeks: buildWeeks(buildProgramWorkouts(fullBodyWorkouts, 'full-body')), - }, -} - -// Export individual arrays for convenience -export const UPPER_BODY_WORKOUTS = buildProgramWorkouts(upperBodyWorkouts, 'upper-body') -export const LOWER_BODY_WORKOUTS = buildProgramWorkouts(lowerBodyWorkouts, 'lower-body') -export const FULL_BODY_WORKOUTS = buildProgramWorkouts(fullBodyWorkouts, 'full-body') - -// Export all workouts as flat array for player compatibility -export const ALL_PROGRAM_WORKOUTS = [ - ...UPPER_BODY_WORKOUTS, - ...LOWER_BODY_WORKOUTS, - ...FULL_BODY_WORKOUTS, -] - -export { upperBodyWorkouts, lowerBodyWorkouts, fullBodyWorkouts } diff --git a/src/shared/data/tabata/CLAUDE.md b/src/shared/data/tabata/CLAUDE.md deleted file mode 100644 index f4a7bc1..0000000 --- a/src/shared/data/tabata/CLAUDE.md +++ /dev/null @@ -1,19 +0,0 @@ - -# Recent Activity - - - -### Apr 9, 2026 - -| ID | Time | T | Title | Read | -|----|------|---|-------|------| -| #5988 | 10:14 AM | 🔴 | Fixed forward reference error in Avancé program | ~277 | -| #5986 | 10:12 AM | 🟣 | Advanced Kine program registered and exported in data layer | ~345 | -| #5981 | 9:56 AM | 🟣 | Bureau program registered in kiné data layer | ~309 | - -### Apr 11, 2026 - -| ID | Time | T | Title | Read | -|----|------|---|-------|------| -| #6144 | 7:45 PM | 🔵 | Intermediaire Kine program metadata structure | ~268 | - \ No newline at end of file diff --git a/src/shared/data/tabata/avance.ts b/src/shared/data/tabata/avance.ts deleted file mode 100644 index 69bfb32..0000000 --- a/src/shared/data/tabata/avance.ts +++ /dev/null @@ -1,315 +0,0 @@ -/** - * Programme Avancé — 4 semaines, 5 séances/semaine - * Source: TabataKine_Guide_Complet.md — Section 4 - * Tier: PREMIUM - */ - -import type { TabataProgram, TabataSession, TabataWeek, TabataBlock, TabataExercise, WarmupPhase, CooldownPhase } from '../../types/program' - -const ex = (name: string, nameEn: string, conseil: string, conseilEn: string): TabataExercise => ({ name, nameEn, conseil, conseilEn }) -const block = (id: string, odd: TabataExercise, even: TabataExercise, rounds = 8, workTime = 20, restTime = 10): TabataBlock => ({ id, oddExercise: odd, evenExercise: even, rounds, workTime, restTime }) - -// ─── Warmup / Cooldown Archetypes (from Guide Section 4) ──────── - -const WARMUP_LEGS: WarmupPhase = { - movements: [ - { name: 'Jogging sur place progressif', nameEn: 'Progressive Jogging in Place', duration: 60 }, - { name: 'Leg swings dynamiques avant/arrière et latéraux', nameEn: 'Dynamic Leg Swings Front/Back and Lateral', duration: 60 }, - { name: 'Fentes dynamiques avec rotation du tronc', nameEn: 'Dynamic Lunges with Torso Rotation', duration: 60 }, - { name: 'Squat profond maintenu 3 sec', nameEn: 'Deep Squat Hold 3 Sec', duration: 60 }, - { name: 'Sauts bas rapides à deux pieds', nameEn: 'Low Rapid Two-foot Jumps', duration: 60 }, - { name: 'Clamshells rapides debout', nameEn: 'Fast Standing Clamshells', duration: 60 }, - ], - totalDuration: 360, -} - -const COOLDOWN_LEGS: CooldownPhase = { - movements: [ - { name: 'Étirement ischio-jambiers dynamique puis statique', nameEn: 'Dynamic to Static Hamstring Stretch', duration: 90 }, - { name: 'Étirement quadriceps debout chaque jambe', nameEn: 'Standing Quad Stretch Each Leg', duration: 90 }, - { name: 'Automassage mollets', nameEn: 'Self-massage Calves', duration: 60 }, - { name: 'Respiration guidée récupération', nameEn: 'Guided Recovery Breathing', duration: 60 }, - ], - totalDuration: 300, -} - -const WARMUP_UPPER: WarmupPhase = { - movements: [ - { name: 'Cercles d\'épaules complets avec résistance', nameEn: 'Full Shoulder Circles with Resistance', duration: 60 }, - { name: 'Face pulls avec élastique', nameEn: 'Face Pulls with Band', duration: 60 }, - { name: 'Pompes lentes descente 4 secondes', nameEn: 'Slow Push-ups 4-sec Descent', duration: 60 }, - { name: 'Dips lents sur chaise', nameEn: 'Slow Chair Dips', duration: 60 }, - { name: 'Planche dynamique haute↔basse', nameEn: 'Dynamic High↔Low Plank', duration: 60 }, - { name: 'Rotation thoracique en fente basse', nameEn: 'Thoracic Rotation in Lunge', duration: 60 }, - ], - totalDuration: 360, -} - -const COOLDOWN_UPPER: CooldownPhase = { - movements: [ - { name: 'Étirement rotateurs externes épaule contre mur', nameEn: 'Wall External Rotator Stretch', duration: 60 }, - { name: 'Mobilisation thoracique sur rouleau', nameEn: 'Thoracic Foam Roller Mobilization', duration: 90 }, - { name: 'Étirement grand pectoral profond', nameEn: 'Deep Pectoral Stretch', duration: 60 }, - { name: 'Respiration guidée récupération', nameEn: 'Guided Recovery Breathing', duration: 60 }, - ], - totalDuration: 270, -} - -const WARMUP_FULL_BODY: WarmupPhase = { - movements: [ - { name: 'Mountain climbers modérés', nameEn: 'Moderate Mountain Climbers', duration: 60 }, - { name: 'Squat jump amplitude partielle', nameEn: 'Partial Range Squat Jumps', duration: 60 }, - { name: 'Burpees sans saut (sprawl)', nameEn: 'No-jump Burpees (Sprawls)', duration: 60 }, - { name: 'High knees progressif', nameEn: 'Progressive High Knees', duration: 60 }, - { name: 'Mobilisation chevilles et poignets', nameEn: 'Ankle and Wrist Mobility', duration: 60 }, - { name: 'Hollow body hold 5 secondes x5', nameEn: 'Hollow Body Hold 5 Sec x5', duration: 60 }, - ], - totalDuration: 360, -} - -const COOLDOWN_FULL_BODY: CooldownPhase = { - movements: [ - { name: 'Foam roller colonne vertébrale', nameEn: 'Spinal Foam Rolling', duration: 90 }, - { name: 'Supine twist chaque côté', nameEn: 'Supine Twist Each Side', duration: 90 }, - { name: 'Respiration 4-7-8 × 4 cycles', nameEn: '4-7-8 Breathing × 4 Cycles', duration: 90 }, - { name: 'Relaxation guidée', nameEn: 'Guided Relaxation', duration: 60 }, - ], - totalDuration: 330, -} - -const WARMUP_CORE: WarmupPhase = { - movements: [ - { name: 'Respiration diaphragmatique', nameEn: 'Diaphragmatic Breathing', duration: 60 }, - { name: 'Cat-cow dynamique', nameEn: 'Dynamic Cat-Cow', duration: 60 }, - { name: 'Rotations bassin debout', nameEn: 'Standing Pelvic Rotations', duration: 60 }, - { name: 'Hollow body progressif 5×10 sec', nameEn: 'Progressive Hollow Body 5×10 Sec', duration: 60 }, - { name: 'Brettzel rotation thoracique', nameEn: 'Brettzel Thoracic Rotation', duration: 60 }, - { name: 'Squat profond asiatique', nameEn: 'Deep Asian Squat', duration: 60 }, - ], - totalDuration: 360, -} - -const COOLDOWN_CORE: CooldownPhase = { - movements: [ - { name: 'Posture de l\'enfant', nameEn: 'Child\'s Pose', duration: 60 }, - { name: 'Torsion vertébrale au sol chaque côté', nameEn: 'Spinal Twist Each Side', duration: 60 }, - { name: 'Étirement cobra', nameEn: 'Cobra Stretch', duration: 60 }, - { name: 'Respiration diaphragmatique finale', nameEn: 'Final Diaphragmatic Breathing', duration: 60 }, - ], - totalDuration: 240, -} - -const ses = (id: string, week: number, order: number, title: string, titleEn: string, desc: string, descEn: string, focus: string[], focusEn: string[], blocks: TabataBlock[], totalRounds: number, totalDuration: number, calories: number, warmup: WarmupPhase, cooldown: CooldownPhase, eq: string[] = []): TabataSession => ({ - id, week, order, title, titleEn, description: desc, descriptionEn: descEn, focus, focusEn, - warmup, blocks, cooldown, - equipment: eq, totalRounds, totalDuration, calories, -}) - -const SQUAT_JUMP_180 = ex('Squat jump 180°', '180° Squat Jump', 'Réception en rotation sollicite fortement le LCA. Antécédent de genou = rester au squat jump classique.', 'Rotational landing stresses ACL heavily. Knee history = stick to regular squat jump.') -const FENTE_SAUTEE_EX = ex('Fente sautée', 'Jump Lunge', 'Réception absorbée sur 2–3 secondes.', 'Absorb landing over 2–3 seconds.') -const PISTOL_FULL = ex('Pistol squat complet', 'Full Pistol Squat', 'Talon qui se soulève = manque de mobilité de cheville. Tronc qui bascule = faiblesse du moyen fessier.', 'Heel lifting = ankle mobility deficit. Torso tilting = gluteus medius weakness.') -const NORDIC_CURL = ex('Nordic curl assisté', 'Assisted Nordic Curl', 'Cliniquement prouvé pour réduire les blessures ischio-jambiers de 50%. Même 3–4 reps contrôlées sont excellentes.', 'Clinically proven to reduce hamstring injuries by 50%. Even 3-4 controlled reps are excellent.') -const BOX_JUMP = ex('Box jump', 'Box Jump', 'Descendre en marchant — ne pas sauter en arrière. Sauter en arrière multiplie les contraintes articulaires.', 'Step down — never jump backward. Jumping down multiplies joint stress.') -const LATERAL_BOUND = ex('Lateral bound', 'Lateral Bound', 'Exercice de prévention des entorses par renforcement proprioceptif.', 'Sprain prevention exercise via proprioceptive strengthening.') -const BROAD_JUMP = ex('Broad jump + recul', 'Broad Jump + Return', 'Le recul contrôlé renforce les stabilisateurs de cheville sous fatigue.', 'Controlled return strengthens ankle stabilizers under fatigue.') -const SINGLE_LEG_DL = ex('Single leg deadlift', 'Single-leg Deadlift', 'Exercice fondamental de proprioception. Qualité > profondeur.', 'Fundamental proprioception exercise. Quality > depth.') -const ONE_ARM_PUSHUP = ex('Pompe 1 bras assistée', 'Assisted One-arm Push-up', 'L\'asymétrie révèle les faiblesses de stabilisation scapulaire.', 'Asymmetry reveals scapular stabilization weaknesses.') -const PIKE_PUSHUP = ex('Pike push-up', 'Pike Push-up', 'Simule le développé épaules. Contre-indiqué si syndrome d\'accrochage sous-acromial.', 'Simulates overhead press. Contraindicated with subacromial impingement.') -const PLYO_PUSHUP = ex('Pompe plyométrique', 'Plyometric Push-up', 'Poignets en parfait alignement — échauffement spécifique non négociable.', 'Perfect wrist alignment — specific warmup non-negotiable.') -const AROUND_WORLD = ex('Around the world planche', 'Around the World Plank', 'Ultra-exigeant pour les rotateurs de l\'épaule et les dentelés antérieurs.', 'Ultra-demanding for shoulder rotators and serratus anterior.') -const ARCHER_FULL = ex('Archer push-up complet', 'Full Archer Push-up', 'Maintenir l\'alignement corps-bras porteur parfait.', 'Maintain perfect body-supporting arm alignment.') -const SIDE_PLANK_ROT = ex('Planche latérale rotation', 'Side Plank with Rotation', 'Sollicite obliques, carré des lombes et rotateurs d\'épaule simultanément.', 'Targets obliques, quadratus lumborum and shoulder rotators simultaneously.') -const PSEUDO_PLANCHE = ex('Pseudo planche push-up', 'Pseudo Planche Push-up', 'Charge extrême sur les triceps et pectoraux inférieurs.', 'Extreme load on triceps and lower pectorals.') -const SUPERMAN_BEAT = ex('Superman battement', 'Superman Flutter', 'Travail des extenseurs dorsaux sous fatigue.', 'Thoracic extensor work under fatigue.') -const BURPEE_TUCK = ex('Burpee saut groupé', 'Tuck Jump Burpee', 'Atterrir genoux fléchis, jamais en extension. Charge lombaire à la réception.', 'Land with bent knees, never extended. Lumbar load on landing.') -const V_UP = ex('V-up', 'V-up', 'Si douleur au bas du dos : revenir au hollow body.', 'If lower back pain: return to hollow body.') -const TUCK_JUMP = ex('Tuck jump', 'Tuck Jump', 'Si syndrome essuie-glace (IT band) : substituer par jumping squats.', 'If IT band syndrome: substitute with jumping squats.') -const MC_CROISE = ex('Mountain climber croisé', 'Cross-body Mountain Climber', 'Plus difficile que le MC classique car la rotation engage les obliques.', 'Harder than regular MC as rotation engages obliques.') -const DEVILS_PRESS = ex('Devil\'s press poids de corps', 'Bodyweight Devil\'s Press', 'Enchaînement fluide entre les phases. Pas de pause entre le grenouille et le relever.', 'Fluid transition between phases. No pause between frog and stand.') -const BEAR_CRAWL_DEPL = ex('Bear crawl en déplacement', 'Traveling Bear Crawl', 'Gainage parfait malgré la vitesse. Genoux à 3 cm du sol.', 'Perfect core despite speed. Knees 3cm off floor.') -const SPRAWL = ex('Sprawl', 'Sprawl', 'La projection vers le bas doit être contrôlée — ne jamais s\'écraser.', 'Downward projection must be controlled — never crash.') -const HOLLOW_ROCK = ex('Hollow body rocks', 'Hollow Body Rocks', 'Continuité du gainage pendant le balancement est l\'objectif.', 'Core continuity during rocking is the goal.') -const HANDSTAND_PU = ex('Handstand push-up mur', 'Wall Handstand Push-up', 'Vérifier l\'absence de douleur cervicale. Ne jamais toucher le sol avec force.', 'Verify no cervical pain. Never forcefully touch floor.') -const SINGLE_LEG_BURPEE = ex('Single leg burpee', 'Single-leg Burpee', 'Test ultime de force, coordination et proprioception.', 'Ultimate test of strength, coordination and proprioception.') -const DRAGON_FLAG = ex('Dragon flag partiel', 'Partial Dragon Flag', 'Ne jamais forcer si douleur lombaire. L\'exercice de Bruce Lee.', 'Never force with lower back pain. Bruce Lee\'s exercise.') -const COPENHAGEN = ex('Copenhagen plank', 'Copenhagen Plank', 'Prévention des adducteurs la plus efficace existante.', 'Most effective adductor prevention exercise in existence.') -const BURPEE_LATERAL = ex('Burpee + saut latéral', 'Burpee + Lateral Jump', 'Augmente l\'impact cardiovasculaire et la coordination.', 'Increases cardiovascular impact and coordination.') - -// ─── Week 1: Bascule vers la complexité (4 blocs, 5 sessions) ── - -const w1: TabataWeek = { - weekNumber: 1, title: 'Bascule vers la complexité', titleEn: 'Shift to Complexity', - description: '4 blocs/séance, ~45 min. Mouvements unilatéraux + plyométrie avancée.', - descriptionEn: '4 blocks/session, ~45 min. Unilateral movements + advanced plyometrics.', - focus: 'Mouvements complexes sous fatigue, unilatéral systématique', focusEn: 'Complex movements under fatigue, systematic unilateral work', isDeload: false, - sessions: [ - ses('avc-w1-s1', 1, 1, 'Jambes explosifs', 'Explosive Legs', 'Squat 180°, pistol squat, Nordic curl, box jump.', '180° squat, pistol squat, Nordic curl, box jump.', - ['Puissance', 'Unilatéral', 'Plyométrie'], ['Power', 'Unilateral', 'Plyometrics'], - [block('avc-w1-s1-b1', SQUAT_JUMP_180, PISTOL_FULL), block('avc-w1-s1-b2', NORDIC_CURL, LATERAL_BOUND), block('avc-w1-s1-b3', BOX_JUMP, SINGLE_LEG_DL), block('avc-w1-s1-b4', BROAD_JUMP, SUPERMAN_BEAT)], - 32, 45, 200, WARMUP_LEGS, COOLDOWN_LEGS, ['Surface surélevée stable']), - ses('avc-w1-s2', 1, 2, 'Haut athlétique', 'Athletic Upper Body', 'Pompe 1 bras, pike push-up, pompe plyo, archer.', - 'One-arm push-up, pike push-up, plyo push-up, archer.', - ['Force', 'Stabilité scapulaire'], ['Strength', 'Scapular Stability'], - [block('avc-w1-s2-b1', ONE_ARM_PUSHUP, PIKE_PUSHUP), block('avc-w1-s2-b2', PLYO_PUSHUP, AROUND_WORLD), block('avc-w1-s3-b3', ARCHER_FULL, SIDE_PLANK_ROT), block('avc-w1-s2-b4', PSEUDO_PLANCHE, SUPERMAN_BEAT)], - 32, 45, 185, WARMUP_UPPER, COOLDOWN_UPPER), - ses('avc-w1-s3', 1, 3, 'Corps entier HIIT', 'Full Body HIIT', 'Burpee groupé, V-up, tuck jump, MC croisé.', - 'Tuck burpee, V-up, tuck jump, cross-body MC.', - ['Cardio max', 'Composé'], ['Max Cardio', 'Compound'], - [block('avc-w1-s3-b1', BURPEE_TUCK, V_UP), block('avc-w1-s3-b2', TUCK_JUMP, MC_CROISE), block('avc-w1-s3-b3', DEVILS_PRESS, BEAR_CRAWL_DEPL), block('avc-w1-s3-b4', SPRAWL, HOLLOW_ROCK)], - 32, 45, 210, WARMUP_FULL_BODY, COOLDOWN_FULL_BODY), - ses('avc-w1-s4', 1, 4, 'Gainage profond + mobilité', 'Deep Core + Mobility', 'Hollow body, Copenhagen, 90/90, Brettzel.', - 'Hollow body, Copenhagen, 90/90, Brettzel.', - ['Gainage', 'Mobilité', 'Récupération'], ['Core', 'Mobility', 'Recovery'], - [], 0, 35, 50, WARMUP_CORE, COOLDOWN_CORE), - ses('avc-w1-s5', 1, 5, 'MetCon 20 min AMRAP', '20-min AMRAP MetCon', '5 burpees, 10 squat jumps, 10 MC croisés, 5 pompes explosives, 10 V-ups en boucle.', - '5 burpees, 10 squat jumps, 10 cross-body MC, 5 explosive push-ups, 10 V-ups on loop.', - ['Endurance de force', 'MetCon'], ['Strength Endurance', 'MetCon'], - [block('avc-w1-s5-b1', BURPEE_TUCK, SQUAT_JUMP_180), block('avc-w1-s5-b2', MC_CROISE, PLYO_PUSHUP), block('avc-w1-s5-b3', V_UP, HOLLOW_ROCK), block('avc-w1-s5-b4', TUCK_JUMP, SPRAWL)], - 32, 20, 150, WARMUP_FULL_BODY, COOLDOWN_FULL_BODY), - ], -} - -// ─── Week 2: Densification (5 blocs, 5 sessions) ───────────── - -const w2: TabataWeek = { - weekNumber: 2, title: 'Densification', titleEn: 'Densification', - description: '5 blocs/séance, ~50 min. Handstand push-up, single leg burpee, dragon flag.', - descriptionEn: '5 blocks/session, ~50 min. Handstand push-up, single-leg burpee, dragon flag.', - focus: 'Nouveaux mouvements très avancés, volume maximal', focusEn: 'Very advanced new movements, max volume', isDeload: false, - sessions: [ - ses('avc-w2-s1', 2, 1, 'Jambes puissance max', 'Max Leg Power', 'Pistol + box jump + Nordic + lateral bound + broad jump.', - 'Pistol + box jump + Nordic + lateral bound + broad jump.', - ['Puissance', 'Explosivité'], ['Power', 'Explosiveness'], - [block('avc-w2-s1-b1', PISTOL_FULL, NORDIC_CURL), block('avc-w2-s1-b2', BOX_JUMP, LATERAL_BOUND), block('avc-w2-s1-b3', BROAD_JUMP, SINGLE_LEG_DL), block('avc-w2-s1-b4', SQUAT_JUMP_180, SUPERMAN_BEAT), block('avc-w2-s1-b5', SINGLE_LEG_BURPEE, HOLLOW_ROCK)], - 40, 50, 250, WARMUP_LEGS, COOLDOWN_LEGS, ['Surface surélevée']), - ses('avc-w2-s2', 2, 2, 'Haut force max', 'Max Upper Strength', 'Handstand PU + archer + plyo + pseudo planche + side plank.', - 'Handstand PU + archer + plyo + pseudo planche + side plank.', - ['Force maximale', 'Épaules'], ['Max Strength', 'Shoulders'], - [block('avc-w2-s2-b1', HANDSTAND_PU, PIKE_PUSHUP), block('avc-w2-s2-b2', ARCHER_FULL, ONE_ARM_PUSHUP), block('avc-w2-s2-b3', PLYO_PUSHUP, AROUND_WORLD), block('avc-w2-s2-b4', PSEUDO_PLANCHE, SIDE_PLANK_ROT), block('avc-w2-s2-b5', DRAGON_FLAG, SUPERMAN_BEAT)], - 40, 50, 230, WARMUP_UPPER, COOLDOWN_UPPER), - ses('avc-w2-s3', 2, 3, 'Cardio avancé', 'Advanced Cardio', 'Single leg burpee + tuck jump + devil\'s press + sprawl + bear crawl.', - 'Single-leg burpee + tuck jump + devil\'s press + sprawl + bear crawl.', - ['Cardio extrême', 'Endurance'], ['Extreme Cardio', 'Endurance'], - [block('avc-w2-s3-b1', SINGLE_LEG_BURPEE, MC_CROISE), block('avc-w2-s3-b2', TUCK_JUMP, DEVILS_PRESS), block('avc-w2-s3-b3', SPRAWL, BEAR_CRAWL_DEPL), block('avc-w2-s3-b4', BURPEE_TUCK, V_UP), block('avc-w2-s3-b5', HOLLOW_ROCK, SQUAT_JUMP_180)], - 40, 50, 260, WARMUP_FULL_BODY, COOLDOWN_FULL_BODY), - ses('avc-w2-s4', 2, 4, 'Gainage avancé', 'Advanced Core', 'Dragon flag + Copenhagen + hollow body + V-up + pseudo planche.', - 'Dragon flag + Copenhagen + hollow body + V-up + pseudo planche.', - ['Gainage profond', 'Stabilité'], ['Deep Core', 'Stability'], - [block('avc-w2-s4-b1', DRAGON_FLAG, COPENHAGEN), block('avc-w2-s4-b2', HOLLOW_ROCK, V_UP), block('avc-w2-s4-b3', SIDE_PLANK_ROT, ARCHER_FULL), block('avc-w2-s4-b4', PSEUDO_PLANCHE, SUPERMAN_BEAT), block('avc-w2-s4-b5', NORDIC_CURL, HOLLOW_ROCK)], - 40, 50, 220, WARMUP_CORE, COOLDOWN_CORE), - ses('avc-w2-s5', 2, 5, 'Mix force + puissance', 'Strength + Power Mix', 'Pistol + handstand PU + single leg burpee + plyo push-up + broad jump.', - 'Pistol + handstand PU + single-leg burpee + plyo push-up + broad jump.', - ['Force + puissance'], ['Strength + power'], - [block('avc-w2-s5-b1', PISTOL_FULL, HANDSTAND_PU), block('avc-w2-s5-b2', SINGLE_LEG_BURPEE, PLYO_PUSHUP), block('avc-w2-s5-b3', BROAD_JUMP, DRAGON_FLAG), block('avc-w2-s5-b4', ARCHER_FULL, V_UP), block('avc-w2-s5-b5', SQUAT_JUMP_180, HOLLOW_ROCK)], - 40, 50, 255, WARMUP_FULL_BODY, COOLDOWN_FULL_BODY), - ], -} - -// ─── Week 3: Pic d'intensité + Complexes (5 blocs) ─────────── - -const w3: TabataWeek = { - weekNumber: 3, title: 'Pic d\'intensité & Complexes', titleEn: 'Peak Intensity & Complexes', - description: '5 blocs + complexes. 2 exercices enchaînés sans pause = 1 répétition.', - descriptionEn: '5 blocks + complexes. 2 exercises chained without rest = 1 rep.', - focus: 'Complexes, intensité maximale', focusEn: 'Complexes, maximum intensity', isDeload: false, - sessions: [ - ses('avc-w3-s1', 3, 1, 'Complexes jambes', 'Lower Body Complexes', 'Squat jump+fente sautée, pistol+Nordic, box+jump lateral.', - 'Squat jump+jump lunge, pistol+Nordic, box+lateral jump.', - ['Complexes', 'Puissance'], ['Complexes', 'Power'], - [block('avc-w3-s1-b1', SQUAT_JUMP_180, FENTE_SAUTEE_EX), block('avc-w3-s1-b2', PISTOL_FULL, NORDIC_CURL), block('avc-w3-s1-b3', BOX_JUMP, LATERAL_BOUND), block('avc-w3-s1-b4', BROAD_JUMP, SINGLE_LEG_DL), block('avc-w3-s1-b5', SINGLE_LEG_BURPEE, HOLLOW_ROCK)], - 40, 50, 265, WARMUP_LEGS, COOLDOWN_LEGS, ['Surface surélevée']), - ses('avc-w3-s2', 3, 2, 'Complexes haut', 'Upper Body Complexes', 'Pompe plyo+MC croisé, archer+side plank, handstand+pike.', - 'Plyo push-up+cross MC, archer+side plank, handstand+pike.', - ['Complexes', 'Force'], ['Complexes', 'Strength'], - [block('avc-w3-s2-b1', PLYO_PUSHUP, MC_CROISE), block('avc-w3-s2-b2', ARCHER_FULL, SIDE_PLANK_ROT), block('avc-w3-s2-b3', HANDSTAND_PU, PIKE_PUSHUP), block('avc-w3-s2-b4', ONE_ARM_PUSHUP, DRAGON_FLAG), block('avc-w3-s2-b5', PSEUDO_PLANCHE, SUPERMAN_BEAT)], - 40, 50, 245, WARMUP_UPPER, COOLDOWN_UPPER), - ses('avc-w3-s3', 3, 3, 'Complexes corps entier', 'Full Body Complexes', 'Burpee+broad jump, sprawl+tuck jump, devil\'s press+V-up.', - 'Burpee+broad jump, sprawl+tuck jump, devil\'s press+V-up.', - ['Complexes', 'Cardio max'], ['Complexes', 'Max cardio'], - [block('avc-w3-s3-b1', BURPEE_LATERAL, BROAD_JUMP), block('avc-w3-s3-b2', SPRAWL, TUCK_JUMP), block('avc-w3-s3-b3', DEVILS_PRESS, V_UP), block('avc-w3-s3-b4', BEAR_CRAWL_DEPL, HOLLOW_ROCK), block('avc-w3-s3-b5', SINGLE_LEG_BURPEE, SQUAT_JUMP_180)], - 40, 50, 275, WARMUP_FULL_BODY, COOLDOWN_FULL_BODY), - ses('avc-w3-s4', 3, 4, 'Gainage + MetCon', 'Core + MetCon', 'Copenhagen+dragon flag, puis circuit rapide.', - 'Copenhagen+dragon flag, then fast circuit.', - ['Gainage', 'MetCon'], ['Core', 'MetCon'], - [block('avc-w3-s4-b1', COPENHAGEN, DRAGON_FLAG), block('avc-w3-s4-b2', HOLLOW_ROCK, V_UP), block('avc-w3-s4-b3', BURPEE_TUCK, MC_CROISE), block('avc-w3-s4-b4', TUCK_JUMP, PLYO_PUSHUP), block('avc-w3-s4-b5', SPRAWL, NORDIC_CURL)], - 40, 50, 250, WARMUP_CORE, COOLDOWN_CORE), - ses('avc-w3-s5', 3, 5, 'MetCon étendu 25 min', 'Extended 25-min MetCon', 'Circuit maximaliste en continu pendant 25 minutes.', - 'Maximalist continuous circuit for 25 minutes.', - ['Endurance maximale'], ['Maximum endurance'], - [block('avc-w3-s5-b1', BURPEE_LATERAL, SQUAT_JUMP_180), block('avc-w3-s5-b2', PLYO_PUSHUP, MC_CROISE), block('avc-w3-s5-b3', BROAD_JUMP, V_UP), block('avc-w3-s5-b4', SINGLE_LEG_BURPEE, HOLLOW_ROCK), block('avc-w3-s5-b5', SPRAWL, TUCK_JUMP)], - 40, 25, 170, WARMUP_FULL_BODY, COOLDOWN_FULL_BODY), - ], -} - -// ─── Week 4: Décharge & tests (3 blocs, 5 sessions) ────────── - -const w4: TabataWeek = { - weekNumber: 4, title: 'Décharge & Tests finaux', titleEn: 'Deload & Final Tests', - description: '3 blocs/séance. Exercices maîtrisés, focus technique. Tests de performance.', - descriptionEn: '3 blocks/session. Mastered exercises, technique focus. Performance tests.', - focus: 'Bilan, tests de performance, récupération', focusEn: 'Assessment, performance tests, recovery', isDeload: true, - sessions: [ - ses('avc-w4-s1', 4, 1, 'Jambes bilan', 'Leg Assessment', 'Squat jump, pistol squat, box jump — qualité max.', - 'Squat jump, pistol squat, box jump — max quality.', - ['Bilan jambes'], ['Leg assessment'], - [block('avc-w4-s1-b1', SQUAT_JUMP_180, PISTOL_FULL), block('avc-w4-s1-b2', BOX_JUMP, NORDIC_CURL), block('avc-w4-s1-b3', SINGLE_LEG_DL, SUPERMAN_BEAT)], - 24, 35, 170, WARMUP_LEGS, COOLDOWN_LEGS, ['Surface surélevée']), - ses('avc-w4-s2', 4, 2, 'Haut bilan', 'Upper Assessment', 'Archer, handstand PU, plyo — qualité max.', - 'Archer, handstand PU, plyo — max quality.', - ['Bilan haut du corps'], ['Upper body assessment'], - [block('avc-w4-s2-b1', ARCHER_FULL, HANDSTAND_PU), block('avc-w4-s2-b2', PLYO_PUSHUP, SIDE_PLANK_ROT), block('avc-w4-s2-b3', ONE_ARM_PUSHUP, DRAGON_FLAG)], - 24, 35, 155, WARMUP_UPPER, COOLDOWN_UPPER), - ses('avc-w4-s3', 4, 3, 'Cardio bilan', 'Cardio Assessment', 'Burpee endurance 3 min + sprint.', - 'Burpee endurance 3 min + sprint.', - ['Bilan cardio'], ['Cardio assessment'], - [block('avc-w4-s3-b1', BURPEE_TUCK, MC_CROISE), block('avc-w4-s3-b2', TUCK_JUMP, BEAR_CRAWL_DEPL), block('avc-w4-s3-b3', SPRAWL, HOLLOW_ROCK)], - 24, 35, 180, WARMUP_FULL_BODY, COOLDOWN_FULL_BODY), - ses('avc-w4-s4', 4, 4, 'Mobilité finale', 'Final Mobility', 'Stretching complet, mobilité articulaire, respiration.', - 'Full stretching, joint mobility, breathing.', - ['Récupération', 'Mobilité'], ['Recovery', 'Mobility'], - [], 0, 30, 40, WARMUP_CORE, COOLDOWN_CORE), - ses('avc-w4-s5', 4, 5, 'Bilan global', 'Overall Assessment', 'Tests finaux: burpees 3min, pistol G/D, broad jump, planche+MC 2min.', - 'Final tests: 3-min burpees, L/R pistol, broad jump, plank+MC 2min.', - ['Tests de passage'], ['Passing tests'], - [block('avc-w4-s5-b1', PISTOL_FULL, HOLLOW_ROCK), block('avc-w4-s5-b2', BURPEE_TUCK, BROAD_JUMP), block('avc-w4-s5-b3', ARCHER_FULL, COPENHAGEN)], - 24, 35, 165, WARMUP_FULL_BODY, COOLDOWN_FULL_BODY), - ], -} - -export const AVANCE_PROGRAM: TabataProgram = { - id: 'avance', title: 'Avancé', titleEn: 'Advanced', - description: 'Mouvements complexes sous fatigue, travail unilatéral systématique, préparation physique de haut niveau.', - descriptionEn: 'Complex movements under fatigue, systematic unilateral work, high-level physical preparation.', - tier: 'premium', accentColor: '#FF453A', icon: 'bolt', - durationWeeks: 4, sessionsPerWeek: 5, totalSessions: 20, - equipment: { required: [], optional: ['Surface surélevée stable', 'Mur'] }, - focusAreas: ['Plyométrie avancée', 'Unilatéral', 'Complexes', 'MetCon'], - focusAreasEn: ['Advanced Plyometrics', 'Unilateral', 'Complexes', 'MetCon'], - principles: [ - 'Si technique s\'effondre round 5 : réduire à exercice seul', - 'Fatigue neurologique = réduire d\'une séance', - 'JAMAQUE sacrifier la technique sous fatigue', - ], - principlesEn: [ - 'If technique collapses at round 5: reduce to single exercise', - 'Neurological fatigue = reduce by one session', - 'NEVER sacrifice technique under fatigue', - ], - completionCriteria: [ - '35+ burpees en 3 minutes', - '5 pistol squats propres G et D', - 'Planche + MC croisé 2 minutes', - 'Broad jump progression vs test intermédiaire', - 'Asymétrie G/D < 20% partout', - ], - completionCriteriaEn: [ - '35+ burpees in 3 minutes', - '5 clean pistol squats L and R', - 'Plank + cross MC for 2 minutes', - 'Broad jump improvement vs intermediate test', - 'L/R asymmetry < 20% everywhere', - ], - weeks: [w1, w2, w3, w4], -} - -export const AVANCE_SESSIONS: TabataSession[] = AVANCE_PROGRAM.weeks.flatMap(w => w.sessions) diff --git a/src/shared/data/tabata/bureau.ts b/src/shared/data/tabata/bureau.ts deleted file mode 100644 index 7e06774..0000000 --- a/src/shared/data/tabata/bureau.ts +++ /dev/null @@ -1,683 +0,0 @@ -/** - * Programme Bureau — 4 semaines, 3-4 séances/semaine - * Source: TabataKine_Guide_Complet.md, Section 7 - * Tier: PREMIUM - * - * Contraintes de conception: - * - Silence : pas de sauts, pas d'impacts, pas de chutes au sol - * - Pas de sol : tous les exercices debout ou assis sur une chaise - * - Pas de sueur visible : intensite calibree - * - 10 ou 20 min max - * - Tenue de bureau : aucun equipement - * - * 3 formats: - * - Format A (10 min, 4 blocs de 2 min = 8 rounds): Assis/desk exercises - * - Format B (20 min, 5 blocs de 4 min = 40 rounds): Standing exercises - * - Format C (20 min, walking meeting): Audio-guided walking - * - * Semaine 4 = decharge + autonomie - */ - -import type { TabataProgram, TabataSession, TabataWeek, TabataBlock, TabataExercise } from '../../types/program' - -// ─── Exercise helpers ────────────────────────────────────────── - -const ex = ( - name: string, nameEn: string, - conseil: string, conseilEn: string, - opts?: { modification?: string; modificationEn?: string; progression?: string; progressionEn?: string } -): TabataExercise => ({ - name, nameEn, conseil, conseilEn, ...opts, -}) - -const block = ( - id: string, - odd: TabataExercise, - even: TabataExercise, - rounds = 8, - workTime = 20, - restTime = 10, -): TabataBlock => ({ - id, oddExercise: odd, evenExercise: even, rounds, workTime, restTime, -}) - -// ─── Format A Exercises (Seated / Desk) ──────────────────────── - -const CONTRACTION_ABDO_ISO = ex( - 'Contraction abdominale isometrique', 'Isometric Abdominal Contraction', - "C'est le transverse. Le contracter regulierement en position assise combat directement les douleurs lombaires liees a la sedentarite.", - 'This targets the transverse abdominis. Regular contraction while seated directly fights lower back pain from sedentary habits.', - { - modification: 'Contracter sur 5 sec au lieu de 20', - modificationEn: 'Contract for 5 sec instead of 20', - progression: 'Ajouter une inclinaison du bassin en retroversion', - progressionEn: 'Add a posterior pelvic tilt', - }, -) - -const SERRAGE_FESSIER = ex( - 'Serrage fessier (assis)', 'Seated Glute Squeeze', - 'Contre la retroversion du bassin liee a la position assise prolongee. Invisible de l\'exterieur.', - 'Counteracts pelvic posterior tilt from prolonged sitting. Invisible to others.', - { - modification: 'Serrer un seul cote a la fois', - modificationEn: 'Squeeze one side at a time', - progression: 'Serrer + soulever legerement le bassin du siege', - progressionEn: 'Squeeze + slightly lift pelvis off the seat', - }, -) - -const EXTENSION_JAMBE_ASSIS = ex( - 'Extension de jambe (assis)', 'Seated Leg Extension', - 'Renforcement du quadriceps. Ajouter une contraction du pied (orteils vers soi) pour activer les tibias anterieurs.', - 'Quadriceps strengthening. Add a foot contraction (toes toward you) to activate tibialis anterior.', - { - modification: 'Extension partielle, jambe a moitie', - modificationEn: 'Partial extension, leg halfway up', - progression: 'Maintenir 3 sec en haut + flexion du pied', - progressionEn: 'Hold 3 sec at top + dorsiflex foot', - }, -) - -const ELEVATION_TALONS_ASSIS = ex( - 'Elevation de talons assis', 'Seated Heel Raise', - 'Active la pompe veineuse des jambes. Prevention des jambes lourdes et des varices.', - 'Activates the leg venous pump. Prevents heavy legs and varicose veins.', - { - modification: 'Elever un talon a la fois', - modificationEn: 'Raise one heel at a time', - progression: 'Elever les deux talons + maintenir 3 sec en haut', - progressionEn: 'Raise both heels + hold 3 sec at top', - }, -) - -const WALL_SIT = ex( - 'Wall sit (chaise invisible)', 'Wall Sit', - 'Aucun bruit, aucun mouvement visible de l\'exterieur, intensite maximale pour les quadriceps. Respirer calmement.', - 'No noise, no visible movement from outside, maximum intensity for quadriceps. Breathe calmly.', - { - modification: 'Angle de 135° au lieu de 90°', - modificationEn: '135° angle instead of 90°', - progression: 'Ajouter une contraction abdo en position basse', - progressionEn: 'Add an ab contraction at the bottom', - }, -) - -const ELEVATION_TALONS_DEBOUT = ex( - 'Elevation de talons debout', 'Standing Heel Raise', - 'Renforcement des soleaires et gastrocnemiens. Bras tendus devant soi pour l\'equilibre si necessaire.', - 'Strengthens soleus and gastrocnemius. Arms extended forward for balance if needed.', - { - modification: 'Tenir un support pour l\'equilibre', - modificationEn: 'Hold a support for balance', - progression: 'Unilateral — un pied a la fois', - progressionEn: 'Unilateral — one foot at a time', - }, -) - -const POMPES_BUREAU = ex( - 'Pompes contre le bureau', 'Desk Push-ups', - 'S\'assurer que le bureau est stable avant de commencer. Plus incline = plus facile.', - 'Make sure the desk is stable before starting. More incline = easier.', - { - modification: 'Mains sur le mur (plus vertical)', - modificationEn: 'Hands on wall (more vertical)', - progression: 'Mains sur un support plus bas (chaise)', - progressionEn: 'Hands on a lower surface (chair)', - }, -) - -const PULL_APART = ex( - 'Pull apart imaginaire', 'Imaginary Pull Apart', - 'Contre le syndrome de l\'epaule roulee du bureau. Ouvrir la poitrine au maximum.', - 'Counteracts desk slouch / rounded shoulders. Open the chest as wide as possible.', - { - modification: 'Bras plies a 90° au lieu de tendus', - modificationEn: 'Bent arms at 90° instead of straight', - progression: 'Ajouter une rotation externe des paumes vers le plafond', - progressionEn: 'Add external rotation of palms toward ceiling', - }, -) - -// ─── Format B Exercises (Standing, Zero Impact) ──────────────── - -const SQUAT_SILENCIEUX = ex( - 'Squat silencieux tempo 3-3', 'Silent Squat Tempo 3-3', - 'Tempo 3 sec descente / 3 sec montee pour rester sous le seuil de transpiration tout en maintenant l\'efficacite musculaire.', - '3 sec down / 3 sec up tempo to stay below the sweat threshold while maintaining muscle effectiveness.', - { - modification: 'Squat 1/4 avec tempo 2-2', - modificationEn: 'Quarter squat with 2-2 tempo', - progression: 'Ajouter 1 sec de maintien en bas', - progressionEn: 'Add 1 sec hold at the bottom', - }, -) - -const FENTE_STATIQUE_ROTATION = ex( - 'Fente statique avec rotation de buste', 'Static Lunge with Torso Rotation', - 'Fente basse tenue + rotation du tronc vers le genou avant. Mobilite thoracique et renforcement simultanes.', - 'Hold low lunge + rotate torso toward front knee. Thoracic mobility and strengthening simultaneously.', - { - modification: 'Fente haute (angle reduit)', - modificationEn: 'High lunge (reduced angle)', - progression: 'Ajouter les bras tendus au-dessus de la tete pendant la rotation', - progressionEn: 'Add arms extended overhead during rotation', - }, -) - -const BUREAU_DIPS = ex( - 'Bureau dips', 'Desk Dips', - 'Mains sur le bureau derriere soi, corps decolle, flechir les coudes. Verifier la stabilite du bureau avant de commencer.', - 'Hands on desk behind you, body lifted, bend elbows. Check desk stability before starting.', - { - modification: 'Jambes pliees, pieds plus proches', - modificationEn: 'Bent legs, feet closer', - progression: 'Jambes tendues, pieds plus eloignes', - progressionEn: 'Straight legs, feet further out', - }, -) - -const CALF_RAISES_FERMES = ex( - 'Calf raises yeux fermes', 'Eyes-closed Calf Raises', - 'Montees sur la pointe des pieds avec les yeux fermes. Double effet : renforcement + proprioception.', - 'Calf raises with eyes closed. Double benefit: strengthening + proprioception.', - { - modification: 'Garder les yeux ouverts, tenir un support', - modificationEn: 'Keep eyes open, hold a support', - progression: 'Unilateral — un pied a la fois, yeux fermes', - progressionEn: 'Unilateral — one foot at a time, eyes closed', - }, -) - -const ISOMETRIE_FESSIERS_DEBOUT = ex( - 'Isometrie fessiers debout', 'Standing Glute Isometric Hold', - 'Contracter les fessiers alternativement sans bouger les jambes. Activation du moyen fessier inhibe par la position assise.', - 'Contract glutes alternately without moving legs. Activates gluteus medius inhibited by prolonged sitting.', - { - modification: 'Contractions rapides (2 sec) au lieu de maintenues', - modificationEn: 'Quick contractions (2 sec) instead of holds', - progression: 'Ajouter une micro-elevee du talon du cote actif', - progressionEn: 'Add a micro heel lift on the active side', - }, -) - -const ROTATION_BUSTE_RAPIDE = ex( - 'Rotation de buste rapide', 'Fast Torso Rotation', - 'Bras croises sur la poitrine, rotation droite-gauche rapide. Active les obliques et echauffe les disques intervertebraux.', - 'Arms crossed on chest, fast right-left rotation. Activates obliques and warms up intervertebral discs.', - { - modification: 'Rotation lente et controlee', - modificationEn: 'Slow and controlled rotation', - progression: 'Bras tendus sur les cotes pour augmenter l\'amplitude', - progressionEn: 'Arms extended to sides for greater range of motion', - }, -) - -// ─── Format C Exercises (Walking / Audio-only) ───────────────── - -const MARCHE_RAPIDE = ex( - 'Marche rapide', 'Brisk Walking', - 'La marche active a 6-7 km/h suffit a atteindre 70-80% de la FC max. Amplement suffisant pour les benefices cardiovasculaires.', - 'Active walking at 6-7 km/h reaches 70-80% of max HR. Sufficient for cardiovascular HIIT benefits.', -) - -const MARCHE_GENOUX_HAUTS = ex( - 'Marche genoux hauts', 'High-knee Walking', - 'Lever les genoux a hauteur des hanches en marchant. Intensite elevee sans impact.', - 'Lift knees to hip height while walking. High intensity without impact.', -) - -const MARCHE_FENTE = ex( - 'Marche en fente', 'Lunge Walking', - 'Pas le plus long possible. Tronc droit, genou avant stable.', - 'Longest stride possible. Torso upright, front knee stable.', -) - -const MONTEE_ESCALIERS = ex( - 'Montee d\'escaliers', 'Stair Climbing', - 'Si disponibles. Monter en marchant rapide, descendre en marchant normale.', - 'If available. Walk up briskly, walk down normally.', -) - -const MARCHE_NORMALE = ex( - 'Marche normale (recuperation)', 'Normal Walking (recovery)', - 'Marche naturelle pour recuperation active entre les phases intenses.', - 'Natural walking for active recovery between intense phases.', -) - -// ─── Format A Warmup & Cooldown ──────────────────────────────── - -const FORMAT_A_WARMUP = { - movements: [ - { name: 'Cercles de poignets dans les deux sens', nameEn: 'Wrist Circles Both Directions', duration: 20 }, - { name: 'Mobilisation cervicale : inclinaisons et rotations douces', nameEn: 'Neck Mobilization: Gentle Tilts & Rotations', duration: 20 }, - { name: 'Ouverture de poitrine : bras en arriere, omoplates rapprochees', nameEn: 'Chest Opener: Arms Back, Squeeze Shoulder Blades', duration: 20 }, - ], - totalDuration: 60, -} - -const FORMAT_A_COOLDOWN = { - movements: [ - { name: 'Etirement cervical lateral doux (chaque cote)', nameEn: 'Gentle Lateral Neck Stretch (each side)', duration: 15 }, - { name: 'Etirement des poignets (extenseurs et flechisseurs)', nameEn: 'Wrist Stretch (extensors and flexors)', duration: 15 }, - { name: '3 grandes respirations diaphragmatiques', nameEn: '3 Deep Diaphragmatic Breaths', duration: 30 }, - ], - totalDuration: 60, -} - -// ─── Format B Warmup & Cooldown ──────────────────────────────── - -const FORMAT_B_WARMUP = { - movements: [ - { name: 'Marche sur place avec bras actifs', nameEn: 'March in Place with Active Arms', duration: 60 }, - { name: 'Cercles de hanches debout', nameEn: 'Standing Hip Circles', duration: 30 }, - { name: 'Squats lents d\'activation x8', nameEn: 'Slow Activation Squats x8', duration: 45 }, - { name: 'Rotations d\'epaules avant et arriere', nameEn: 'Shoulder Circles Forward & Back', duration: 30 }, - { name: 'Respiration diaphragmatique', nameEn: 'Diaphragmatic Breathing', duration: 15 }, - ], - totalDuration: 180, -} - -const FORMAT_B_COOLDOWN = { - movements: [ - { name: 'Etirement quadriceps debout (chaque jambe)', nameEn: 'Standing Quad Stretch (each leg)', duration: 30 }, - { name: 'Etirement des mollets contre un mur (chaque jambe)', nameEn: 'Wall Calf Stretch (each leg)', duration: 30 }, - { name: 'Etirement pectoraux en porte', nameEn: 'Doorway Chest Stretch', duration: 30 }, - { name: 'Rotation cervicale lente', nameEn: 'Slow Neck Rotation', duration: 15 }, - { name: 'Respiration 4-7-8 x 3 cycles', nameEn: '4-7-8 Breathing x 3 cycles', duration: 57 }, - ], - totalDuration: 162, -} - -// ─── Format C Warmup & Cooldown ──────────────────────────────── - -const FORMAT_C_WARMUP = { - movements: [ - { name: 'Marche normale d\'echauffement', nameEn: 'Normal Walking Warmup', duration: 60 }, - { name: 'Rotations d\'epaules en marchant', nameEn: 'Shoulder Rotations While Walking', duration: 30 }, - { name: 'Marche avec montees de genoux lentes', nameEn: 'Walking with Slow High Knees', duration: 30 }, - ], - totalDuration: 120, -} - -const FORMAT_C_COOLDOWN = { - movements: [ - { name: 'Marche normale de retour au calme', nameEn: 'Normal Walking Cooldown', duration: 60 }, - { name: 'Etirement des mollets en marchant', nameEn: 'Walking Calf Stretches', duration: 30 }, - { name: 'Respiration profonde en marchant', nameEn: 'Deep Breathing While Walking', duration: 30 }, - ], - totalDuration: 120, -} - -// ─── Session Builders ────────────────────────────────────────── - -/** Format A session: 10 min, 4 blocks of 2 min (8 rounds each) */ -const formatASession = ( - id: string, week: number, order: number, - title: string, titleEn: string, - description: string, descriptionEn: string, - focus: string[], focusEn: string[], - b1Odd: TabataExercise, b1Even: TabataExercise, - b2Odd: TabataExercise, b2Even: TabataExercise, - b3Odd: TabataExercise, b3Even: TabataExercise, - b4Odd: TabataExercise, b4Even: TabataExercise, - calories: number, -): TabataSession => ({ - id, week, order, title, titleEn, description, descriptionEn, focus, focusEn, - warmup: FORMAT_A_WARMUP, - blocks: [ - block(`${id}-b1`, b1Odd, b1Even), - block(`${id}-b2`, b2Odd, b2Even), - block(`${id}-b3`, b3Odd, b3Even), - block(`${id}-b4`, b4Odd, b4Even), - ], - cooldown: FORMAT_A_COOLDOWN, - equipment: ['Chaise', 'Mur (optionnel)', 'Bureau stable'], - totalRounds: 32, - totalDuration: 10, - calories, -}) - -/** Format B session: 20 min, 5 blocks of 4 min (8 rounds each) */ -const formatBSession = ( - id: string, week: number, order: number, - title: string, titleEn: string, - description: string, descriptionEn: string, - focus: string[], focusEn: string[], - b1Odd: TabataExercise, b1Even: TabataExercise, - b2Odd: TabataExercise, b2Even: TabataExercise, - b3Odd: TabataExercise, b3Even: TabataExercise, - b4Odd: TabataExercise, b4Even: TabataExercise, - b5Odd: TabataExercise, b5Even: TabataExercise, - calories: number, -): TabataSession => ({ - id, week, order, title, titleEn, description, descriptionEn, focus, focusEn, - warmup: FORMAT_B_WARMUP, - blocks: [ - block(`${id}-b1`, b1Odd, b1Even), - block(`${id}-b2`, b2Odd, b2Even), - block(`${id}-b3`, b3Odd, b3Even), - block(`${id}-b4`, b4Odd, b4Even), - block(`${id}-b5`, b5Odd, b5Even), - ], - cooldown: FORMAT_B_COOLDOWN, - equipment: ['Bureau stable', 'Mur (optionnel)'], - totalRounds: 40, - totalDuration: 20, - calories, -}) - -/** Format C session: 20 min walking meeting, 5 blocks of 4 min */ -const formatCSession = ( - id: string, week: number, order: number, - title: string, titleEn: string, - description: string, descriptionEn: string, - focus: string[], focusEn: string[], - calories: number, -): TabataSession => ({ - id, week, order, title, titleEn, description, descriptionEn, focus, focusEn, - warmup: FORMAT_C_WARMUP, - blocks: [ - block(`${id}-b1`, MARCHE_RAPIDE, MARCHE_NORMALE), - block(`${id}-b2`, MARCHE_GENOUX_HAUTS, MARCHE_NORMALE), - block(`${id}-b3`, MARCHE_FENTE, MARCHE_RAPIDE), - block(`${id}-b4`, MONTEE_ESCALIERS, MARCHE_NORMALE), - block(`${id}-b5`, MARCHE_RAPIDE, MARCHE_NORMALE), - ], - cooldown: FORMAT_C_COOLDOWN, - equipment: [], - totalRounds: 40, - totalDuration: 20, - calories, -}) - -// ─── Week 1: Creer l'habitude (3x Format A) ─────────────────── - -const week1: TabataWeek = { - weekNumber: 1, - title: 'Creer l\'habitude de la pause active', - titleEn: 'Building the Active Break Habit', - description: '3 seances Format A (10 min chacune). Mouvement assis et debout, parfaitement discret au bureau. Aucun equipement necessaire.', - descriptionEn: '3 Format A sessions (10 min each). Seated and standing movement, perfectly discreet at the office. No equipment needed.', - focus: 'Integration du mouvement dans la journee de travail', - focusEn: 'Integrating movement into the workday', - isDeload: false, - sessions: [ - // W1-S1 — Format A: Activation profonde + membres inferieurs - formatASession( - 'bur-w1-s1', 1, 1, - 'Pause active assise', 'Seated Active Break', - 'Activation profonde (assis) et membres inferieurs assis. Parfaitement discret.', - 'Deep activation (seated) and seated lower body. Perfectly discreet.', - ['Transverse', 'Quadriceps', 'Mollets'], - ['Transverse Abdominis', 'Quadriceps', 'Calves'], - CONTRACTION_ABDO_ISO, SERRAGE_FESSIER, - EXTENSION_JAMBE_ASSIS, ELEVATION_TALONS_ASSIS, - WALL_SIT, ELEVATION_TALONS_DEBOUT, - POMPES_BUREAU, PULL_APART, - 35, - ), - // W1-S2 — Format A: Renforcement jambes + haut du corps - formatASession( - 'bur-w1-s2', 1, 2, - 'Renforcement bureau', 'Desk Strength', - 'Extension de jambes, wall sit et pompes bureau. Seance equilibree pour toute la journee.', - 'Leg extensions, wall sits and desk push-ups. Balanced session for the whole day.', - ['Quadriceps', 'Fessiers', 'Pectoraux'], - ['Quadriceps', 'Glutes', 'Chest'], - SERRAGE_FESSIER, CONTRACTION_ABDO_ISO, - ELEVATION_TALONS_ASSIS, EXTENSION_JAMBE_ASSIS, - ELEVATION_TALONS_DEBOUT, WALL_SIT, - PULL_APART, POMPES_BUREAU, - 38, - ), - // W1-S3 — Format A: Variante equilibree - formatASession( - 'bur-w1-s3', 1, 3, - 'Equilibre bureau', 'Desk Balance', - 'Melange des exercices de la semaine pour consolider les mouvements.', - 'Mix of the week\'s exercises to consolidate movements.', - ['Gainage', 'Mollets', 'Dos'], - ['Core', 'Calves', 'Back'], - CONTRACTION_ABDO_ISO, SERRAGE_FESSIER, - EXTENSION_JAMBE_ASSIS, ELEVATION_TALONS_ASSIS, - WALL_SIT, ELEVATION_TALONS_DEBOUT, - PULL_APART, POMPES_BUREAU, - 36, - ), - ], -} - -// ─── Week 2: Introduction du format long (2x A + 1x B) ──────── - -const week2: TabataWeek = { - weekNumber: 2, - title: 'Introduction du format long', - titleEn: 'Introducing the Longer Format', - description: '2 seances Format A (10 min) + 1 seance Format B (20 min). Le Format B introduit des exercices debout plus intenses.', - descriptionEn: '2 Format A sessions (10 min) + 1 Format B session (20 min). Format B introduces more intense standing exercises.', - focus: 'Progression vers le format 20 minutes, exercices debout', - focusEn: 'Progressing to the 20-minute format, standing exercises', - isDeload: false, - sessions: [ - // W2-S1 — Format A (assis) - formatASession( - 'bur-w2-s1', 2, 1, - 'Pause rapide assise', 'Quick Seated Break', - 'Format A renforce. Les contractions isometriques deviennent plus naturelles.', - 'Consolidated Format A. Isometric contractions become more natural.', - ['Transverse', 'Quadriceps', 'Epaules'], - ['Transverse Abdominis', 'Quadriceps', 'Shoulders'], - CONTRACTION_ABDO_ISO, SERRAGE_FESSIER, - EXTENSION_JAMBE_ASSIS, ELEVATION_TALONS_ASSIS, - WALL_SIT, ELEVATION_TALONS_DEBOUT, - POMPES_BUREAU, PULL_APART, - 37, - ), - // W2-S2 — Format A (variant) - formatASession( - 'bur-w2-s2', 2, 2, - 'Renforcement silencieux', 'Silent Strengthening', - 'Derniere seance Format A de la semaine. Focus sur la qualite des contractions.', - 'Last Format A session of the week. Focus on contraction quality.', - ['Fessiers', 'Pectoraux', 'Mollets'], - ['Glutes', 'Chest', 'Calves'], - SERRAGE_FESSIER, CONTRACTION_ABDO_ISO, - ELEVATION_TALONS_ASSIS, EXTENSION_JAMBE_ASSIS, - ELEVATION_TALONS_DEBOUT, WALL_SIT, - PULL_APART, POMPES_BUREAU, - 38, - ), - // W2-S3 — Format B (20 min debout) - formatBSession( - 'bur-w2-s3', 2, 3, - 'Format long debout', 'Long Standing Session', - 'Premiere seance Format B. 20 minutes debout avec squats silencieux, fentes et dips bureau.', - 'First Format B session. 20 minutes standing with silent squats, lunges and desk dips.', - ['Quadriceps', 'Triceps', 'Proprioception', 'Obliques'], - ['Quadriceps', 'Triceps', 'Proprioception', 'Obliques'], - SQUAT_SILENCIEUX, FENTE_STATIQUE_ROTATION, - BUREAU_DIPS, CALF_RAISES_FERMES, - ISOMETRIE_FESSIERS_DEBOUT, ROTATION_BUSTE_RAPIDE, - SQUAT_SILENCIEUX, ELEVATION_TALONS_DEBOUT, - ROTATION_BUSTE_RAPIDE, ISOMETRIE_FESSIERS_DEBOUT, - 90, - ), - ], -} - -// ─── Week 3: Walking meeting integre (1x A + 2x B + 1x C) ──── - -const week3: TabataWeek = { - weekNumber: 3, - title: 'Walking meeting integre', - titleEn: 'Walking Meeting Integrated', - description: '1 Format A + 2 Format B + 1 Format C (walking meeting audio). Seule semaine a 4 seances.', - descriptionEn: '1 Format A + 2 Format B + 1 Format C (audio walking meeting). Only week with 4 sessions.', - focus: 'Introduction de la marche active, autonomie dans les formats', - focusEn: 'Introducing active walking, autonomy across formats', - isDeload: false, - sessions: [ - // W3-S1 — Format A (rappel) - formatASession( - 'bur-w3-s1', 3, 1, - 'Pause express bureau', 'Express Desk Break', - 'Dernier Format A du programme. Tous les exercices doivent etre fluides.', - 'Last Format A of the program. All exercises should feel fluid.', - ['Transverse', 'Quadriceps', 'Haut du corps'], - ['Transverse Abdominis', 'Quadriceps', 'Upper Body'], - CONTRACTION_ABDO_ISO, SERRAGE_FESSIER, - EXTENSION_JAMBE_ASSIS, ELEVATION_TALONS_ASSIS, - WALL_SIT, ELEVATION_TALONS_DEBOUT, - POMPES_BUREAU, PULL_APART, - 38, - ), - // W3-S2 — Format B (renforcement) - formatBSession( - 'bur-w3-s2', 3, 2, - 'Renforcement standing', 'Standing Strength', - 'Format B renforce. Squats silencieux, fentes avec rotation et proprioception.', - 'Consolidated Format B. Silent squats, lunges with rotation and proprioception.', - ['Quadriceps', 'Triceps', 'Mobilite thoracique', 'Equilibre'], - ['Quadriceps', 'Triceps', 'Thoracic Mobility', 'Balance'], - SQUAT_SILENCIEUX, FENTE_STATIQUE_ROTATION, - BUREAU_DIPS, CALF_RAISES_FERMES, - ISOMETRIE_FESSIERS_DEBOUT, ROTATION_BUSTE_RAPIDE, - WALL_SIT, SQUAT_SILENCIEUX, - PULL_APART, ROTATION_BUSTE_RAPIDE, - 92, - ), - // W3-S3 — Format B (intensite) - formatBSession( - 'bur-w3-s3', 3, 3, - 'Intensite bureau avancee', 'Advanced Desk Intensity', - 'Format B intense. Plus de proprioception et de mobilite thoracique.', - 'Intense Format B. More proprioception and thoracic mobility.', - ['Fessiers', 'Obliques', 'Proprioception', 'Dos'], - ['Glutes', 'Obliques', 'Proprioception', 'Back'], - FENTE_STATIQUE_ROTATION, SQUAT_SILENCIEUX, - CALF_RAISES_FERMES, BUREAU_DIPS, - ROTATION_BUSTE_RAPIDE, ISOMETRIE_FESSIERS_DEBOUT, - ELEVATION_TALONS_DEBOUT, WALL_SIT, - ISOMETRIE_FESSIERS_DEBOUT, ROTATION_BUSTE_RAPIDE, - 95, - ), - // W3-S4 — Format C (walking meeting) - formatCSession( - 'bur-w3-s4', 3, 4, - 'Walking meeting actif', 'Active Walking Meeting', - 'Seance audio guidee pendant une marche. Marche rapide, genoux hauts, marche en fente et escaliers.', - 'Audio-guided session during a walk. Brisk walking, high knees, lunge walking and stairs.', - ['Cardio', 'Membres inferieurs', 'Endurance'], - ['Cardio', 'Lower Body', 'Endurance'], - 85, - ), - ], -} - -// ─── Week 4: Autonomie — Decharge (3x mixed formats) ────────── - -const week4: TabataWeek = { - weekNumber: 4, - title: 'Autonomie — Semaine de decharge', - titleEn: 'Autonomy — Deload Week', - description: 'Semaine 4 = decharge + prise d\'autonomie. Choisir selon la journee. L\'objectif : integrer le mouvement comme reflexe.', - descriptionEn: 'Week 4 = deload + building autonomy. Choose based on your day. Goal: make movement a reflex.', - focus: 'Autonomie, choix du format selon la journee, consolidation', - focusEn: 'Autonomy, choosing format based on the day, consolidation', - isDeload: true, - sessions: [ - // W4-S1 — Format A (deload) - formatASession( - 'bur-w4-s1', 4, 1, - 'Micro-pause autonome', 'Autonomous Micro-break', - 'Format A en autonomie. 10 minutes pour relancer la concentration.', - 'Autonomous Format A. 10 minutes to boost concentration.', - ['Transverse', 'Fessiers', 'Epaules'], - ['Transverse Abdominis', 'Glutes', 'Shoulders'], - CONTRACTION_ABDO_ISO, SERRAGE_FESSIER, - EXTENSION_JAMBE_ASSIS, ELEVATION_TALONS_ASSIS, - WALL_SIT, ELEVATION_TALONS_DEBOUT, - PULL_APART, POMPES_BUREAU, - 32, - ), - // W4-S2 — Format B (deload) - formatBSession( - 'bur-w4-s2', 4, 2, - 'Pause longue autonome', 'Autonomous Long Break', - 'Format B en autonomie. Mouvements debout avec proprioception et mobilite.', - 'Autonomous Format B. Standing movements with proprioception and mobility.', - ['Quadriceps', 'Equilibre', 'Mobilite thoracique'], - ['Quadriceps', 'Balance', 'Thoracic Mobility'], - SQUAT_SILENCIEUX, ELEVATION_TALONS_DEBOUT, - FENTE_STATIQUE_ROTATION, ISOMETRIE_FESSIERS_DEBOUT, - PULL_APART, ROTATION_BUSTE_RAPIDE, - WALL_SIT, CALF_RAISES_FERMES, - BUREAU_DIPS, PULL_APART, - 80, - ), - // W4-S3 — Format C (walking meeting deload) - formatCSession( - 'bur-w4-s3', 4, 3, - 'Marche active autonome', 'Autonomous Active Walk', - 'Walking meeting en autonomie. Le mouvement est devenu un reflexe.', - 'Autonomous walking meeting. Movement has become a reflex.', - ['Cardio', 'Endurance', 'Bien-etre'], - ['Cardio', 'Endurance', 'Wellbeing'], - 75, - ), - ], -} - -// ─── Program Export ───────────────────────────────────────────── - -export const BUREAU_PROGRAM: TabataProgram = { - id: 'bureau', - title: 'Programme Bureau', - titleEn: 'Office Program', - description: 'Integrer le mouvement comme reflexe dans la journee de travail. 10 minutes de mouvement actif reduisent les douleurs lombaires de 30% et ameliorent la concentration de 20%.', - descriptionEn: 'Make movement a reflex in your workday. 10 minutes of active movement reduces lower back pain by 30% and improves concentration by 20%.', - tier: 'premium', - accentColor: '#FFD60A', - icon: 'briefcase', - durationWeeks: 4, - sessionsPerWeek: 4, // Variable: 3 in W1/W2/W4, 4 in W3 - totalSessions: 13, - equipment: { - required: [], - optional: ['Chaise', 'Bureau stable', 'Mur'], - }, - focusAreas: ['Wall sit', 'Gainage assis', 'Pompes bureau', 'Extension jambe assise', 'Proprioception'], - focusAreasEn: ['Wall sit', 'Seated core', 'Desk push-ups', 'Seated leg extension', 'Proprioception'], - principles: [ - 'Silence : pas de sauts, pas d\'impacts, pas de chutes au sol', - 'Pas de sol : exercices debout ou assis sur une chaise uniquement', - 'Pas de sueur visible : intensite calibree pour le bureau', - '10 ou 20 min max selon le format', - 'Tenue de bureau : aucun equipement sportif necessaire', - ], - principlesEn: [ - 'Silent: no jumps, no impact, no floor work', - 'No floor: standing or seated on a chair only', - 'No visible sweat: intensity calibrated for the office', - '10 or 20 min max depending on format', - 'Office attire: no sports equipment needed', - ], - completionCriteria: [ - 'Realiser un Format B complet sans pause supplementaire', - 'Tenir un wall sit 90 secondes sans douleur', - 'Integrer au moins 3 pauses actives par semaine de travail', - 'Connaitre les exercices par cœur (sans regarder l\'ecran)', - ], - completionCriteriaEn: [ - 'Complete a full Format B without extra breaks', - 'Hold a wall sit for 90 seconds without pain', - 'Integrate at least 3 active breaks per work week', - 'Know the exercises by heart (without looking at the screen)', - ], - nextProgramId: 'debutant', - weeks: [week1, week2, week3, week4], -} - -/** All sessions flattened for quick lookup */ -export const BUREAU_SESSIONS: TabataSession[] = BUREAU_PROGRAM.weeks.flatMap(w => w.sessions) diff --git a/src/shared/data/tabata/debutant.ts b/src/shared/data/tabata/debutant.ts deleted file mode 100644 index c0d284a..0000000 --- a/src/shared/data/tabata/debutant.ts +++ /dev/null @@ -1,717 +0,0 @@ -/** - * Programme Débutant — 4 semaines, 3 séances/semaine - * Source: TabataKine_Guide_Complet.md - * Tier: GRATUIT - * - * Règles: - * - Zéro impact les 2 premières semaines - * - La technique avant l'intensité - * - Semaine 4 = décharge (volume réduit 40%) - */ - -import type { TabataProgram, TabataSession, TabataWeek, TabataBlock, TabataExercise } from '../../types/program' - -// ─── Exercise helpers ────────────────────────────────────────── - -const ex = ( - name: string, nameEn: string, - conseil: string, conseilEn: string, - opts?: { modification?: string; modificationEn?: string; progression?: string; progressionEn?: string } -): TabataExercise => ({ - name, nameEn, conseil, conseilEn, ...opts, -}) - -const block = ( - id: string, - odd: TabataExercise, - even: TabataExercise, - rounds = 8, - workTime = 20, - restTime = 10, -): TabataBlock => ({ - id, oddExercise: odd, evenExercise: even, rounds, workTime, restTime, -}) - -// ─── Exercises Library ───────────────────────────────────────── - -const SQUAT_CLASSIQUE = ex( - 'Squat classique', 'Classic Squat', - 'Si les talons se soulèvent : écarter davantage les pieds ou placer un support sous les talons. Genoux dans l\'axe des pieds, jamais vers l\'intérieur.', - 'If heels lift: widen your stance or place a support under heels. Keep knees aligned with feet, never cave inward.', -) - -const PONT_FESSIER = ex( - 'Pont fessier', 'Glute Bridge', - 'Ne pas creuser le bas du dos en position haute. Le bassin monte grâce aux fessiers, pas grâce aux lombaires.', - 'Don\'t arch your lower back at the top. Drive through your glutes, not your lower back.', -) - -const POMPE_GENOUX = ex( - 'Pompes genoux', 'Knee Push-ups', - 'Si douleur aux poignets : faire sur les poings fermés ou les avant-bras. Vérifier l\'alignement poignet / coude / épaule.', - 'If wrist pain: do them on closed fists or forearms. Check wrist/elbow/shoulder alignment.', -) - -const PLANCHE_AVANT_BRAS = ex( - 'Planche avant-bras', 'Forearm Plank', - 'Respirer normalement. La planche doit être une contraction active — réduire la durée si tremblements excessifs.', - 'Breathe normally. Plank should be an active contraction — reduce duration if excessive shaking.', -) - -const STEP_TOUCH = ex( - 'Step touch latéral', 'Lateral Step Touch', - 'Garder le regard droit. Les bras actifs contribuent à 20% de l\'effort cardiovasculaire.', - 'Keep eyes forward. Active arms contribute 20% of cardiovascular effort.', -) - -const SUPERMAN = ex( - 'Superman', 'Superman', - 'Ne pas forcer sur le cou — il reste dans l\'axe. Exercice roi pour les lombaires et les paravertébraux.', - 'Don\'t strain your neck — keep it aligned. Top exercise for lower back and paraspinal muscles.', -) - -const FENTE_AVANT = ex( - 'Fente avant alternée', 'Alternating Forward Lunge', - 'Le genou avant ne dépasse pas les orteils. Si douleur rotulienne : réduire l\'amplitude.', - 'Front knee should not pass toes. If kneecap pain: reduce range of motion.', -) - -const DEAD_BUG = ex( - 'Dead bug', 'Dead Bug', - 'Gainage profond transverse — excellent pour les lombaires. La version un seul membre reste disponible si besoin.', - 'Deep transverse core engagement — excellent for lower back. Single-limb version available if needed.', -) - -const BIRD_DOG = ex( - 'Bird dog', 'Bird Dog', - 'Placer une bouteille sur le dos pour vérifier que le bassin reste horizontal.', - 'Place a bottle on your back to check that your pelvis stays horizontal.', -) - -const SQUAT_JUMP_LOW = ex( - 'Squat jump low', 'Low Squat Jump', - 'Réception silencieuse sur avant-pied. Si bruit à l\'atterrissage : réduire la hauteur.', - 'Silent landing on forefoot. If you hear noise on landing: reduce height.', -) - -const STEP_UP = ex( - 'Step-up sur marche', 'Step-up', - 'Genou de la jambe de montée au-dessus du pied de la marche.', - 'Knee of stepping leg should be above the step foot.', -) - -const MOUNTAIN_CLIMBER_LENt = ex( - 'Mountain climber lent', 'Slow Mountain Climber', - 'Gainage parfait pendant tout le mouvement. Ne pas laisser les hanches monter.', - 'Perfect core engagement throughout. Don\'t let hips rise.', -) - -const PONT_FESSIER_UNILAT = ex( - 'Pont fessier unilatéral', 'Single-leg Glute Bridge', - 'Le bassin ne doit pas s\'incliner du côté de la jambe levée — signe de faiblesse du moyen fessier.', - 'Pelvis should not tilt toward the raised leg — indicates gluteus medius weakness.', -) - -const FENTE_AVANT_MAÎTRISÉE = ex( - 'Fente avant maîtrisée', 'Controlled Forward Lunge', - '¼ de descente supplémentaire par rapport à la semaine 1. Contrôle total du mouvement.', - 'Quarter descent deeper than week 1. Total control of the movement.', -) - -const SQUAT_CONSOLIDATION = ex( - 'Squat classique (consolidation)', 'Classic Squat (consolidation)', - 'Augmenter la profondeur, viser cuisses parallèles au sol, tempo 2-1-2.', - 'Increase depth, aim for thighs parallel to floor, tempo 2-1-2.', -) - -const PONT_FESSIER_CONSOL = ex( - 'Pont fessier (consolidation)', 'Glute Bridge (consolidation)', - 'Ajouter 1 sec de maintien en haut, soulever les orteils pour intensifier.', - 'Add 1 sec hold at the top, lift toes to intensify.', -) - -const POMPE_GENOUX_CONSOL = ex( - 'Pompes genoux (consolidation)', 'Knee Push-ups (consolidation)', - 'Essayer 2–3 pompes complètes sur orteils si possible.', - 'Try 2–3 full push-ups on toes if possible.', -) - -const PLANCHE_CONSOL = ex( - 'Planche avant-bras (consolidation)', 'Forearm Plank (consolidation)', - 'Tenter la planche sur orteils 10 sec puis repasser sur genoux si besoin.', - 'Try plank on toes for 10 sec then return to knees if needed.', -) - -const SUPERMAN_DYNAMIQUE = ex( - 'Superman dynamique', 'Dynamic Superman', - 'Version dynamique : lever et descendre en rythme avec la respiration.', - 'Dynamic version: raise and lower in rhythm with breathing.', -) - -const STEP_TOUCH_CONSOL = ex( - 'Step touch (consolidation)', 'Step Touch (consolidation)', - 'Augmenter la vitesse, bras au-dessus des épaules.', - 'Increase speed, arms above shoulders.', -) - -const SUPERMAN_CONSOL = ex( - 'Superman (consolidation)', 'Superman (consolidation)', - 'Maintenir la position haute 3 secondes au lieu de 2.', - 'Hold the top position for 3 seconds instead of 2.', -) - -const FENTE_ROTATION = ex( - 'Fente avant + rotation de buste', 'Forward Lunge + Torso Rotation', - 'En fente basse, rotation du tronc vers le genou avant.', - 'In low lunge, rotate torso toward front knee.', -) - -const DEAD_BUG_LENt = ex( - 'Dead bug lent', 'Slow Dead Bug', - '5 secondes par membre, qualité absolue.', - '5 seconds per limb, absolute quality.', -) - -// ─── Week 1: Découverte du rythme (1 bloc/séance) ──────────── - -const week1: TabataWeek = { - weekNumber: 1, - title: 'Découverte du rythme', - titleEn: 'Finding Your Rhythm', - description: 'Un bloc tabata par séance (4 min) + échauffement + retour au calme. Durée totale : ~20 minutes.', - descriptionEn: 'One tabata block per session (4 min) + warmup + cooldown. Total duration: ~20 min.', - focus: 'Apprentissage du protocole 20/10, technique de base', - focusEn: 'Learning the 20/10 protocol, basic technique', - isDeload: false, - sessions: [ - // 1A — Membres inférieurs - { - id: 'deb-w1-s1', - week: 1, order: 1, - title: 'Membres inférieurs', - titleEn: 'Lower Body', - description: 'Squat classique et pont fessier pour construire les bases des jambes.', - descriptionEn: 'Classic squat and glute bridge to build leg foundations.', - focus: ['Quadriceps', 'Fessiers', 'Mollets'], - focusEn: ['Quadriceps', 'Glutes', 'Calves'], - warmup: { - movements: [ - { name: 'Marche sur place genoux hauts', nameEn: 'High-knee March in Place', duration: 60 }, - { name: 'Cercles de chevilles', nameEn: 'Ankle Circles', duration: 60 }, - { name: 'Flexions de genoux lentes', nameEn: 'Slow Knee Bends', duration: 60 }, - { name: 'Fentes statiques alternées', nameEn: 'Alternating Static Lunges', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w1-s1-b1', SQUAT_CLASSIQUE, PONT_FESSIER), - ], - cooldown: { - movements: [ - { name: 'Étirement quadriceps debout (chaque jambe)', nameEn: 'Standing Quad Stretch (each leg)', duration: 45 }, - { name: 'Étirement ischio-jambiers assis (chaque jambe)', nameEn: 'Seated Hamstring Stretch (each leg)', duration: 45 }, - { name: 'Respiration diaphragmatique', nameEn: 'Diaphragmatic Breathing', duration: 30 }, - ], - totalDuration: 120, - }, - equipment: ['Tapis (optionnel)'], - totalRounds: 8, - totalDuration: 20, - calories: 45, - }, - // 1B — Membres supérieurs & gainage - { - id: 'deb-w1-s2', - week: 1, order: 2, - title: 'Membres supérieurs & gainage', - titleEn: 'Upper Body & Core', - description: 'Pompes sur genoux et planche avant-bras pour renforcer le haut du corps.', - descriptionEn: 'Knee push-ups and forearm plank to strengthen upper body.', - focus: ['Pectoraux', 'Triceps', 'Abdominaux profonds'], - focusEn: ['Chest', 'Triceps', 'Deep Core'], - warmup: { - movements: [ - { name: 'Rotations d\'épaules avant et arrière', nameEn: 'Shoulder Circles Forward & Back', duration: 60 }, - { name: 'Ouvertures de poitrine', nameEn: 'Chest Openers', duration: 60 }, - { name: 'Cercles de poignets', nameEn: 'Wrist Circles', duration: 60 }, - { name: 'Cat-cow (mobilité lombaire)', nameEn: 'Cat-Cow (Spinal Mobility)', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w1-s2-b1', POMPE_GENOUX, PLANCHE_AVANT_BRAS), - ], - cooldown: { - movements: [ - { name: 'Étirement pectoraux contre un mur (chaque côté)', nameEn: 'Wall Chest Stretch (each side)', duration: 45 }, - { name: 'Étirement triceps derrière la tête', nameEn: 'Overhead Triceps Stretch', duration: 30 }, - { name: 'Étirement cervical latéral doux', nameEn: 'Gentle Lateral Neck Stretch', duration: 30 }, - ], - totalDuration: 120, - }, - equipment: ['Tapis (optionnel)'], - totalRounds: 8, - totalDuration: 20, - calories: 40, - }, - // 1C — Corps entier - { - id: 'deb-w1-s3', - week: 1, order: 3, - title: 'Corps entier', - titleEn: 'Full Body', - description: 'Step touch latéral et superman pour une séance complète sans impact.', - descriptionEn: 'Lateral step touch and superman for a complete no-impact session.', - focus: ['Cardio léger', 'Dos', 'Épaules'], - focusEn: ['Light Cardio', 'Back', 'Shoulders'], - warmup: { - movements: [ - { name: 'Jumping jacks lents sans sauter', nameEn: 'Slow Jumping Jacks (no jump)', duration: 60 }, - { name: 'Rotations de hanches debout', nameEn: 'Standing Hip Circles', duration: 60 }, - { name: 'Marche avec bras croisés', nameEn: 'Walking with Crossed Arms', duration: 60 }, - { name: 'Squats ¼ de descente', nameEn: 'Quarter Squats', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w1-s3-b1', STEP_TOUCH, SUPERMAN), - ], - cooldown: { - movements: [ - { name: 'Posture de l\'enfant (balasana)', nameEn: 'Child\'s Pose (Balasana)', duration: 60 }, - { name: 'Étirement des hanches en pigeon (chaque côté)', nameEn: 'Pigeon Hip Stretch (each side)', duration: 45 }, - ], - totalDuration: 105, - }, - equipment: ['Tapis (optionnel)'], - totalRounds: 8, - totalDuration: 20, - calories: 42, - }, - ], -} - -// ─── Week 2: Consolidation (2 blocs/séance) ────────────────── - -const week2: TabataWeek = { - weekNumber: 2, - title: 'Consolidation', - titleEn: 'Building Strength', - description: '2 blocs tabata + 1 min récupération entre les blocs. Durée totale : ~25 minutes.', - descriptionEn: '2 tabata blocks + 1 min recovery between blocks. Total duration: ~25 min.', - focus: 'Consolidation des mouvements, introduction de nouveaux exercices', - focusEn: 'Consolidating movements, introducing new exercises', - isDeload: false, - sessions: [ - // 2A — Membres inférieurs renforcés - { - id: 'deb-w2-s1', - week: 2, order: 1, - title: 'Membres inférieurs renforcés', - titleEn: 'Strengthened Lower Body', - description: 'Consolidation squat + pont fessier, puis fente avant + dead bug.', - descriptionEn: 'Consolidation squat + glute bridge, then forward lunge + dead bug.', - focus: ['Quadriceps', 'Fessiers', 'Transverse'], - focusEn: ['Quadriceps', 'Glutes', 'Transverse Abdominis'], - warmup: { - movements: [ - { name: 'Marche sur place avec genoux hauts', nameEn: 'High-knee March', duration: 60 }, - { name: 'Squats lents d\'activation', nameEn: 'Slow Activation Squats', duration: 60 }, - { name: 'Cercles de hanches', nameEn: 'Hip Circles', duration: 60 }, - { name: 'Fentes statiques légères', nameEn: 'Light Static Lunges', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w2-s1-b1', SQUAT_CONSOLIDATION, PONT_FESSIER_CONSOL), - block('deb-w2-s1-b2', FENTE_AVANT, DEAD_BUG), - ], - cooldown: { - movements: [ - { name: 'Étirement du psoas en fente basse (chaque côté)', nameEn: 'Low Lunge Psoas Stretch (each side)', duration: 60 }, - { name: 'Étirement des ischio-jambiers allongé', nameEn: 'Lying Hamstring Stretch', duration: 45 }, - { name: 'Respiration guidée', nameEn: 'Guided Breathing', duration: 30 }, - ], - totalDuration: 135, - }, - equipment: ['Tapis (optionnel)'], - totalRounds: 16, - totalDuration: 25, - calories: 75, - }, - // 2B — Haut du corps renforcé - { - id: 'deb-w2-s2', - week: 2, order: 2, - title: 'Haut du corps renforcé', - titleEn: 'Strengthened Upper Body', - description: 'Consolidation pompes + planche, puis bird dog + superman dynamique.', - descriptionEn: 'Consolidation push-ups + plank, then bird dog + dynamic superman.', - focus: ['Pectoraux', 'Épaules', 'Lombaires'], - focusEn: ['Chest', 'Shoulders', 'Lower Back'], - warmup: { - movements: [ - { name: 'Rotations d\'épaules complètes', nameEn: 'Full Shoulder Rotations', duration: 60 }, - { name: 'Pompes lentes d\'activation', nameEn: 'Slow Activation Push-ups', duration: 60 }, - { name: 'Planche dynamique haute ↔ basse', nameEn: 'Dynamic Plank High ↔ Low', duration: 60 }, - { name: 'Cat-cow', nameEn: 'Cat-Cow', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w2-s2-b1', POMPE_GENOUX_CONSOL, PLANCHE_CONSOL), - block('deb-w2-s2-b2', BIRD_DOG, SUPERMAN_DYNAMIQUE), - ], - cooldown: { - movements: [ - { name: 'Étirement pectoraux en porte', nameEn: 'Doorway Chest Stretch', duration: 45 }, - { name: 'Étirement grand dorsal', nameEn: 'Lat Stretch', duration: 45 }, - { name: 'Respiration guidée', nameEn: 'Guided Breathing', duration: 30 }, - ], - totalDuration: 120, - }, - equipment: ['Tapis (optionnel)'], - totalRounds: 16, - totalDuration: 25, - calories: 70, - }, - // 2C — Corps entier mixte - { - id: 'deb-w2-s3', - week: 2, order: 3, - title: 'Corps entier mixte', - titleEn: 'Mixed Full Body', - description: 'Consolidation step touch + superman, puis fente rotation + dead bug lent.', - descriptionEn: 'Consolidation step touch + superman, then lunge rotation + slow dead bug.', - focus: ['Cardio', 'Gainage', 'Mobilité thoracique'], - focusEn: ['Cardio', 'Core', 'Thoracic Mobility'], - warmup: { - movements: [ - { name: 'Jumping jacks lents', nameEn: 'Slow Jumping Jacks', duration: 60 }, - { name: 'Rotations de hanches', nameEn: 'Hip Circles', duration: 60 }, - { name: 'Squats légers', nameEn: 'Light Squats', duration: 60 }, - { name: 'Mobilisation cervicale', nameEn: 'Neck Mobilization', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w2-s3-b1', STEP_TOUCH_CONSOL, SUPERMAN_CONSOL), - block('deb-w2-s3-b2', FENTE_ROTATION, DEAD_BUG_LENt), - ], - cooldown: { - movements: [ - { name: 'Posture de l\'enfant', nameEn: 'Child\'s Pose', duration: 60 }, - { name: 'Torsion vertébrale au sol (chaque côté)', nameEn: 'Supine Spinal Twist (each side)', duration: 45 }, - { name: 'Respiration 4-7-8', nameEn: '4-7-8 Breathing', duration: 30 }, - ], - totalDuration: 135, - }, - equipment: ['Tapis (optionnel)'], - totalRounds: 16, - totalDuration: 25, - calories: 72, - }, - ], -} - -// ─── Week 3: Montée en intensité (3 blocs/séance) ──────────── - -const week3: TabataWeek = { - weekNumber: 3, - title: 'Montée en intensité', - titleEn: 'Building Intensity', - description: '3 blocs tabata + 1 min récupération entre chaque. Durée totale : ~30 minutes.', - descriptionEn: '3 tabata blocks + 1 min recovery between each. Total duration: ~30 min.', - focus: 'Introduction d\'impacts très légers, augmentation du volume', - focusEn: 'Introducing very light impact, increasing volume', - isDeload: false, - sessions: [ - // 3A — Membres inférieurs - { - id: 'deb-w3-s1', - week: 3, order: 1, - title: 'Membres inférieurs explosifs', - titleEn: 'Explosive Lower Body', - description: 'Squat classique + pont unilatéral, squat jump low + fente maîtrisée, step-up + mountain climber.', - descriptionEn: 'Classic squat + single-leg bridge, low squat jump + controlled lunge, step-up + mountain climber.', - focus: ['Puissance', 'Équilibre', 'Proprioception'], - focusEn: ['Power', 'Balance', 'Proprioception'], - warmup: { - movements: [ - { name: 'Marche rapide avec bras actifs', nameEn: 'Brisk Walk with Active Arms', duration: 60 }, - { name: 'Squats lents x10', nameEn: 'Slow Squats x10', duration: 60 }, - { name: 'Montées de genoux', nameEn: 'High Knees', duration: 60 }, - { name: 'Hip circles', nameEn: 'Hip Circles', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w3-s1-b1', SQUAT_CONSOLIDATION, PONT_FESSIER_UNILAT), - block('deb-w3-s1-b2', SQUAT_JUMP_LOW, FENTE_AVANT_MAÎTRISÉE), - block('deb-w3-s1-b3', STEP_UP, MOUNTAIN_CLIMBER_LENt), - ], - cooldown: { - movements: [ - { name: 'Étirement psoas en fente basse', nameEn: 'Low Lunge Psoas Stretch', duration: 60 }, - { name: 'Étirement mollets contre un mur', nameEn: 'Wall Calf Stretch', duration: 45 }, - { name: 'Automassage quadriceps', nameEn: 'Self-massage Quadriceps', duration: 45 }, - { name: 'Respiration guidée', nameEn: 'Guided Breathing', duration: 30 }, - ], - totalDuration: 180, - }, - equipment: ['Marche ou step bas', 'Tapis (optionnel)'], - totalRounds: 24, - totalDuration: 30, - calories: 120, - }, - // 3B — Haut du corps - { - id: 'deb-w3-s2', - week: 3, order: 2, - title: 'Haut du corps dynamique', - titleEn: 'Dynamic Upper Body', - description: 'Pompes + planche consolidation, pompes rotation + planche tap épaule, superman dynamique.', - descriptionEn: 'Push-ups + plank consolidation, rotation push-ups + shoulder tap plank, dynamic superman.', - focus: ['Pectoraux', 'Épaules', 'Stabilité scapulaire'], - focusEn: ['Chest', 'Shoulders', 'Scapular Stability'], - warmup: { - movements: [ - { name: 'Rotations complètes d\'épaules', nameEn: 'Full Shoulder Rotations', duration: 60 }, - { name: 'Pompes lentes x8', nameEn: 'Slow Push-ups x8', duration: 60 }, - { name: 'Planche dynamique haute ↔ basse', nameEn: 'Dynamic Plank High ↔ Low', duration: 60 }, - { name: 'Dead bug lent', nameEn: 'Slow Dead Bug', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w3-s2-b1', POMPE_GENOUX_CONSOL, PLANCHE_CONSOL), - block('deb-w3-s2-b2', BIRD_DOG, SUPERMAN_DYNAMIQUE), - block('deb-w3-s2-b3', - ex('Pompe avec rotation', 'Push-up with Rotation', 'Ouvrir complètement la hanche à la rotation.', 'Fully open hip on rotation.'), - ex('Planche tap épaule', 'Plank Shoulder Tap', 'Résister à la rotation du bassin. Pieds plus écartés pour stabiliser.', 'Resist pelvic rotation. Wider feet for stability.'), - ), - ], - cooldown: { - movements: [ - { name: 'Étirement pectoraux en porte', nameEn: 'Doorway Chest Stretch', duration: 45 }, - { name: 'Étirement grand dorsal', nameEn: 'Lat Stretch', duration: 45 }, - { name: 'Mobilisation cervicale douce', nameEn: 'Gentle Neck Mobilization', duration: 45 }, - ], - totalDuration: 135, - }, - equipment: ['Tapis (optionnel)'], - totalRounds: 24, - totalDuration: 30, - calories: 110, - }, - // 3C — Corps entier - { - id: 'deb-w3-s3', - week: 3, order: 3, - title: 'Corps entier haute intensité', - titleEn: 'High Intensity Full Body', - description: 'Step touch + superman, fente rotation + dead bug, squat jump low + mountain climber.', - descriptionEn: 'Step touch + superman, lunge rotation + dead bug, low squat jump + mountain climber.', - focus: ['Cardio', 'Puissance', 'Endurance musculaire'], - focusEn: ['Cardio', 'Power', 'Muscular Endurance'], - warmup: { - movements: [ - { name: 'Marche rapide bras actifs', nameEn: 'Brisk Walk with Active Arms', duration: 60 }, - { name: 'Squats d\'activation', nameEn: 'Activation Squats', duration: 60 }, - { name: 'Fentes alternées lentes', nameEn: 'Slow Alternating Lunges', duration: 60 }, - { name: 'Sauts légers sur place', nameEn: 'Light Jumps in Place', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w3-s3-b1', STEP_TOUCH_CONSOL, SUPERMAN_CONSOL), - block('deb-w3-s3-b2', FENTE_ROTATION, DEAD_BUG_LENt), - block('deb-w3-s3-b3', SQUAT_JUMP_LOW, MOUNTAIN_CLIMBER_LENt), - ], - cooldown: { - movements: [ - { name: 'Posture de l\'enfant', nameEn: 'Child\'s Pose', duration: 60 }, - { name: 'Pigeon yoga (chaque côté)', nameEn: 'Pigeon Pose (each side)', duration: 45 }, - { name: 'Respiration 4-7-8 × 4 cycles', nameEn: '4-7-8 Breathing × 4 cycles', duration: 60 }, - ], - totalDuration: 165, - }, - equipment: ['Tapis (optionnel)'], - totalRounds: 24, - totalDuration: 30, - calories: 115, - }, - ], -} - -// ─── Week 4: Décharge & consolidation (2 blocs/séance) ────── - -const week4: TabataWeek = { - weekNumber: 4, - title: 'Décharge & consolidation', - titleEn: 'Deload & Consolidation', - description: 'Retour à 2 blocs tabata. Volume réduit de 40%. C\'est pendant le repos que le corps consolide les adaptations.', - descriptionEn: 'Back to 2 tabata blocks. Volume reduced by 40%. The body consolidates adaptations during rest.', - focus: 'Technique parfaite, respiration consciente, ressenti musculaire', - focusEn: 'Perfect technique, conscious breathing, muscle awareness', - isDeload: true, - sessions: [ - // 4A — Membres inférieurs (décharge) - { - id: 'deb-w4-s1', - week: 4, order: 1, - title: 'Membres inférieurs (décharge)', - titleEn: 'Lower Body (Deload)', - description: 'Focus sur la technique parfaite. Respiration coordonnée avec le mouvement.', - descriptionEn: 'Focus on perfect technique. Breathing coordinated with movement.', - focus: ['Technique', 'Respiration', 'Ressenti musculaire'], - focusEn: ['Technique', 'Breathing', 'Muscle Awareness'], - warmup: { - movements: [ - { name: 'Marche sur place', nameEn: 'March in Place', duration: 60 }, - { name: 'Cercles de chevilles et hanches', nameEn: 'Ankle & Hip Circles', duration: 60 }, - { name: 'Squats lents conscience corporelle', nameEn: 'Slow Mindful Squats', duration: 60 }, - { name: 'Respiration diaphragmatique', nameEn: 'Diaphragmatic Breathing', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w4-s1-b1', SQUAT_CONSOLIDATION, PONT_FESSIER_CONSOL), - block('deb-w4-s1-b2', FENTE_AVANT, DEAD_BUG), - ], - cooldown: { - movements: [ - { name: 'Étirement quadriceps debout', nameEn: 'Standing Quad Stretch', duration: 45 }, - { name: 'Étirement ischio-jambiers', nameEn: 'Hamstring Stretch', duration: 45 }, - { name: 'Respiration guidée', nameEn: 'Guided Breathing', duration: 30 }, - ], - totalDuration: 120, - }, - equipment: ['Tapis (optionnel)'], - totalRounds: 16, - totalDuration: 25, - calories: 70, - }, - // 4B — Haut du corps (décharge) - { - id: 'deb-w4-s2', - week: 4, order: 2, - title: 'Haut du corps (décharge)', - titleEn: 'Upper Body (Deload)', - description: 'Qualité sur chaque répétition. Bilan personnel sur les exercices maîtrisés.', - descriptionEn: 'Quality on every rep. Personal assessment of mastered exercises.', - focus: ['Technique', 'Gainage profond', 'Contrôle'], - focusEn: ['Technique', 'Deep Core', 'Control'], - warmup: { - movements: [ - { name: 'Rotations d\'épaules', nameEn: 'Shoulder Rotations', duration: 60 }, - { name: 'Ouvertures de poitrine', nameEn: 'Chest Openers', duration: 60 }, - { name: 'Cat-cow lent', nameEn: 'Slow Cat-Cow', duration: 60 }, - { name: 'Respiration diaphragmatique', nameEn: 'Diaphragmatic Breathing', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w4-s2-b1', POMPE_GENOUX_CONSOL, PLANCHE_CONSOL), - block('deb-w4-s2-b2', BIRD_DOG, SUPERMAN), - ], - cooldown: { - movements: [ - { name: 'Étirement pectoraux', nameEn: 'Chest Stretch', duration: 45 }, - { name: 'Étirement triceps', nameEn: 'Triceps Stretch', duration: 30 }, - { name: 'Étirement cervical', nameEn: 'Neck Stretch', duration: 30 }, - ], - totalDuration: 105, - }, - equipment: ['Tatis (optionnel)'], - totalRounds: 16, - totalDuration: 25, - calories: 65, - }, - // 4C — Corps entier bilan - { - id: 'deb-w4-s3', - week: 4, order: 3, - title: 'Corps entier — Bilan final', - titleEn: 'Full Body — Final Assessment', - description: 'Dernière séance du programme. Focus total sur la qualité. Quels exercices sont devenus faciles ?', - descriptionEn: 'Final session of the program. Total focus on quality. Which exercises have become easy?', - focus: ['Bilan global', 'Autonomie', 'Confiance'], - focusEn: ['Overall Assessment', 'Autonomy', 'Confidence'], - warmup: { - movements: [ - { name: 'Marche active', nameEn: 'Active Walk', duration: 60 }, - { name: 'Mobilisation articulaire complète', nameEn: 'Full Joint Mobilization', duration: 60 }, - { name: 'Squats lents avec respiration', nameEn: 'Slow Squats with Breathing', duration: 60 }, - { name: 'Gainage léger', nameEn: 'Light Core Activation', duration: 60 }, - ], - totalDuration: 240, - }, - blocks: [ - block('deb-w4-s3-b1', SQUAT_CLASSIQUE, STEP_TOUCH), - block('deb-w4-s3-b2', SUPERMAN, DEAD_BUG), - ], - cooldown: { - movements: [ - { name: 'Posture de l\'enfant', nameEn: 'Child\'s Pose', duration: 60 }, - { name: 'Torsion vertébrale (chaque côté)', nameEn: 'Spinal Twist (each side)', duration: 45 }, - { name: 'Savasana + respiration guidée', nameEn: 'Savasana + Guided Breathing', duration: 60 }, - ], - totalDuration: 165, - }, - equipment: ['Tatis (optionnel)'], - totalRounds: 16, - totalDuration: 25, - calories: 68, - }, - ], -} - -// ─── Program Export ───────────────────────────────────────────── - -export const DEBUTANT_PROGRAM: TabataProgram = { - id: 'debutant', - title: 'Débutant', - titleEn: 'Beginner', - description: 'Apprendre le protocole tabata, construire les bases techniques de chaque mouvement fondamental, et terminer 12 séances sans douleur articulaire.', - descriptionEn: 'Learn the tabata protocol, build technical foundations for each fundamental movement, and complete 12 sessions without joint pain.', - tier: 'free', - accentColor: '#00C896', // Energy green - icon: 'seedling', - durationWeeks: 4, - sessionsPerWeek: 3, - totalSessions: 12, - equipment: { - required: [], - optional: ['Tapis de yoga'], - }, - focusAreas: ['Squat', 'Gainage', 'Pompes', 'Équilibre', 'Mobilité'], - focusAreasEn: ['Squat', 'Core', 'Push-ups', 'Balance', 'Mobility'], - principles: [ - 'Zéro impact les 2 premières semaines', - 'La technique avant l\'intensité', - 'Semaine 4 = décharge (volume réduit 40%)', - ], - principlesEn: [ - 'Zero impact for the first 2 weeks', - 'Technique before intensity', - 'Week 4 = deload (40% volume reduction)', - ], - completionCriteria: [ - 'Planche sur avant-bras tenue 30 secondes', - '10 squats propres consécutifs sans douleur', - '5 pompes complètes corps aligné', - 'Aucune douleur articulaire résiduelle', - ], - completionCriteriaEn: [ - 'Hold forearm plank for 30 seconds', - '10 clean consecutive squats without pain', - '5 full push-ups with aligned body', - 'No residual joint pain after sessions', - ], - nextProgramId: 'intermediaire', - weeks: [week1, week2, week3, week4], -} - -/** All sessions flattened for quick lookup */ -export const DEBUTANT_SESSIONS: TabataSession[] = DEBUTANT_PROGRAM.weeks.flatMap(w => w.sessions) diff --git a/src/shared/data/tabata/index.ts b/src/shared/data/tabata/index.ts deleted file mode 100644 index 4238901..0000000 --- a/src/shared/data/tabata/index.ts +++ /dev/null @@ -1,126 +0,0 @@ -/** - * Tabata Programs — Data Access Layer - * Central exports and helper functions for tabata programs - */ - -import type { TabataProgram, TabataProgramId, TabataSession } from '../../types/program' -import type { Workout, Exercise } from '../../types/workout' -import { DEBUTANT_PROGRAM, DEBUTANT_SESSIONS } from './debutant' -import { INTERMEDIAIRE_PROGRAM, INTERMEDIAIRE_SESSIONS } from './intermediaire' -import { AVANCE_PROGRAM, AVANCE_SESSIONS } from './avance' -import { BUREAU_PROGRAM, BUREAU_SESSIONS } from './bureau' - -// ─── Program Registry ────────────────────────────────────────── - -const _PROGRAMS: Record = { - debutant: DEBUTANT_PROGRAM, - intermediaire: INTERMEDIAIRE_PROGRAM, - avance: AVANCE_PROGRAM, - bureau: BUREAU_PROGRAM, -} - -// ─── Program Access ──────────────────────────────────────────── - -export function getTabataProgramById(id: TabataProgramId): TabataProgram | undefined { - return _PROGRAMS[id] -} - -export function getAllTabataPrograms(): TabataProgram[] { - return Object.values(_PROGRAMS).filter(Boolean) as TabataProgram[] -} - -export function getPremiumPrograms(): TabataProgram[] { - return getAllTabataPrograms().filter(p => p.tier === 'premium') -} - -// ─── Session Access ──────────────────────────────────────────── - -/** Get all sessions across all programs */ -export function getAllTabataSessions(): TabataSession[] { - return getAllTabataPrograms().flatMap(p => p.weeks.flatMap(w => w.sessions)) -} - -/** Find a session by ID across all programs */ -export function getTabataSessionById(id: string): TabataSession | undefined { - return getAllTabataSessions().find(s => s.id === id) -} - -/** Get all sessions for a specific program */ -export function getTabataSessionsByProgram(programId: TabataProgramId): TabataSession[] { - const program = getTabataProgramById(programId) - if (!program) return [] - return program.weeks.flatMap(w => w.sessions) -} - -/** Get sessions for a specific week of a program */ -export function getTabataSessionsByWeek(programId: TabataProgramId, weekNumber: number): TabataSession[] { - const program = getTabataProgramById(programId) - if (!program) return [] - const week = program.weeks.find(w => w.weekNumber === weekNumber) - return week?.sessions ?? [] -} - -/** Determine which program a session belongs to */ -export function getSessionProgramId(sessionId: string): TabataProgramId | undefined { - for (const program of getAllTabataPrograms()) { - const found = program.weeks.flatMap(w => w.sessions).find(s => s.id === sessionId) - if (found) return program.id - } - return undefined -} - -/** Check if a session ID belongs to the tabata system */ -export function isTabataSession(sessionId: string): boolean { - return sessionId.startsWith('deb-') || sessionId.startsWith('int-') || - sessionId.startsWith('avc-') || sessionId.startsWith('bur-') -} - -// ─── Adapter: TabataSession → Workout ───────────────────────── - -/** - * Convert a TabataSession's current block to a Workout-compatible object - * for use with the existing player and timer system. - * - * For multi-block sessions, pass blockIndex (default: 0). - * The player will need to handle block progression separately. - */ -export function tabataSessionToWorkoutAdapter( - session: TabataSession, - blockIndex = 0, -): Workout { - const block = session.blocks[blockIndex] - if (!block) throw new Error(`Block ${blockIndex} not found in session ${session.id}`) - - const exercises: Exercise[] = [] - for (let i = 0; i < block.rounds; i++) { - const exercise = i % 2 === 0 ? block.oddExercise : block.evenExercise - exercises.push({ - name: exercise.name, - duration: block.workTime, - }) - } - - return { - id: session.id, - title: `${session.title} — Bloc ${blockIndex + 1}`, - trainerId: 'tabata', - category: 'full-body', - level: 'Beginner', - duration: Math.ceil(session.totalDuration / session.blocks.length) as Workout['duration'], - calories: Math.ceil(session.calories / session.blocks.length), - exercises, - rounds: block.rounds, - prepTime: blockIndex === 0 ? 10 : 60, - workTime: block.workTime, - restTime: block.restTime, - equipment: session.equipment, - musicVibe: 'chill', - } -} - -// ─── Re-exports ──────────────────────────────────────────────── - -export { DEBUTANT_PROGRAM, DEBUTANT_SESSIONS } from './debutant' -export { INTERMEDIAIRE_PROGRAM, INTERMEDIAIRE_SESSIONS } from './intermediaire' -export { AVANCE_PROGRAM, AVANCE_SESSIONS } from './avance' -export { BUREAU_PROGRAM, BUREAU_SESSIONS } from './bureau' diff --git a/src/shared/data/tabata/intermediaire.ts b/src/shared/data/tabata/intermediaire.ts deleted file mode 100644 index 70a07b2..0000000 --- a/src/shared/data/tabata/intermediaire.ts +++ /dev/null @@ -1,609 +0,0 @@ -/** - * Programme Intermédiaire — 4 semaines, 4 séances/semaine - * Source: TabataKine_Guide_Complet.md — Section 3 - * Tier: PREMIUM - */ - -import type { TabataProgram, TabataSession, TabataWeek, TabataBlock, TabataExercise } from '../../types/program' - -const ex = ( - name: string, nameEn: string, - conseil: string, conseilEn: string, - opts?: { modification?: string; modificationEn?: string; progression?: string; progressionEn?: string } -): TabataExercise => ({ name, nameEn, conseil, conseilEn, ...opts }) - -const block = ( - id: string, odd: TabataExercise, even: TabataExercise, - rounds = 8, workTime = 20, restTime = 10, -): TabataBlock => ({ id, oddExercise: odd, evenExercise: even, rounds, workTime, restTime }) - -// ─── Exercises ───────────────────────────────────────────────── - -const SQUAT_JUMP = ex( - 'Squat jump', 'Squat Jump', - 'Descente contrôlée, explosion vers le haut, réception silencieuse avant-pied. Si la réception fait du bruit : réduire la hauteur.', - 'Controlled descent, explode upward, silent forefoot landing. If landing makes noise: reduce height.', -) - -const PONT_UNILAT = ex( - 'Pont fessier unilatéral', 'Single-leg Glute Bridge', - 'Le bassin ne s\'inclined pas du côté de la jambe levée — signe de faiblesse du moyen fessier.', - 'Pelvis should not tilt toward raised leg — indicates gluteus medius weakness.', -) - -const FENTE_SAUTEE = ex( - 'Fente sautée alternée', 'Alternating Jump Lunge', - 'Si douleur antérieure du genou : revenir à la fente marchée. Réception absorbée sur 2–3 secondes.', - 'If anterior knee pain: return to walking lunge. Absorb landing over 2–3 seconds.', -) - -const ISO_SQUAT = ex( - 'Isométrie squat (chaise)', 'Wall Sit', - 'L\'isométrie renforce l\'endurance musculaire sans impact. Excellent pour skieurs et cyclistes.', - 'Isometrics build muscular endurance without impact. Great for skiers and cyclists.', -) - -const STEP_EXPLOSIF = ex( - 'Step-up explosif', 'Explosive Step-up', - 'La descente est aussi importante que la montée. Ne pas sauter en bas.', - 'The descent is as important as the ascent. Don\'t jump down.', -) - -const GLUTE_KICKBACK = ex( - 'Glute kickback à quatre pattes', 'Quadruped Glute Kickback', - 'Ne pas cambrer le bas du dos pour aller plus haut — c\'est la hanche qui travaille, pas les lombaires.', - 'Don\'t arch your lower back to go higher — hip does the work, not the lumbar spine.', -) - -const POMPE_CLASSIQUE = ex( - 'Pompes classiques complètes', 'Full Push-ups', - 'Corps aligné, coudes à 45°, descendre jusqu\'au contact de la poitrine.', - 'Body aligned, elbows at 45°, lower until chest contacts floor.', -) - -const RENEGADE_ROW = ex( - 'Renegade row sans poids', 'Weightless Renegade Row', - 'Gainage total pendant le mouvement. Le bassin ne se balance pas.', - 'Full core engagement throughout. Pelvis doesn\'t sway.', -) - -const POMPE_ROTATION_T = ex( - 'Pompe avec rotation en T', 'T-push-up', - 'Exercice combiné : obliques + dentatés antérieurs + rotateurs d\'épaule. Ouvrir complètement la hanche.', - 'Combined exercise: obliques + serratus anterior + shoulder rotators. Fully open the hip.', -) - -const PLANCHE_TAP = ex( - 'Planche tap épaule', 'Plank Shoulder Tap', - 'La résistance à la rotation du bassin est l\'objectif. Pieds plus écartés pour stabiliser.', - 'Resisting pelvic rotation is the goal. Wider feet for stability.', -) - -const DIPS_CHAISE = ex( - 'Dips sur chaise', 'Chair Dips', - 'Si inconfort à l\'avant de l\'épaule : réduire l\'amplitude. Contre-indiqué si tendinopathie du biceps.', - 'If anterior shoulder discomfort: reduce range. Contraindicated with biceps tendinopathy.', -) - -const SUPERMAN_YWT = ex( - 'Superman en Y·W·T', 'Y-W-T Superman', - 'Travail intense des rhomboïdes et trapèzes inférieurs. Muscles posturaux clés.', - 'Intense work for rhomboids and lower traps. Key postural muscles.', -) - -const BURPEE_MODIFIE = ex( - 'Burpee modifié', 'Modified Burpee', - 'Marcher les pieds en arrière jusqu\'à planche, marcher retour, se relever. Pas de saut.', - 'Walk feet back to plank, walk return, stand up. No jump.', -) - -const MC_RAPIDE = ex( - 'Mountain climber rapide', 'Fast Mountain Climber', - 'Les hanches ne remontent pas au-dessus des épaules. Regard vers le sol.', - 'Hips don\'t rise above shoulders. Eyes toward the floor.', -) - -const SKATERS = ex( - 'Skaters', 'Skaters', - 'Atterrissage sur un pied — demande bonne proprioception de cheville. En cas d\'entorse récente : éviter.', - 'Single-foot landing — requires good ankle proprioception. If recent sprain: avoid.', -) - -const PLANCHE_DOWNDOG = ex( - 'Planche to downward dog', 'Plank to Downward Dog', - 'Tirer les talons vers le sol en V inversé pour étirer les mollets.', - 'Pull heels toward floor in inverted V to stretch calves.', -) - -const HIGH_KNEES = ex( - 'High knees', 'High Knees', - 'Le but est le rythme, pas la hauteur maximale. Les bras pompeurs contribuent à 15% de la dépense.', - 'Focus on rhythm, not max height. Pumping arms contribute 15% of calorie burn.', -) - -const BEAR_CRAWL = ex( - 'Bear crawl sur place', 'Stationary Bear Crawl', - 'Très intense pour le gainage et les épaules. Genoux à 3 cm du sol.', - 'Very intense for core and shoulders. Knees 3cm off the floor.', -) - -const BURPEE_COMPLET = ex( - 'Burpee complet', 'Full Burpee', - 'Ne jamais arrondir violemment le dos sous fatigue.', - 'Never violently round your back under fatigue.', -) - -const HOLLOW_BODY = ex( - 'Hollow body', 'Hollow Body Hold', - 'Gainage profond issu de la gymnastique artistique — le plus efficace pour les abdominaux profonds.', - 'Deep core hold from artistic gymnastics — most effective for deep abs.', -) - -const V_SIT = ex( - 'V-sit hold', 'V-sit Hold', - 'Si douleur lombaire : fléchir légèrement les genoux.', - 'If lower back pain: slightly bend knees.', -) - -const THRUSTER = ex( - 'Thruster', 'Thruster (Bodyweight)', - 'La montée en pression intra-abdominale est importante — expirer lors de la poussée vers le haut.', - 'Intra-abdominal pressure buildup matters — exhale on the upward push.', -) - -const PISTOL_ASSIST = ex( - 'Pistol squat assisté', 'Assisted Pistol Squat', - 'Révélateur des asymétries de force et de mobilité.', - 'Reveals strength and mobility asymmetries.', -) - -const ARCHER_PUSHUP = ex( - 'Archer push-up', 'Archer Push-up', - 'Maintenir l\'alignement corps-bras porteur parfait.', - 'Maintain perfect body-supporting arm alignment.', -) - -// ─── Week 1: Transition avec impacts (3 blocs/séance) ───────── - -const week1: TabataWeek = { - weekNumber: 1, - title: 'Transition avec impacts', - titleEn: 'Transition to Impact', - description: '3 blocs tabata + 1 min récupération entre chaque. Durée totale : ~35 minutes.', - descriptionEn: '3 tabata blocks + 1 min recovery between each. Total: ~35 min.', - focus: 'Introduction de la plyométrie contrôlée, travail unilatéral', - focusEn: 'Introduction to controlled plyometrics, unilateral work', - isDeload: false, - sessions: [ - { - id: 'int-w1-s1', week: 1, order: 1, - title: 'Membres inférieurs plyométriques', titleEn: 'Plyometric Lower Body', - description: 'Squat jump, fente sautée, step-up explosif.', descriptionEn: 'Squat jump, jump lunge, explosive step-up.', - focus: ['Quadriceps', 'Fessiers', 'Puissance'], focusEn: ['Quads', 'Glutes', 'Power'], - warmup: { movements: [ - { name: 'Marche rapide bras actifs', nameEn: 'Brisk Walk Active Arms', duration: 60 }, - { name: 'Squats lents x10', nameEn: 'Slow Squats x10', duration: 60 }, - { name: 'Fentes alternées lentes x8', nameEn: 'Slow Alt Lunges x8', duration: 60 }, - { name: 'Sauts très légers sur place', nameEn: 'Very Light Jumps', duration: 30 }, - { name: 'Hip circles', nameEn: 'Hip Circles', duration: 60 }, - ], totalDuration: 270 }, - blocks: [ - block('int-w1-s1-b1', SQUAT_JUMP, PONT_UNILAT), - block('int-w1-s1-b2', FENTE_SAUTEE, ISO_SQUAT), - block('int-w1-s1-b3', STEP_EXPLOSIF, GLUTE_KICKBACK), - ], - cooldown: { movements: [ - { name: 'Étirement psoas en fente basse', nameEn: 'Low Lunge Psoas Stretch', duration: 60 }, - { name: 'Étirement mollets contre mur', nameEn: 'Wall Calf Stretch', duration: 45 }, - { name: 'Automassage quadriceps', nameEn: 'Self-massage Quads', duration: 60 }, - { name: 'Respiration guidée', nameEn: 'Guided Breathing', duration: 30 }, - ], totalDuration: 195 }, - equipment: ['Marche ou step bas'], totalRounds: 24, totalDuration: 35, calories: 135, - }, - { - id: 'int-w1-s2', week: 1, order: 2, - title: 'Haut du corps & gainage dynamique', titleEn: 'Dynamic Upper Body & Core', - description: 'Pompes classiques, pompes rotation, dips sur chaise.', descriptionEn: 'Full push-ups, T-push-ups, chair dips.', - focus: ['Pectoraux', 'Épaules', 'Triceps'], focusEn: ['Chest', 'Shoulders', 'Triceps'], - warmup: { movements: [ - { name: 'Rotations épaules avec serviette', nameEn: 'Shoulder Rotations with Towel', duration: 60 }, - { name: 'Pompes lentes x8', nameEn: 'Slow Push-ups x8', duration: 60 }, - { name: 'Planche dynamique haute↔basse', nameEn: 'Dynamic Plank High↔Low', duration: 60 }, - { name: 'Dead bug lent', nameEn: 'Slow Dead Bug', duration: 60 }, - ], totalDuration: 240 }, - blocks: [ - block('int-w1-s2-b1', POMPE_CLASSIQUE, RENEGADE_ROW), - block('int-w1-s2-b2', POMPE_ROTATION_T, PLANCHE_TAP), - block('int-w1-s2-b3', DIPS_CHAISE, SUPERMAN_YWT), - ], - cooldown: { movements: [ - { name: 'Étirement pectoraux en porte', nameEn: 'Doorway Chest Stretch', duration: 45 }, - { name: 'Étirement grand dorsal', nameEn: 'Lat Stretch', duration: 45 }, - { name: 'Mobilisation cervicale douce', nameEn: 'Gentle Neck Mobilization', duration: 60 }, - ], totalDuration: 150 }, - equipment: ['Chaise stable'], totalRounds: 24, totalDuration: 35, calories: 125, - }, - { - id: 'int-w1-s3', week: 1, order: 3, - title: 'Corps entier cardio dominant', titleEn: 'Cardio Full Body', - description: 'Burpee modifié, skaters, high knees, bear crawl.', descriptionEn: 'Modified burpee, skaters, high knees, bear crawl.', - focus: ['Cardio', 'Coordination', 'Endurance'], focusEn: ['Cardio', 'Coordination', 'Endurance'], - warmup: { movements: [ - { name: 'Jumping jacks', nameEn: 'Jumping Jacks', duration: 60 }, - { name: 'High knees légers', nameEn: 'Light High Knees', duration: 60 }, - { name: 'Fentes dynamiques', nameEn: 'Dynamic Lunges', duration: 60 }, - { name: 'Cat-cow', nameEn: 'Cat-Cow', duration: 60 }, - ], totalDuration: 240 }, - blocks: [ - block('int-w1-s3-b1', BURPEE_MODIFIE, MC_RAPIDE), - block('int-w1-s3-b2', SKATERS, PLANCHE_DOWNDOG), - block('int-w1-s3-b3', HIGH_KNEES, BEAR_CRAWL), - ], - cooldown: { movements: [ - { name: 'Foam roller mollets', nameEn: 'Foam Roll Calves', duration: 60 }, - { name: 'Pigeon yoga (chaque côté)', nameEn: 'Pigeon Pose (each side)', duration: 45 }, - { name: 'Respiration 4-7-8 × 4', nameEn: '4-7-8 Breathing × 4', duration: 60 }, - ], totalDuration: 165 }, - equipment: [], totalRounds: 24, totalDuration: 35, calories: 140, - }, - { - id: 'int-w1-s4', week: 1, order: 4, - title: 'Mobilité & récupération active', titleEn: 'Active Recovery & Mobility', - description: 'Pas de blocs 20/10. Mobilité articulaire + étirements + respiration guidée.', descriptionEn: 'No 20/10 blocks. Joint mobility + stretching + guided breathing.', - focus: ['Récupération', 'Mobilité', 'Respiration'], focusEn: ['Recovery', 'Mobility', 'Breathing'], - warmup: { movements: [], totalDuration: 0 }, - blocks: [], // Special: no tabata blocks - cooldown: { movements: [], totalDuration: 0 }, - equipment: [], totalRounds: 0, totalDuration: 25, calories: 30, - }, - ], -} - -// ─── Week 2: Montée en densité (4 blocs/séance) ────────────── - -const week2: TabataWeek = { - weekNumber: 2, - title: 'Montée en densité', titleEn: 'Increasing Density', - description: '4 blocs tabata + 1 min récup. Nouveaux: Thruster, Burpee complet, Hollow body.', - descriptionEn: '4 tabata blocks + 1 min recovery. New: Thruster, Full Burpee, Hollow body.', - focus: 'Augmentation du volume, nouveaux exercices composés', - focusEn: 'Volume increase, new compound exercises', - isDeload: false, - sessions: [ - { - id: 'int-w2-s1', week: 2, order: 1, - title: 'Corps entier — Densité', titleEn: 'Full Body — Density', - description: 'Squat jump, fente sautée, thruster, burpee complet.', descriptionEn: 'Squat jump, jump lunge, thruster, full burpee.', - focus: ['Puissance', 'Endurance', 'Composé'], focusEn: ['Power', 'Endurance', 'Compound'], - warmup: { movements: [ - { name: 'Marche rapide bras actifs', nameEn: 'Brisk Walk Active Arms', duration: 60 }, - { name: 'Squats d\'activation x10', nameEn: 'Activation Squats x10', duration: 60 }, - { name: 'Fentes dynamiques x8', nameEn: 'Dynamic Lunges x8', duration: 60 }, - { name: '2 burpees complets', nameEn: '2 Full Burpees', duration: 30 }, - ], totalDuration: 210 }, - blocks: [ - block('int-w2-s1-b1', SQUAT_JUMP, PONT_UNILAT), - block('int-w2-s1-b2', FENTE_SAUTEE, ISO_SQUAT), - block('int-w2-s1-b3', THRUSTER, HOLLOW_BODY), - block('int-w2-s1-b4', BURPEE_COMPLET, V_SIT), - ], - cooldown: { movements: [ - { name: 'Étirement psoas en fente basse', nameEn: 'Low Lunge Psoas Stretch', duration: 60 }, - { name: 'Étirement ischio-jambiers', nameEn: 'Hamstring Stretch', duration: 45 }, - { name: 'Respiration guidée', nameEn: 'Guided Breathing', duration: 30 }, - ], totalDuration: 135 }, - equipment: [], totalRounds: 32, totalDuration: 40, calories: 185, - }, - { - id: 'int-w2-s2', week: 2, order: 2, - title: 'Haut du corps — Densité', titleEn: 'Upper Body — Density', - description: 'Pompes classiques, pompes rotation, dips, archer push-up.', descriptionEn: 'Full push-ups, T-push-ups, dips, archer push-up.', - focus: ['Force', 'Stabilité', 'Endurance'], focusEn: ['Strength', 'Stability', 'Endurance'], - warmup: { movements: [ - { name: 'Rotations épaules', nameEn: 'Shoulder Rotations', duration: 60 }, - { name: 'Pompes lentes x8', nameEn: 'Slow Push-ups x8', duration: 60 }, - { name: 'Planche dynamique', nameEn: 'Dynamic Plank', duration: 60 }, - ], totalDuration: 180 }, - blocks: [ - block('int-w2-s2-b1', POMPE_CLASSIQUE, PLANCHE_TAP), - block('int-w2-s2-b2', POMPE_ROTATION_T, HOLLOW_BODY), - block('int-w2-s2-b3', DIPS_CHAISE, SUPERMAN_YWT), - block('int-w2-s2-b4', ARCHER_PUSHUP, V_SIT), - ], - cooldown: { movements: [ - { name: 'Étirement pectoraux', nameEn: 'Chest Stretch', duration: 45 }, - { name: 'Étirement triceps', nameEn: 'Triceps Stretch', duration: 30 }, - { name: 'Respiration guidée', nameEn: 'Guided Breathing', duration: 30 }, - ], totalDuration: 105 }, - equipment: ['Chaise stable'], totalRounds: 32, totalDuration: 40, calories: 170, - }, - { - id: 'int-w2-s3', week: 2, order: 3, - title: 'Cardio — Densité', titleEn: 'Cardio — Density', - description: 'Burpee complet, skaters, high knees, MC rapide.', descriptionEn: 'Full burpee, skaters, high knees, fast MC.', - focus: ['Cardio', 'Agilité', 'Vitesse'], focusEn: ['Cardio', 'Agility', 'Speed'], - warmup: { movements: [ - { name: 'Jumping jacks', nameEn: 'Jumping Jacks', duration: 60 }, - { name: 'High knees légers', nameEn: 'Light High Knees', duration: 60 }, - { name: 'Squats activation', nameEn: 'Activation Squats', duration: 60 }, - ], totalDuration: 180 }, - blocks: [ - block('int-w2-s3-b1', BURPEE_COMPLET, MC_RAPIDE), - block('int-w2-s3-b2', SKATERS, BEAR_CRAWL), - block('int-w2-s3-b3', HIGH_KNEES, PLANCHE_DOWNDOG), - block('int-w2-s3-b4', BURPEE_MODIFIE, HOLLOW_BODY), - ], - cooldown: { movements: [ - { name: 'Foam roller IT band', nameEn: 'Foam Roll IT Band', duration: 60 }, - { name: 'Pigeon yoga', nameEn: 'Pigeon Pose', duration: 60 }, - { name: 'Respiration 4-7-8', nameEn: '4-7-8 Breathing', duration: 60 }, - ], totalDuration: 180 }, - equipment: [], totalRounds: 32, totalDuration: 40, calories: 195, - }, - { - id: 'int-w2-s4', week: 2, order: 4, - title: 'Force & gainage', titleEn: 'Strength & Core', - description: 'Thruster, pistol squat assisté, archer push-up, hollow body.', descriptionEn: 'Thruster, assisted pistol squat, archer push-up, hollow body.', - focus: ['Force unilatérale', 'Gainage profond'], focusEn: ['Unilateral strength', 'Deep core'], - warmup: { movements: [ - { name: 'Marche active', nameEn: 'Active Walk', duration: 60 }, - { name: 'Squats profonds x8', nameEn: 'Deep Squats x8', duration: 60 }, - { name: 'Pompes x6', nameEn: 'Push-ups x6', duration: 60 }, - { name: 'Dead bug x8', nameEn: 'Dead Bug x8', duration: 60 }, - ], totalDuration: 240 }, - blocks: [ - block('int-w2-s4-b1', THRUSTER, PISTOL_ASSIST), - block('int-w2-s4-b2', ARCHER_PUSHUP, HOLLOW_BODY), - block('int-w2-s4-b3', FENTE_SAUTEE, GLUTE_KICKBACK), - block('int-w2-s4-b4', POMPE_CLASSIQUE, V_SIT), - ], - cooldown: { movements: [ - { name: 'Étirement psoas', nameEn: 'Psoas Stretch', duration: 60 }, - { name: 'Étirement mollets', nameEn: 'Calf Stretch', duration: 45 }, - { name: 'Respiration guidée', nameEn: 'Guided Breathing', duration: 30 }, - ], totalDuration: 135 }, - equipment: [], totalRounds: 32, totalDuration: 40, calories: 175, - }, - ], -} - -// ─── Week 3 & 4 (simplified — full content in production) ───── - -const week3: TabataWeek = { - weekNumber: 3, - title: 'Intensité maximale', titleEn: 'Maximum Intensity', - description: '4 blocs/séance. Exercices signature: Burpee saut latéral, Pistol squat, Archer push-up.', - descriptionEn: '4 blocks/session. Signature moves: Lateral burpee, Pistol squat, Archer push-up.', - focus: 'Intensité maximale, mouvements complexes', - focusEn: 'Maximum intensity, complex movements', - isDeload: false, - sessions: [ - { - id: 'int-w3-s1', week: 3, order: 1, - title: 'Jambes puissance max', titleEn: 'Max Leg Power', - description: 'Squat jump, pistol squat assisté, fente sautée, step-up explosif.', descriptionEn: 'Squat jump, assisted pistol squat, jump lunge, explosive step-up.', - focus: ['Puissance', 'Unilatéral'], focusEn: ['Power', 'Unilateral'], - warmup: { movements: [ - { name: 'Marche rapide', nameEn: 'Brisk Walk', duration: 60 }, - { name: 'Squats x10', nameEn: 'Squats x10', duration: 60 }, - { name: 'Fentes dynamiques', nameEn: 'Dynamic Lunges', duration: 60 }, - ], totalDuration: 180 }, - blocks: [ - block('int-w3-s1-b1', SQUAT_JUMP, PISTOL_ASSIST), - block('int-w3-s1-b2', FENTE_SAUTEE, PONT_UNILAT), - block('int-w3-s1-b3', STEP_EXPLOSIF, ISO_SQUAT), - block('int-w3-s1-b4', THRUSTER, GLUTE_KICKBACK), - ], - cooldown: { movements: [ - { name: 'Étirement psoas', nameEn: 'Psoas Stretch', duration: 60 }, - { name: 'Étirement mollets', nameEn: 'Calf Stretch', duration: 45 }, - { name: 'Respiration', nameEn: 'Breathing', duration: 30 }, - ], totalDuration: 135 }, - equipment: ['Marche/step'], totalRounds: 32, totalDuration: 40, calories: 190, - }, - { - id: 'int-w3-s2', week: 3, order: 2, - title: 'Haut du corps avancé', titleEn: 'Advanced Upper Body', - description: 'Archer push-up, pompe rotation T, dips, pompes classiques.', descriptionEn: 'Archer push-up, T-push-up, dips, full push-ups.', - focus: ['Force', 'Stabilité scapulaire'], focusEn: ['Strength', 'Scapular Stability'], - warmup: { movements: [ - { name: 'Rotations épaules', nameEn: 'Shoulder Rotations', duration: 60 }, - { name: 'Pompes x8', nameEn: 'Push-ups x8', duration: 60 }, - { name: 'Planche dynamique', nameEn: 'Dynamic Plank', duration: 60 }, - ], totalDuration: 180 }, - blocks: [ - block('int-w3-s2-b1', ARCHER_PUSHUP, PLANCHE_TAP), - block('int-w3-s2-b2', POMPE_ROTATION_T, HOLLOW_BODY), - block('int-w3-s2-b3', DIPS_CHAISE, SUPERMAN_YWT), - block('int-w3-s2-b4', POMPE_CLASSIQUE, V_SIT), - ], - cooldown: { movements: [ - { name: 'Étirement pectoraux', nameEn: 'Chest Stretch', duration: 45 }, - { name: 'Étirement triceps', nameEn: 'Triceps Stretch', duration: 30 }, - { name: 'Respiration', nameEn: 'Breathing', duration: 30 }, - ], totalDuration: 105 }, - equipment: ['Chaise'], totalRounds: 32, totalDuration: 40, calories: 180, - }, - { - id: 'int-w3-s3', week: 3, order: 3, - title: 'Cardio extrême', titleEn: 'Extreme Cardio', - description: 'Burpee complet, high knees, skaters, MC rapide.', descriptionEn: 'Full burpee, high knees, skaters, fast MC.', - focus: ['Cardio max', 'Endurance'], focusEn: ['Max cardio', 'Endurance'], - warmup: { movements: [ - { name: 'Jumping jacks', nameEn: 'Jumping Jacks', duration: 60 }, - { name: 'High knees', nameEn: 'High Knees', duration: 60 }, - { name: '2 burpees complets', nameEn: '2 Full Burpees', duration: 30 }, - ], totalDuration: 150 }, - blocks: [ - block('int-w3-s3-b1', BURPEE_COMPLET, MC_RAPIDE), - block('int-w3-s3-b2', HIGH_KNEES, BEAR_CRAWL), - block('int-w3-s3-b3', SKATERS, PLANCHE_DOWNDOG), - block('int-w3-s3-b4', BURPEE_COMPLET, HOLLOW_BODY), - ], - cooldown: { movements: [ - { name: 'Foam roller', nameEn: 'Foam Roll', duration: 60 }, - { name: 'Respiration 4-7-8', nameEn: '4-7-8 Breathing', duration: 60 }, - ], totalDuration: 120 }, - equipment: [], totalRounds: 32, totalDuration: 40, calories: 200, - }, - { - id: 'int-w3-s4', week: 3, order: 4, - title: 'Mix force + cardio', titleEn: 'Strength + Cardio Mix', - description: 'Thruster, squat jump, archer push-up, burpee.', descriptionEn: 'Thruster, squat jump, archer push-up, burpee.', - focus: ['Composé', 'Endurance de force'], focusEn: ['Compound', 'Strength Endurance'], - warmup: { movements: [ - { name: 'Marche active', nameEn: 'Active Walk', duration: 60 }, - { name: 'Squats x8', nameEn: 'Squats x8', duration: 60 }, - { name: 'Pompes x6', nameEn: 'Push-ups x6', duration: 60 }, - ], totalDuration: 180 }, - blocks: [ - block('int-w3-s4-b1', THRUSTER, PISTOL_ASSIST), - block('int-w3-s4-b2', SQUAT_JUMP, FENTE_SAUTEE), - block('int-w3-s4-b3', ARCHER_PUSHUP, V_SIT), - block('int-w3-s4-b4', BURPEE_COMPLET, HOLLOW_BODY), - ], - cooldown: { movements: [ - { name: 'Étirement complet', nameEn: 'Full Stretch', duration: 60 }, - { name: 'Respiration', nameEn: 'Breathing', duration: 30 }, - ], totalDuration: 90 }, - equipment: [], totalRounds: 32, totalDuration: 40, calories: 195, - }, - ], -} - -const week4: TabataWeek = { - weekNumber: 4, - title: 'Décharge & bilan', titleEn: 'Deload & Assessment', - description: 'Retour à 3 blocs. Exercices maîtrisés, focus technique. Tests de fin de programme.', - descriptionEn: 'Back to 3 blocks. Mastered exercises, technique focus. End-of-program tests.', - focus: 'Technique parfaite, récupération, tests', - focusEn: 'Perfect technique, recovery, tests', - isDeload: true, - sessions: [ - { - id: 'int-w4-s1', week: 4, order: 1, - title: 'Jambes (décharge)', titleEn: 'Legs (Deload)', - description: 'Squat jump maîtrisé, fente contrôlée, pont unilatéral.', descriptionEn: 'Controlled squat jump, controlled lunge, single-leg bridge.', - focus: ['Technique', 'Contrôle'], focusEn: ['Technique', 'Control'], - warmup: { movements: [ - { name: 'Marche sur place', nameEn: 'March in Place', duration: 60 }, - { name: 'Squats lents', nameEn: 'Slow Squats', duration: 60 }, - { name: 'Fentes statiques', nameEn: 'Static Lunges', duration: 60 }, - ], totalDuration: 180 }, - blocks: [ - block('int-w4-s1-b1', SQUAT_JUMP, PONT_UNILAT), - block('int-w4-s1-b2', FENTE_SAUTEE, ISO_SQUAT), - block('int-w4-s1-b3', STEP_EXPLOSIF, GLUTE_KICKBACK), - ], - cooldown: { movements: [ - { name: 'Étirement complet jambes', nameEn: 'Full Leg Stretch', duration: 90 }, - { name: 'Respiration', nameEn: 'Breathing', duration: 30 }, - ], totalDuration: 120 }, - equipment: ['Marche/step'], totalRounds: 24, totalDuration: 35, calories: 140, - }, - { - id: 'int-w4-s2', week: 4, order: 2, - title: 'Haut du corps (décharge)', titleEn: 'Upper Body (Deload)', - description: 'Pompes classiques, planche tap, dips modérés.', descriptionEn: 'Full push-ups, shoulder taps, moderate dips.', - focus: ['Qualité', 'Stabilité'], focusEn: ['Quality', 'Stability'], - warmup: { movements: [ - { name: 'Rotations épaules', nameEn: 'Shoulder Rotations', duration: 60 }, - { name: 'Pompes genoux x8', nameEn: 'Knee Push-ups x8', duration: 60 }, - ], totalDuration: 120 }, - blocks: [ - block('int-w4-s2-b1', POMPE_CLASSIQUE, PLANCHE_TAP), - block('int-w4-s2-b2', POMPE_ROTATION_T, SUPERMAN_YWT), - block('int-w4-s2-b3', DIPS_CHAISE, HOLLOW_BODY), - ], - cooldown: { movements: [ - { name: 'Étirement haut du corps', nameEn: 'Upper Body Stretch', duration: 90 }, - { name: 'Respiration', nameEn: 'Breathing', duration: 30 }, - ], totalDuration: 120 }, - equipment: ['Chaise'], totalRounds: 24, totalDuration: 35, calories: 130, - }, - { - id: 'int-w4-s3', week: 4, order: 3, - title: 'Cardio léger + tests', titleEn: 'Light Cardio + Tests', - description: 'Burpee modéré, MC rapide, skaters légers.', descriptionEn: 'Moderate burpee, fast MC, light skaters.', - focus: ['Récupération active', 'Bilan'], focusEn: ['Active Recovery', 'Assessment'], - warmup: { movements: [ - { name: 'Marche active', nameEn: 'Active Walk', duration: 60 }, - { name: 'Mobilisation articulaire', nameEn: 'Joint Mobility', duration: 60 }, - ], totalDuration: 120 }, - blocks: [ - block('int-w4-s3-b1', BURPEE_MODIFIE, MC_RAPIDE), - block('int-w4-s3-b2', SKATERS, PLANCHE_DOWNDOG), - block('int-w4-s3-b3', HIGH_KNEES, BEAR_CRAWL), - ], - cooldown: { movements: [ - { name: 'Étirement complet', nameEn: 'Full Stretch', duration: 90 }, - { name: 'Respiration 4-7-8', nameEn: '4-7-8 Breathing', duration: 60 }, - ], totalDuration: 150 }, - equipment: [], totalRounds: 24, totalDuration: 35, calories: 135, - }, - { - id: 'int-w4-s4', week: 4, order: 4, - title: 'Bilan final', titleEn: 'Final Assessment', - description: 'Tests: planche 60s, burpees 1min, squat jump ×8, asymétrie G/D.', descriptionEn: 'Tests: 60s plank, 1min burpees, 8 rounds squat jump, L/R asymmetry.', - focus: ['Tests de passage', 'Évaluation'], focusEn: ['Passing Tests', 'Assessment'], - warmup: { movements: [ - { name: 'Marche active', nameEn: 'Active Walk', duration: 60 }, - { name: 'Mobilisation complète', nameEn: 'Full Mobility', duration: 60 }, - ], totalDuration: 120 }, - blocks: [ - block('int-w4-s4-b1', THRUSTER, HOLLOW_BODY), - block('int-w4-s4-b2', ARCHER_PUSHUP, V_SIT), - block('int-w4-s4-b3', PISTOL_ASSIST, SUPERMAN_YWT), - ], - cooldown: { movements: [ - { name: 'Savasana + respiration', nameEn: 'Savasana + Breathing', duration: 120 }, - ], totalDuration: 120 }, - equipment: [], totalRounds: 24, totalDuration: 35, calories: 125, - }, - ], -} - -// ─── Export ───────────────────────────────────────────────────── - -export const INTERMEDIAIRE_PROGRAM: TabataProgram = { - id: 'intermediaire', - title: 'Intermédiaire', - titleEn: 'Intermediate', - description: 'Introduire la plyométrie contrôlée, intensifier le travail unilatéral, passer à 4 blocs tabata.', - descriptionEn: 'Introduce controlled plyometrics, intensify unilateral work, progress to 4 tabata blocks.', - tier: 'premium', - accentColor: '#85C7F2', - icon: 'flame', - durationWeeks: 4, - sessionsPerWeek: 4, - totalSessions: 16, - equipment: { required: [], optional: ['Marche ou step bas', 'Chaise stable', 'Foam roller'] }, - focusAreas: ['Plyométrie', 'Gainage dynamique', 'Burpees', 'Force unilatérale'], - focusAreasEn: ['Plyometrics', 'Dynamic Core', 'Burpees', 'Unilateral Strength'], - principles: [ - 'Réception silencieuse sur avant-pied', - 'Ne jamais faire 2 séances intenses consécutives', - 'La fatigue neurologique = réduire d\'une séance', - ], - principlesEn: [ - 'Silent forefoot landing', - 'Never do 2 intense sessions back-to-back', - 'Neurological fatigue = reduce by one session', - ], - completionCriteria: [ - 'Planche avant-bras 60 secondes', - '12-15 burpees en 1 minute', - 'Squat jump ×8 rounds rythme maintenu', - 'Asymétrie G/D < 20% au pistol squat', - ], - completionCriteriaEn: [ - '60-second forearm plank', - '12-15 burpees in 1 minute', - '8-round squat jump maintaining pace', - 'L/R asymmetry < 20% on pistol squat', - ], - nextProgramId: 'avance', - weeks: [week1, week2, week3, week4], -} - -export const INTERMEDIAIRE_SESSIONS: TabataSession[] = INTERMEDIAIRE_PROGRAM.weeks.flatMap(w => w.sessions) diff --git a/src/shared/data/trainers.ts b/src/shared/data/trainers.ts deleted file mode 100644 index 63cd2a8..0000000 --- a/src/shared/data/trainers.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * TabataFit Trainer Data - * 1 male + 1 female trainer - */ - -import { Trainer } from '../types' - -export const TRAINERS: Trainer[] = [ - { - id: 'felia', - name: 'Félia', - gender: 'female', - specialty: 'Core', - color: '#00C896', - workoutCount: 15, - }, - { - id: 'felix', - name: 'Félix', - gender: 'male', - specialty: 'Strength', - color: '#FFD60A', - workoutCount: 15, - }, -] diff --git a/src/shared/data/workouts.ts b/src/shared/data/workouts.ts deleted file mode 100644 index 9202016..0000000 --- a/src/shared/data/workouts.ts +++ /dev/null @@ -1,1084 +0,0 @@ -/** - * TabataFit Workout Data - * 50 workouts across 5 categories, 4 durations, 3 levels, 2 trainers - */ - -import { Workout } from '../types' - -export const WORKOUTS: Workout[] = [ - // ═══════════════════════════════════════════════════════════════════════════ - // FULL BODY (10 workouts) - // ═══════════════════════════════════════════════════════════════════════════ - { - id: '1', - title: 'Full Body Ignite', - trainerId: 'felia', - category: 'full-body', - level: 'Beginner', - duration: 4, - calories: 45, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required', 'Yoga mat optional'], - musicVibe: 'electronic', - videoUrl: 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8', - exercises: [ - { name: 'Jumping Jacks', duration: 20 }, - { name: 'Squats', duration: 20 }, - { name: 'Push-ups', duration: 20 }, - { name: 'High Knees', duration: 20 }, - ], - isFeatured: true, - }, - { - id: '2', - title: 'Total Body Blast', - trainerId: 'felix', - category: 'full-body', - level: 'Intermediate', - duration: 8, - calories: 90, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Dumbbells optional'], - musicVibe: 'hip-hop', - videoUrl: 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_16x9/bipbop_16x9_variant.m3u8', - exercises: [ - { name: 'Burpees', duration: 20 }, - { name: 'Lunges', duration: 20 }, - { name: 'Push-up to Row', duration: 20 }, - { name: 'Mountain Climbers', duration: 20 }, - ], - }, - { - id: '3', - title: 'Power Surge', - trainerId: 'felix', - category: 'full-body', - level: 'Advanced', - duration: 12, - calories: 140, - rounds: 24, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Kettlebell recommended'], - musicVibe: 'rock', - exercises: [ - { name: 'Thrusters', duration: 20 }, - { name: 'Box Jumps', duration: 20 }, - { name: 'Renegade Rows', duration: 20 }, - { name: 'Tuck Jumps', duration: 20 }, - ], - }, - { - id: '4', - title: 'Morning Wake-Up', - trainerId: 'felia', - category: 'full-body', - level: 'Beginner', - duration: 4, - calories: 40, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'pop', - exercises: [ - { name: 'Arm Circles', duration: 20 }, - { name: 'Bodyweight Squats', duration: 20 }, - { name: 'Knee Push-ups', duration: 20 }, - { name: 'Marching in Place', duration: 20 }, - ], - }, - { - id: '5', - title: 'Endurance Builder', - trainerId: 'felix', - category: 'full-body', - level: 'Advanced', - duration: 20, - calories: 220, - rounds: 40, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Dumbbells', 'Yoga mat'], - musicVibe: 'electronic', - exercises: [ - { name: 'Devil Press', duration: 20 }, - { name: 'Squat Jumps', duration: 20 }, - { name: 'Push-up Burpees', duration: 20 }, - { name: 'Plank Jacks', duration: 20 }, - ], - }, - { - id: '6', - title: 'Quick Burn', - trainerId: 'felia', - category: 'full-body', - level: 'Beginner', - duration: 4, - calories: 42, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'pop', - exercises: [ - { name: 'Star Jumps', duration: 20 }, - { name: 'Wall Sit', duration: 20 }, - { name: 'Tricep Dips', duration: 20 }, - { name: 'Butt Kicks', duration: 20 }, - ], - }, - { - id: '7', - title: 'Functional Flow', - trainerId: 'felia', - category: 'full-body', - level: 'Intermediate', - duration: 8, - calories: 85, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Resistance band optional'], - musicVibe: 'chill', - exercises: [ - { name: 'Inchworms', duration: 20 }, - { name: 'Curtsy Lunges', duration: 20 }, - { name: 'Bear Crawls', duration: 20 }, - { name: 'Squat Pulses', duration: 20 }, - ], - }, - { - id: '8', - title: 'Athletic Power', - trainerId: 'felix', - category: 'full-body', - level: 'Advanced', - duration: 12, - calories: 145, - rounds: 24, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Medicine ball'], - musicVibe: 'rock', - exercises: [ - { name: 'Clean & Press', duration: 20 }, - { name: 'Lateral Bounds', duration: 20 }, - { name: 'Slam Ball', duration: 20 }, - { name: 'Sprawls', duration: 20 }, - ], - }, - { - id: '9', - title: 'Sweat Session', - trainerId: 'felia', - category: 'full-body', - level: 'Intermediate', - duration: 8, - calories: 88, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'electronic', - exercises: [ - { name: 'Jumping Lunges', duration: 20 }, - { name: 'Push-up to T', duration: 20 }, - { name: 'Speed Skaters', duration: 20 }, - { name: 'Plank Shoulder Taps', duration: 20 }, - ], - }, - { - id: '10', - title: 'Total Tone', - trainerId: 'felia', - category: 'full-body', - level: 'Beginner', - duration: 4, - calories: 38, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'pop', - exercises: [ - { name: 'Side Lunges', duration: 20 }, - { name: 'Diamond Push-ups', duration: 20 }, - { name: 'Glute Bridges', duration: 20 }, - { name: 'Toe Touches', duration: 20 }, - ], - }, - - // ═══════════════════════════════════════════════════════════════════════════ - // CORE (10 workouts) - // ═══════════════════════════════════════════════════════════════════════════ - { - id: '11', - title: 'Core Crusher', - trainerId: 'felia', - category: 'core', - level: 'Intermediate', - duration: 4, - calories: 38, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Yoga mat'], - musicVibe: 'electronic', - videoUrl: 'https://devstreaming-cdn.apple.com/videos/streaming/examples/adv_dv_atmos/main.m3u8', - exercises: [ - { name: 'Crunches', duration: 20 }, - { name: 'Russian Twists', duration: 20 }, - { name: 'Leg Raises', duration: 20 }, - { name: 'Plank Hold', duration: 20 }, - ], - }, - { - id: '12', - title: 'Ab Shredder', - trainerId: 'felia', - category: 'core', - level: 'Advanced', - duration: 8, - calories: 75, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Yoga mat'], - musicVibe: 'hip-hop', - exercises: [ - { name: 'V-Ups', duration: 20 }, - { name: 'Bicycle Crunches', duration: 20 }, - { name: 'Dragon Flags', duration: 20 }, - { name: 'Flutter Kicks', duration: 20 }, - ], - }, - { - id: '13', - title: 'Core Foundations', - trainerId: 'felia', - category: 'core', - level: 'Beginner', - duration: 4, - calories: 32, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Yoga mat'], - musicVibe: 'chill', - exercises: [ - { name: 'Dead Bug', duration: 20 }, - { name: 'Bird Dog', duration: 20 }, - { name: 'Side Plank (L)', duration: 20 }, - { name: 'Side Plank (R)', duration: 20 }, - ], - }, - { - id: '14', - title: 'Oblique Inferno', - trainerId: 'felix', - category: 'core', - level: 'Intermediate', - duration: 8, - calories: 72, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Yoga mat', 'Dumbbell optional'], - musicVibe: 'rock', - exercises: [ - { name: 'Woodchoppers', duration: 20 }, - { name: 'Side Crunches', duration: 20 }, - { name: 'Windshield Wipers', duration: 20 }, - { name: 'Plank Hip Dips', duration: 20 }, - ], - }, - { - id: '15', - title: 'Core Endurance', - trainerId: 'felia', - category: 'core', - level: 'Advanced', - duration: 12, - calories: 110, - rounds: 24, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Yoga mat', 'Medicine ball'], - musicVibe: 'electronic', - exercises: [ - { name: 'Hollow Body Hold', duration: 20 }, - { name: 'Turkish Get-ups', duration: 20 }, - { name: 'Ab Rollouts', duration: 20 }, - { name: 'Pallof Press', duration: 20 }, - ], - }, - { - id: '16', - title: 'Gentle Core', - trainerId: 'felia', - category: 'core', - level: 'Beginner', - duration: 4, - calories: 28, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Yoga mat'], - musicVibe: 'chill', - exercises: [ - { name: 'Pelvic Tilts', duration: 20 }, - { name: 'Modified Crunches', duration: 20 }, - { name: 'Supine Leg March', duration: 20 }, - { name: 'Cat-Cow', duration: 20 }, - ], - }, - { - id: '17', - title: 'Core Power', - trainerId: 'felix', - category: 'core', - level: 'Intermediate', - duration: 4, - calories: 40, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'hip-hop', - exercises: [ - { name: 'Mountain Climbers', duration: 20 }, - { name: 'Plank to Push-up', duration: 20 }, - { name: 'Reverse Crunches', duration: 20 }, - { name: 'Bear Hold', duration: 20 }, - ], - }, - { - id: '18', - title: '360 Core', - trainerId: 'felix', - category: 'core', - level: 'Advanced', - duration: 8, - calories: 78, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Yoga mat'], - musicVibe: 'electronic', - exercises: [ - { name: 'L-Sits', duration: 20 }, - { name: 'Dragon Flag Negatives', duration: 20 }, - { name: 'Hanging Knee Raises', duration: 20 }, - { name: 'Plank Walkouts', duration: 20 }, - ], - }, - { - id: '19', - title: 'Core Stability', - trainerId: 'felia', - category: 'core', - level: 'Beginner', - duration: 4, - calories: 30, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Yoga mat'], - musicVibe: 'chill', - exercises: [ - { name: 'Forearm Plank', duration: 20 }, - { name: 'Slow Bicycle', duration: 20 }, - { name: 'Glute Bridge March', duration: 20 }, - { name: 'Prone Cobra', duration: 20 }, - ], - }, - { - id: '20', - title: 'Core Marathon', - trainerId: 'felia', - category: 'core', - level: 'Advanced', - duration: 20, - calories: 180, - rounds: 40, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Yoga mat', 'Stability ball'], - musicVibe: 'electronic', - exercises: [ - { name: 'Stir the Pot', duration: 20 }, - { name: 'Ab Wheel Rollout', duration: 20 }, - { name: 'Hanging Leg Raises', duration: 20 }, - { name: 'Dragon Flags', duration: 20 }, - ], - }, - - // ═══════════════════════════════════════════════════════════════════════════ - // UPPER BODY (10 workouts) - // ═══════════════════════════════════════════════════════════════════════════ - { - id: '21', - title: 'Upper Body Blitz', - trainerId: 'felix', - category: 'upper-body', - level: 'Intermediate', - duration: 8, - calories: 82, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Dumbbells'], - musicVibe: 'rock', - exercises: [ - { name: 'Push-ups', duration: 20 }, - { name: 'Dumbbell Rows', duration: 20 }, - { name: 'Shoulder Press', duration: 20 }, - { name: 'Bicep Curls', duration: 20 }, - ], - }, - { - id: '22', - title: 'Arm Sculptor', - trainerId: 'felix', - category: 'upper-body', - level: 'Beginner', - duration: 4, - calories: 35, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Light dumbbells'], - musicVibe: 'pop', - exercises: [ - { name: 'Bicep Curls', duration: 20 }, - { name: 'Tricep Extensions', duration: 20 }, - { name: 'Lateral Raises', duration: 20 }, - { name: 'Front Raises', duration: 20 }, - ], - }, - { - id: '23', - title: 'Push-Up Mastery', - trainerId: 'felia', - category: 'upper-body', - level: 'Intermediate', - duration: 4, - calories: 42, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'electronic', - exercises: [ - { name: 'Wide Push-ups', duration: 20 }, - { name: 'Diamond Push-ups', duration: 20 }, - { name: 'Decline Push-ups', duration: 20 }, - { name: 'Explosive Push-ups', duration: 20 }, - ], - }, - { - id: '24', - title: 'Shoulder Shredder', - trainerId: 'felix', - category: 'upper-body', - level: 'Advanced', - duration: 8, - calories: 88, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Dumbbells', 'Resistance band'], - musicVibe: 'rock', - exercises: [ - { name: 'Arnold Press', duration: 20 }, - { name: 'Upright Rows', duration: 20 }, - { name: 'Face Pulls', duration: 20 }, - { name: 'Handstand Hold', duration: 20 }, - ], - }, - { - id: '25', - title: 'Chest & Back', - trainerId: 'felix', - category: 'upper-body', - level: 'Intermediate', - duration: 12, - calories: 120, - rounds: 24, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Dumbbells', 'Pull-up bar'], - musicVibe: 'hip-hop', - exercises: [ - { name: 'Chest Press', duration: 20 }, - { name: 'Bent Over Rows', duration: 20 }, - { name: 'Chest Flyes', duration: 20 }, - { name: 'Pull-ups', duration: 20 }, - ], - }, - { - id: '26', - title: 'Bodyweight Upper', - trainerId: 'felia', - category: 'upper-body', - level: 'Beginner', - duration: 4, - calories: 34, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'pop', - exercises: [ - { name: 'Knee Push-ups', duration: 20 }, - { name: 'Arm Circles', duration: 20 }, - { name: 'Tricep Dips (Chair)', duration: 20 }, - { name: 'Plank Shoulder Taps', duration: 20 }, - ], - }, - { - id: '27', - title: 'Strength Tabata', - trainerId: 'felix', - category: 'upper-body', - level: 'Advanced', - duration: 12, - calories: 130, - rounds: 24, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Dumbbells', 'Kettlebell'], - musicVibe: 'rock', - exercises: [ - { name: 'Clean & Jerk', duration: 20 }, - { name: 'Renegade Rows', duration: 20 }, - { name: 'Turkish Get-up', duration: 20 }, - { name: 'Overhead Press', duration: 20 }, - ], - }, - { - id: '28', - title: 'Tone & Define', - trainerId: 'felia', - category: 'upper-body', - level: 'Beginner', - duration: 4, - calories: 32, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Light dumbbells'], - musicVibe: 'chill', - exercises: [ - { name: 'Hammer Curls', duration: 20 }, - { name: 'Overhead Tricep', duration: 20 }, - { name: 'Lateral Raises', duration: 20 }, - { name: 'Reverse Flyes', duration: 20 }, - ], - }, - { - id: '29', - title: 'Power Arms', - trainerId: 'felix', - category: 'upper-body', - level: 'Intermediate', - duration: 8, - calories: 80, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Dumbbells'], - musicVibe: 'hip-hop', - exercises: [ - { name: 'Concentration Curls', duration: 20 }, - { name: 'Skull Crushers', duration: 20 }, - { name: 'Zottman Curls', duration: 20 }, - { name: 'Dips', duration: 20 }, - ], - }, - { - id: '30', - title: 'Upper Endurance', - trainerId: 'felix', - category: 'upper-body', - level: 'Advanced', - duration: 20, - calories: 200, - rounds: 40, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Full gym setup'], - musicVibe: 'rock', - exercises: [ - { name: 'Barbell Press', duration: 20 }, - { name: 'Pull-ups', duration: 20 }, - { name: 'Dumbbell Snatch', duration: 20 }, - { name: 'Plyo Push-ups', duration: 20 }, - ], - }, - - // ═══════════════════════════════════════════════════════════════════════════ - // LOWER BODY (10 workouts) - // ═══════════════════════════════════════════════════════════════════════════ - { - id: '31', - title: 'Lower Body Burn', - trainerId: 'felia', - category: 'lower-body', - level: 'Beginner', - duration: 4, - calories: 44, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'pop', - exercises: [ - { name: 'Squats', duration: 20 }, - { name: 'Lunges', duration: 20 }, - { name: 'Glute Bridges', duration: 20 }, - { name: 'Calf Raises', duration: 20 }, - ], - }, - { - id: '32', - title: 'Leg Day Tabata', - trainerId: 'felix', - category: 'lower-body', - level: 'Intermediate', - duration: 8, - calories: 92, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Dumbbells optional'], - musicVibe: 'hip-hop', - exercises: [ - { name: 'Jump Squats', duration: 20 }, - { name: 'Walking Lunges', duration: 20 }, - { name: 'Step-ups', duration: 20 }, - { name: 'Wall Sit', duration: 20 }, - ], - }, - { - id: '33', - title: 'Glute Activator', - trainerId: 'felia', - category: 'lower-body', - level: 'Beginner', - duration: 4, - calories: 36, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Resistance band optional'], - musicVibe: 'pop', - exercises: [ - { name: 'Glute Bridges', duration: 20 }, - { name: 'Donkey Kicks', duration: 20 }, - { name: 'Fire Hydrants', duration: 20 }, - { name: 'Clamshells', duration: 20 }, - ], - }, - { - id: '34', - title: 'Explosive Legs', - trainerId: 'felix', - category: 'lower-body', - level: 'Advanced', - duration: 8, - calories: 98, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Box or step'], - musicVibe: 'electronic', - exercises: [ - { name: 'Box Jumps', duration: 20 }, - { name: 'Pistol Squats', duration: 20 }, - { name: 'Jumping Lunges', duration: 20 }, - { name: 'Broad Jumps', duration: 20 }, - ], - }, - { - id: '35', - title: 'Squat Challenge', - trainerId: 'felix', - category: 'lower-body', - level: 'Intermediate', - duration: 4, - calories: 46, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'rock', - exercises: [ - { name: 'Goblet Squats', duration: 20 }, - { name: 'Sumo Squats', duration: 20 }, - { name: 'Pulse Squats', duration: 20 }, - { name: 'Squat Jumps', duration: 20 }, - ], - }, - { - id: '36', - title: 'Lower Power', - trainerId: 'felix', - category: 'lower-body', - level: 'Advanced', - duration: 12, - calories: 150, - rounds: 24, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Barbell', 'Dumbbells'], - musicVibe: 'rock', - exercises: [ - { name: 'Front Squats', duration: 20 }, - { name: 'Romanian Deadlifts', duration: 20 }, - { name: 'Split Squats', duration: 20 }, - { name: 'Power Cleans', duration: 20 }, - ], - }, - { - id: '37', - title: 'Knee-Friendly Legs', - trainerId: 'felia', - category: 'lower-body', - level: 'Beginner', - duration: 4, - calories: 34, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Chair for balance'], - musicVibe: 'chill', - exercises: [ - { name: 'Glute Bridges', duration: 20 }, - { name: 'Standing Kickbacks', duration: 20 }, - { name: 'Side Leg Raises', duration: 20 }, - { name: 'Calf Raises', duration: 20 }, - ], - }, - { - id: '38', - title: 'Sprint Tabata', - trainerId: 'felix', - category: 'lower-body', - level: 'Advanced', - duration: 4, - calories: 52, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'electronic', - exercises: [ - { name: 'High Knees Sprint', duration: 20 }, - { name: 'Lateral Shuffles', duration: 20 }, - { name: 'Tuck Jumps', duration: 20 }, - { name: 'Butt Kick Sprint', duration: 20 }, - ], - }, - { - id: '39', - title: 'Legs & Glutes', - trainerId: 'felia', - category: 'lower-body', - level: 'Intermediate', - duration: 12, - calories: 125, - rounds: 24, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Resistance band', 'Dumbbells'], - musicVibe: 'pop', - exercises: [ - { name: 'Banded Squats', duration: 20 }, - { name: 'Hip Thrusts', duration: 20 }, - { name: 'Lateral Band Walks', duration: 20 }, - { name: 'Step-back Lunges', duration: 20 }, - ], - }, - { - id: '40', - title: 'Leg Day Marathon', - trainerId: 'felix', - category: 'lower-body', - level: 'Advanced', - duration: 20, - calories: 210, - rounds: 40, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Full gym setup'], - musicVibe: 'rock', - exercises: [ - { name: 'Back Squats', duration: 20 }, - { name: 'Leg Press Jumps', duration: 20 }, - { name: 'Walking Lunges', duration: 20 }, - { name: 'Box Jump Overs', duration: 20 }, - ], - }, - - // ═══════════════════════════════════════════════════════════════════════════ - // CARDIO (10 workouts) - // ═══════════════════════════════════════════════════════════════════════════ - { - id: '41', - title: 'HIIT Extreme', - trainerId: 'felix', - category: 'cardio', - level: 'Advanced', - duration: 8, - calories: 95, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'electronic', - videoUrl: 'https://devstreaming-cdn.apple.com/videos/streaming/examples/bipbop_4x3/bipbop_4x3_variant.m3u8', - exercises: [ - { name: 'Burpees', duration: 20 }, - { name: 'Mountain Climbers', duration: 20 }, - { name: 'Jump Squats', duration: 20 }, - { name: 'High Knees', duration: 20 }, - ], - }, - { - id: '42', - title: 'Cardio Blast', - trainerId: 'felix', - category: 'cardio', - level: 'Intermediate', - duration: 4, - calories: 48, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'electronic', - exercises: [ - { name: 'Jumping Jacks', duration: 20 }, - { name: 'Speed Skaters', duration: 20 }, - { name: 'Butt Kicks', duration: 20 }, - { name: 'Star Jumps', duration: 20 }, - ], - }, - { - id: '43', - title: 'Dance Cardio', - trainerId: 'felia', - category: 'cardio', - level: 'Beginner', - duration: 4, - calories: 40, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'pop', - videoUrl: 'https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_ts/master.m3u8', - exercises: [ - { name: 'Grapevine', duration: 20 }, - { name: 'Step Touch', duration: 20 }, - { name: 'Cha-Cha Slide', duration: 20 }, - { name: 'Jumping Jacks', duration: 20 }, - ], - }, - { - id: '44', - title: 'Fat Burn Express', - trainerId: 'felix', - category: 'cardio', - level: 'Intermediate', - duration: 8, - calories: 88, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Jump rope optional'], - musicVibe: 'hip-hop', - exercises: [ - { name: 'Jump Rope', duration: 20 }, - { name: 'Burpees', duration: 20 }, - { name: 'Mountain Climbers', duration: 20 }, - { name: 'Tuck Jumps', duration: 20 }, - ], - }, - { - id: '45', - title: 'Low Impact Cardio', - trainerId: 'felia', - category: 'cardio', - level: 'Beginner', - duration: 4, - calories: 30, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'chill', - exercises: [ - { name: 'Marching in Place', duration: 20 }, - { name: 'Step Touches', duration: 20 }, - { name: 'Boxing Punches', duration: 20 }, - { name: 'Side Steps', duration: 20 }, - ], - }, - { - id: '46', - title: 'Cardio Inferno', - trainerId: 'felix', - category: 'cardio', - level: 'Advanced', - duration: 12, - calories: 155, - rounds: 24, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'electronic', - exercises: [ - { name: 'Burpee Tuck Jumps', duration: 20 }, - { name: 'Sprint in Place', duration: 20 }, - { name: 'Plyo Lunges', duration: 20 }, - { name: 'Lateral Bounds', duration: 20 }, - ], - }, - { - id: '47', - title: 'Sunrise Flow', - trainerId: 'felia', - category: 'cardio', - level: 'Beginner', - duration: 4, - calories: 28, - rounds: 8, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'chill', - exercises: [ - { name: 'Sun Salutation', duration: 20 }, - { name: 'Light Jog', duration: 20 }, - { name: 'Arm Swings', duration: 20 }, - { name: 'Gentle Twists', duration: 20 }, - ], - }, - { - id: '48', - title: 'Power Hour', - trainerId: 'felix', - category: 'cardio', - level: 'Intermediate', - duration: 12, - calories: 130, - rounds: 24, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['No equipment required'], - musicVibe: 'hip-hop', - exercises: [ - { name: 'Burpees', duration: 20 }, - { name: 'Speed Skaters', duration: 20 }, - { name: 'High Knees', duration: 20 }, - { name: 'Plank Jacks', duration: 20 }, - ], - }, - { - id: '49', - title: 'Deep Stretch', - trainerId: 'felia', - category: 'cardio', - level: 'Beginner', - duration: 8, - calories: 35, - rounds: 16, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Yoga mat'], - musicVibe: 'chill', - exercises: [ - { name: 'Forward Fold', duration: 20 }, - { name: 'Pigeon Pose', duration: 20 }, - { name: 'Spinal Twist', duration: 20 }, - { name: 'Butterfly Stretch', duration: 20 }, - ], - }, - { - id: '50', - title: 'Cardio Marathon', - trainerId: 'felix', - category: 'cardio', - level: 'Advanced', - duration: 20, - calories: 240, - rounds: 40, - prepTime: 10, - workTime: 20, - restTime: 10, - equipment: ['Jump rope', 'Box or step'], - musicVibe: 'electronic', - exercises: [ - { name: 'Double Unders', duration: 20 }, - { name: 'Box Jump Burpees', duration: 20 }, - { name: 'Sprint Intervals', duration: 20 }, - { name: 'Lateral Bounds', duration: 20 }, - ], - }, -] diff --git a/src/shared/hooks/useSupabaseData.ts b/src/shared/hooks/useSupabaseData.ts deleted file mode 100644 index b9c1443..0000000 --- a/src/shared/hooks/useSupabaseData.ts +++ /dev/null @@ -1,151 +0,0 @@ -/** - * React Query Data Hooks - * Replaces manual state management with React Query for better caching and performance - */ - -import { useQuery } from '@tanstack/react-query' -import { dataService } from '../data/dataService' -import type { Workout, Trainer, Collection, Program } from '../types' - -// Query Keys -export const queryKeys = { - workouts: 'workouts', - workout: (id: string) => ['workouts', id], - workoutsByCategory: (category: string) => ['workouts', 'category', category], - workoutsByTrainer: (trainerId: string) => ['workouts', 'trainer', trainerId], - featuredWorkouts: ['workouts', 'featured'], - trainers: 'trainers', - trainer: (id: string) => ['trainers', id], - collections: 'collections', - collection: (id: string) => ['collections', id], - programs: 'programs', -} as const - -/** - * Hook to fetch all workouts - */ -export function useWorkouts() { - return useQuery({ - queryKey: [queryKeys.workouts], - queryFn: () => dataService.getAllWorkouts(), - staleTime: 1000 * 60 * 5, // 5 minutes - }) -} - -/** - * Hook to fetch single workout - */ -export function useWorkout(id: string | undefined) { - return useQuery({ - queryKey: queryKeys.workout(id || ''), - queryFn: () => dataService.getWorkoutById(id!), - enabled: !!id, - staleTime: 1000 * 60 * 5, - }) -} - -/** - * Hook to fetch workouts by category - */ -export function useWorkoutsByCategory(category: string) { - return useQuery({ - queryKey: queryKeys.workoutsByCategory(category), - queryFn: () => dataService.getWorkoutsByCategory(category), - enabled: !!category, - staleTime: 1000 * 60 * 5, - }) -} - -/** - * Hook to fetch workouts by trainer - */ -export function useWorkoutsByTrainer(trainerId: string) { - return useQuery({ - queryKey: queryKeys.workoutsByTrainer(trainerId), - queryFn: () => dataService.getWorkoutsByTrainer(trainerId), - enabled: !!trainerId, - staleTime: 1000 * 60 * 5, - }) -} - -/** - * Hook to fetch featured workouts - */ -export function useFeaturedWorkouts() { - return useQuery({ - queryKey: queryKeys.featuredWorkouts, - queryFn: () => dataService.getFeaturedWorkouts(), - staleTime: 1000 * 60 * 5, - }) -} - -/** - * Hook to fetch popular workouts (uses recent workouts as proxy) - */ -export function usePopularWorkouts(count: number = 8) { - return useQuery({ - queryKey: ['workouts', 'popular', count], - queryFn: async () => { - const allWorkouts = await dataService.getAllWorkouts() - return allWorkouts.slice(0, count) - }, - staleTime: 1000 * 60 * 5, - }) -} - -/** - * Hook to fetch all trainers - */ -export function useTrainers() { - return useQuery({ - queryKey: [queryKeys.trainers], - queryFn: () => dataService.getAllTrainers(), - staleTime: 1000 * 60 * 5, - }) -} - -/** - * Hook to fetch single trainer - */ -export function useTrainer(id: string | undefined) { - return useQuery({ - queryKey: queryKeys.trainer(id || ''), - queryFn: () => dataService.getTrainerById(id!), - enabled: !!id, - staleTime: 1000 * 60 * 5, - }) -} - -/** - * Hook to fetch all collections - */ -export function useCollections() { - return useQuery({ - queryKey: [queryKeys.collections], - queryFn: () => dataService.getAllCollections(), - staleTime: 1000 * 60 * 5, - }) -} - -/** - * Hook to fetch single collection - */ -export function useCollection(id: string | undefined) { - return useQuery({ - queryKey: queryKeys.collection(id || ''), - queryFn: () => dataService.getCollectionById(id!), - enabled: !!id, - staleTime: 1000 * 60 * 5, - }) -} - -/** - * Hook to fetch all programs - */ -export function usePrograms() { - return useQuery({ - queryKey: [queryKeys.programs], - queryFn: () => dataService.getAllPrograms(), - staleTime: 1000 * 60 * 5, - }) -} \ No newline at end of file diff --git a/src/shared/stores/activityStore.ts b/src/shared/stores/activityStore.ts deleted file mode 100644 index 0fe504e..0000000 --- a/src/shared/stores/activityStore.ts +++ /dev/null @@ -1,135 +0,0 @@ -/** - * TabataFit Activity Store - * Workout history, streak, stats — persisted via AsyncStorage - * Added: Sync integration for personalized programs - */ - -import { create } from 'zustand' -import { persist, createJSONStorage } from 'zustand/middleware' -import AsyncStorage from '@react-native-async-storage/async-storage' -import type { WorkoutResult, DayActivity } from '../types' -import { useUserStore } from './userStore' -import { syncWorkoutSession } from '@/src/shared/services/sync' - -interface ActivityState { - history: WorkoutResult[] - streak: { current: number; longest: number } - - // Actions - addWorkoutResult: (result: WorkoutResult) => Promise - getWorkoutHistory: () => WorkoutResult[] -} - -function getDateString(timestamp: number) { - return new Date(timestamp).toISOString().split('T')[0] -} - -function calculateStreak(history: WorkoutResult[]): { current: number; longest: number } { - if (history.length === 0) return { current: 0, longest: 0 } - - const uniqueDays = new Set(history.map((r) => getDateString(r.completedAt))) - const sortedDays = Array.from(uniqueDays).sort().reverse() - - const today = getDateString(Date.now()) - const yesterday = getDateString(Date.now() - 86400000) - const hasRecentActivity = sortedDays[0] === today || sortedDays[0] === yesterday - - if (!hasRecentActivity) return { current: 0, longest: calculateLongest(sortedDays) } - - let current = 1 - for (let i = 0; i < sortedDays.length - 1; i++) { - const diff = new Date(sortedDays[i]).getTime() - new Date(sortedDays[i + 1]).getTime() - if (diff <= 86400000) { - current++ - } else { - break - } - } - - return { current, longest: Math.max(current, calculateLongest(sortedDays)) } -} - -function calculateLongest(sortedDays: string[]): number { - if (sortedDays.length === 0) return 0 - let longest = 1 - let streak = 1 - for (let i = 0; i < sortedDays.length - 1; i++) { - const diff = new Date(sortedDays[i]).getTime() - new Date(sortedDays[i + 1]).getTime() - if (diff <= 86400000) { - streak++ - longest = Math.max(longest, streak) - } else { - streak = 1 - } - } - return longest -} - -export const useActivityStore = create()( - persist( - (set, get) => ({ - history: [], - streak: { current: 0, longest: 0 }, - - addWorkoutResult: async (result) => { - const newHistory = [result, ...get().history] - const newStreak = calculateStreak(newHistory) - set({ - history: newHistory, - streak: newStreak, - }) - - // Check if we should show sync prompt (first workout for premium user) - const userStore = useUserStore.getState() - const isPremium = userStore.profile.subscription !== 'free' - const shouldPrompt = - userStore.profile.syncStatus === 'never-synced' && isPremium - - if (shouldPrompt) { - // Mark that we should show prompt after this workout - userStore.setPromptPending() - } - - // If already synced, sync this workout to Supabase - if (userStore.profile.syncStatus === 'synced') { - await syncWorkoutSession({ - workoutId: result.workoutId, - completedAt: new Date(result.completedAt).toISOString(), - durationSeconds: result.durationMinutes * 60, - caloriesBurned: result.calories, - feelingRating: undefined, // Can be added later if needed - }) - } - }, - - getWorkoutHistory: () => { - return get().history - }, - }), - { - name: 'tabatafit-activity', - storage: createJSONStorage(() => AsyncStorage), - } - ) -) - -// Standalone helper functions (use outside selectors) -export function getWeeklyActivity(history: WorkoutResult[]): DayActivity[] { - const days: DayActivity[] = [] - const today = new Date() - const startOfWeek = new Date(today) - startOfWeek.setDate(today.getDate() - today.getDay()) - - for (let i = 0; i < 7; i++) { - const date = new Date(startOfWeek) - date.setDate(startOfWeek.getDate() + i) - const dateStr = getDateString(date.getTime()) - const workoutsOnDay = history.filter((r) => getDateString(r.completedAt) === dateStr) - days.push({ - date: String(i), - completed: workoutsOnDay.length > 0, - workoutCount: workoutsOnDay.length, - }) - } - return days -} diff --git a/src/shared/stores/programStore.ts b/src/shared/stores/programStore.ts deleted file mode 100644 index e45803c..0000000 --- a/src/shared/stores/programStore.ts +++ /dev/null @@ -1,358 +0,0 @@ -/** - * TabataFit Program Store - * Handles program selection, progression tracking, and sequential unlocking - */ - -import { create } from 'zustand' -import { persist } from 'zustand/middleware' -import AsyncStorage from '@react-native-async-storage/async-storage' -import type { - ProgramId, - ProgramWorkout, - ProgramProgress, - AssessmentResult, -} from '../types/program' -import { PROGRAMS } from '../data/programs' - -interface ProgramState { - // Program selection - selectedProgramId: ProgramId | null - - // Progress tracking for each program - programsProgress: Record - - // Assessment - assessment: { - isCompleted: boolean - result: AssessmentResult | null - } - - // Actions - selectProgram: (programId: ProgramId) => void - completeWorkout: (programId: ProgramId, workoutId: string) => void - completeAssessment: (result: AssessmentResult) => void - skipAssessment: () => void - resetProgram: (programId: ProgramId) => void - changeProgram: (programId: ProgramId) => void - - // Getters - getCurrentWorkout: (programId: ProgramId) => ProgramWorkout | null - getNextWorkout: (programId: ProgramId) => ProgramWorkout | null - isWeekUnlocked: (programId: ProgramId, weekNumber: number) => boolean - isWorkoutUnlocked: (programId: ProgramId, workoutId: string) => boolean - getProgramCompletion: (programId: ProgramId) => number - getTotalWorkoutsCompleted: () => number - getProgramStatus: (programId: ProgramId) => 'not-started' | 'in-progress' | 'completed' - getRecommendedNextWorkout: () => { programId: ProgramId; workout: ProgramWorkout } | null -} - -const createInitialProgress = (programId: ProgramId): ProgramProgress => ({ - programId, - currentWeek: 1, - currentWorkoutIndex: 0, - completedWorkoutIds: [], - isProgramCompleted: false, - startDate: undefined, - lastWorkoutDate: undefined, -}) - -export const useProgramStore = create()( - persist( - (set, get) => ({ - // Initial state - selectedProgramId: null, - programsProgress: { - 'upper-body': createInitialProgress('upper-body'), - 'lower-body': createInitialProgress('lower-body'), - 'full-body': createInitialProgress('full-body'), - }, - assessment: { - isCompleted: false, - result: null, - }, - - // Select a program to start - selectProgram: (programId) => { - const state = get() - const progress = state.programsProgress[programId] - - // If starting for the first time, set start date - if (progress.completedWorkoutIds.length === 0 && !progress.startDate) { - set((state) => ({ - selectedProgramId: programId, - programsProgress: { - ...state.programsProgress, - [programId]: { - ...progress, - startDate: new Date().toISOString(), - }, - }, - })) - } else { - set({ selectedProgramId: programId }) - } - }, - - // Complete a workout and advance progress - completeWorkout: (programId, workoutId) => { - const state = get() - const progress = state.programsProgress[programId] - const program = PROGRAMS[programId] - - if (!program) return - - // Add to completed list - const newCompletedIds = [...progress.completedWorkoutIds, workoutId] - - // Find current workout position - let newWeek = progress.currentWeek - let newWorkoutIndex = progress.currentWorkoutIndex - - // Check if we completed the last workout of the week - const currentWeekWorkouts = program.weeks[progress.currentWeek - 1]?.workouts || [] - const isLastWorkoutOfWeek = progress.currentWorkoutIndex >= currentWeekWorkouts.length - 1 - - if (isLastWorkoutOfWeek && progress.currentWeek < 4) { - // Move to next week - newWeek = (progress.currentWeek + 1) as 1 | 2 | 3 | 4 - newWorkoutIndex = 0 - } else if (!isLastWorkoutOfWeek) { - // Move to next workout in same week - newWorkoutIndex = progress.currentWorkoutIndex + 1 - } - - // Check if program is completed (all 20 workouts) - const isProgramCompleted = newCompletedIds.length >= 20 - - set((state) => ({ - programsProgress: { - ...state.programsProgress, - [programId]: { - ...progress, - completedWorkoutIds: newCompletedIds, - currentWeek: newWeek, - currentWorkoutIndex: newWorkoutIndex, - isProgramCompleted, - lastWorkoutDate: new Date().toISOString(), - }, - }, - })) - }, - - // Complete assessment - completeAssessment: (result) => { - set({ - assessment: { - isCompleted: true, - result, - }, - }) - }, - - // Skip assessment - skipAssessment: () => { - set({ - assessment: { - isCompleted: true, - result: null, - }, - }) - }, - - // Reset a program to start over - resetProgram: (programId) => { - set((state) => ({ - programsProgress: { - ...state.programsProgress, - [programId]: createInitialProgress(programId), - }, - selectedProgramId: state.selectedProgramId === programId ? null : state.selectedProgramId, - })) - }, - - // Change to a different program (allow switching) - changeProgram: (programId) => { - set({ selectedProgramId: programId }) - }, - - // Get the current workout for a program - getCurrentWorkout: (programId) => { - const state = get() - const progress = state.programsProgress[programId] - const program = PROGRAMS[programId] - - if (!program || !progress) return null - - const week = program.weeks[progress.currentWeek - 1] - if (!week) return null - - return week.workouts[progress.currentWorkoutIndex] || null - }, - - // Get the next workout (for displaying what's coming up) - getNextWorkout: (programId) => { - const state = get() - const progress = state.programsProgress[programId] - const program = PROGRAMS[programId] - - if (!program || !progress) return null - - const currentWeek = program.weeks[progress.currentWeek - 1] - if (!currentWeek) return null - - // Check if there's another workout in the current week - if (progress.currentWorkoutIndex < currentWeek.workouts.length - 1) { - return currentWeek.workouts[progress.currentWorkoutIndex + 1] - } - - // Check if there's a next week - if (progress.currentWeek < 4) { - const nextWeek = program.weeks[progress.currentWeek] - return nextWeek?.workouts[0] || null - } - - return null - }, - - // Check if a week is unlocked - isWeekUnlocked: (programId, weekNumber) => { - const state = get() - const progress = state.programsProgress[programId] - - // Week 1 is always unlocked - if (weekNumber === 1) return true - - // Check if all workouts from previous week are completed - const program = PROGRAMS[programId] - if (!program) return false - - const previousWeek = program.weeks[weekNumber - 2] - if (!previousWeek) return false - - const previousWeekWorkoutIds = previousWeek.workouts.map((w) => w.id) - return previousWeekWorkoutIds.every((id) => - progress.completedWorkoutIds.includes(id) - ) - }, - - // Check if a specific workout is unlocked - isWorkoutUnlocked: (programId, workoutId) => { - const state = get() - const progress = state.programsProgress[programId] - const program = PROGRAMS[programId] - - if (!program || !progress) return false - - // Find the workout in the program structure - for (const week of program.weeks) { - const workoutIndex = week.workouts.findIndex((w) => w.id === workoutId) - if (workoutIndex === -1) continue - - // If it's in week 1, it's unlocked - if (week.weekNumber === 1) { - // Check if it's before or at current position - if (week.weekNumber === progress.currentWeek) { - return workoutIndex <= progress.currentWorkoutIndex - } - return true - } - - // Check if the week is unlocked - if (!get().isWeekUnlocked(programId, week.weekNumber)) { - return false - } - - // Check if it's before or at current position - if (week.weekNumber === progress.currentWeek) { - return workoutIndex <= progress.currentWorkoutIndex - } - - // If it's in a previous week, it's unlocked - if (week.weekNumber < progress.currentWeek) { - return true - } - } - - return false - }, - - // Get completion percentage for a program - getProgramCompletion: (programId) => { - const state = get() - const progress = state.programsProgress[programId] - if (!progress) return 0 - - return Math.round((progress.completedWorkoutIds.length / 20) * 100) - }, - - // Get total workouts completed across all programs - getTotalWorkoutsCompleted: () => { - const state = get() - return Object.values(state.programsProgress).reduce( - (total, progress) => total + progress.completedWorkoutIds.length, - 0 - ) - }, - - // Get program status - getProgramStatus: (programId) => { - const state = get() - const progress = state.programsProgress[programId] - - if (!progress || progress.completedWorkoutIds.length === 0) { - return 'not-started' - } - - if (progress.isProgramCompleted) { - return 'completed' - } - - return 'in-progress' - }, - - // Get recommended next workout (for home screen) - getRecommendedNextWorkout: () => { - const state = get() - - // If a program is selected, recommend the next workout in that program - if (state.selectedProgramId) { - const nextWorkout = get().getCurrentWorkout(state.selectedProgramId) - if (nextWorkout) { - return { - programId: state.selectedProgramId, - workout: nextWorkout, - } - } - } - - // Find any in-progress program - for (const programId of Object.keys(PROGRAMS) as ProgramId[]) { - const status = get().getProgramStatus(programId) - if (status === 'in-progress') { - const nextWorkout = get().getCurrentWorkout(programId) - if (nextWorkout) { - return { programId, workout: nextWorkout } - } - } - } - - return null - }, - }), - { - name: 'tabatafit-program-storage', - storage: { - getItem: async (name) => { - const value = await AsyncStorage.getItem(name) - return value ? JSON.parse(value) : null - }, - setItem: async (name, value) => { - await AsyncStorage.setItem(name, JSON.stringify(value)) - }, - removeItem: async (name) => { - await AsyncStorage.removeItem(name) - }, - }, - } - ) -) diff --git a/src/shared/stores/tabataProgramStore.ts b/src/shared/stores/tabataProgramStore.ts deleted file mode 100644 index 6d3f1d5..0000000 --- a/src/shared/stores/tabataProgramStore.ts +++ /dev/null @@ -1,335 +0,0 @@ -/** - * Tabata Program Store - * Handles program selection, progression tracking, and sequential unlocking - * for the 4 tabata programs (debutant, intermediaire, avance, bureau) - */ - -import { create } from 'zustand' -import { persist } from 'zustand/middleware' -import AsyncStorage from '@react-native-async-storage/async-storage' -import type { - TabataProgramId, - TabataProgramProgress, -} from '../types/program' -import type { TabataProgram, TabataSession } from '../types/program' -import { getTabataProgramById, getAllTabataPrograms, getTabataSessionById } from '../data/tabata' - -// ─── Types ───────────────────────────────────────────────────── - -interface TabataProgramState { - // Program selection - selectedProgramId: TabataProgramId | null - - // Progress tracking for each program - programsProgress: Record - - // Actions - selectProgram: (programId: TabataProgramId) => void - completeSession: (programId: TabataProgramId, sessionId: string) => void - resetProgram: (programId: TabataProgramId) => void - changeProgram: (programId: TabataProgramId) => void - - // Getters - getCurrentSession: (programId: TabataProgramId) => TabataSession | null - getNextSession: (programId: TabataProgramId) => TabataSession | null - isWeekUnlocked: (programId: TabataProgramId, weekNumber: number) => boolean - isSessionUnlocked: (programId: TabataProgramId, sessionId: string) => boolean - getProgramCompletion: (programId: TabataProgramId) => number - getTotalSessionsCompleted: () => number - getProgramStatus: (programId: TabataProgramId) => 'not-started' | 'in-progress' | 'completed' - getRecommendedNext: () => { programId: TabataProgramId; session: TabataSession } | null - getProgram: (programId: TabataProgramId) => TabataProgram | undefined -} - -// ─── Helpers ─────────────────────────────────────────────────── - -const PROGRAM_IDS: TabataProgramId[] = ['debutant', 'intermediaire', 'avance', 'bureau'] - -const createInitialProgress = (programId: TabataProgramId): TabataProgramProgress => ({ - programId, - currentWeek: 1, - currentSessionIndex: 0, - completedSessionIds: [], - isProgramCompleted: false, - startDate: undefined, - lastSessionDate: undefined, -}) - -const createAllProgress = (): Record => { - const result = {} as Record - for (const id of PROGRAM_IDS) { - result[id] = createInitialProgress(id) - } - return result -} - -/** Get sessions for a specific week of a program */ -const getWeekSessions = (program: TabataProgram, weekNumber: number): TabataSession[] => { - const week = program.weeks.find(w => w.weekNumber === weekNumber) - return week?.sessions ?? [] -} - -// ─── Store ───────────────────────────────────────────────────── - -export const useTabataProgramStore = create()( - persist( - (set, get) => ({ - // Initial state - selectedProgramId: null, - programsProgress: createAllProgress(), - - // Select a program to start - selectProgram: (programId) => { - const state = get() - const progress = state.programsProgress[programId] - - if (progress.completedSessionIds.length === 0 && !progress.startDate) { - set((state) => ({ - selectedProgramId: programId, - programsProgress: { - ...state.programsProgress, - [programId]: { - ...progress, - startDate: new Date().toISOString(), - }, - }, - })) - } else { - set({ selectedProgramId: programId }) - } - }, - - // Complete a session and advance progress - completeSession: (programId, sessionId) => { - const state = get() - const progress = state.programsProgress[programId] - const program = getTabataProgramById(programId) - - if (!program) return - - // Avoid duplicate completions - if (progress.completedSessionIds.includes(sessionId)) return - - const newCompletedIds = [...progress.completedSessionIds, sessionId] - - // Find current session position - let newWeek = progress.currentWeek - let newSessionIndex = progress.currentSessionIndex - - const currentWeekSessions = getWeekSessions(program, progress.currentWeek) - const isLastSessionOfWeek = progress.currentSessionIndex >= currentWeekSessions.length - 1 - - if (isLastSessionOfWeek && progress.currentWeek < program.durationWeeks) { - // Move to next week - newWeek = progress.currentWeek + 1 - newSessionIndex = 0 - } else if (!isLastSessionOfWeek) { - // Move to next session in same week - newSessionIndex = progress.currentSessionIndex + 1 - } - - // Check if program is completed - const isProgramCompleted = newCompletedIds.length >= program.totalSessions - - set((state) => ({ - programsProgress: { - ...state.programsProgress, - [programId]: { - ...progress, - completedSessionIds: newCompletedIds, - currentWeek: newWeek, - currentSessionIndex: newSessionIndex, - isProgramCompleted, - lastSessionDate: new Date().toISOString(), - }, - }, - })) - }, - - // Reset a program to start over - resetProgram: (programId) => { - set((state) => ({ - programsProgress: { - ...state.programsProgress, - [programId]: createInitialProgress(programId), - }, - selectedProgramId: state.selectedProgramId === programId ? null : state.selectedProgramId, - })) - }, - - // Change to a different program - changeProgram: (programId) => { - set({ selectedProgramId: programId }) - }, - - // Get the current session for a program - getCurrentSession: (programId) => { - const state = get() - const progress = state.programsProgress[programId] - const program = getTabataProgramById(programId) - - if (!program || !progress) return null - - const week = program.weeks.find(w => w.weekNumber === progress.currentWeek) - if (!week) return null - - return week.sessions[progress.currentSessionIndex] ?? null - }, - - // Get the next session - getNextSession: (programId) => { - const state = get() - const progress = state.programsProgress[programId] - const program = getTabataProgramById(programId) - - if (!program || !progress) return null - - const currentWeek = program.weeks.find(w => w.weekNumber === progress.currentWeek) - if (!currentWeek) return null - - if (progress.currentSessionIndex < currentWeek.sessions.length - 1) { - return currentWeek.sessions[progress.currentSessionIndex + 1] - } - - if (progress.currentWeek < program.durationWeeks) { - const nextWeek = program.weeks.find(w => w.weekNumber === progress.currentWeek + 1) - return nextWeek?.sessions[0] ?? null - } - - return null - }, - - // Check if a week is unlocked - isWeekUnlocked: (programId, weekNumber) => { - if (weekNumber === 1) return true - - const state = get() - const progress = state.programsProgress[programId] - const program = getTabataProgramById(programId) - - if (!program) return false - - const previousWeek = program.weeks.find(w => w.weekNumber === weekNumber - 1) - if (!previousWeek) return false - - const previousWeekSessionIds = previousWeek.sessions.map(s => s.id) - return previousWeekSessionIds.every(id => progress.completedSessionIds.includes(id)) - }, - - // Check if a specific session is unlocked - isSessionUnlocked: (programId, sessionId) => { - const state = get() - const progress = state.programsProgress[programId] - const program = getTabataProgramById(programId) - - if (!program || !progress) return false - - for (const week of program.weeks) { - const sessionIndex = week.sessions.findIndex(s => s.id === sessionId) - if (sessionIndex === -1) continue - - // Week must be unlocked - if (!get().isWeekUnlocked(programId, week.weekNumber)) return false - - // If completed, always accessible - if (progress.completedSessionIds.includes(sessionId)) return true - - // Must be at or before current position - if (week.weekNumber === progress.currentWeek) { - return sessionIndex <= progress.currentSessionIndex - } - - if (week.weekNumber < progress.currentWeek) return true - } - - return false - }, - - // Get completion percentage - getProgramCompletion: (programId) => { - const state = get() - const progress = state.programsProgress[programId] - const program = getTabataProgramById(programId) - - if (!progress || !program) return 0 - - return Math.round((progress.completedSessionIds.length / program.totalSessions) * 100) - }, - - // Get total sessions completed across all programs - getTotalSessionsCompleted: () => { - const state = get() - return Object.values(state.programsProgress).reduce( - (total, progress) => total + progress.completedSessionIds.length, - 0, - ) - }, - - // Get program status - getProgramStatus: (programId) => { - const state = get() - const progress = state.programsProgress[programId] - - if (!progress || progress.completedSessionIds.length === 0) return 'not-started' - if (progress.isProgramCompleted) return 'completed' - return 'in-progress' - }, - - // Get recommended next session - getRecommendedNext: () => { - const state = get() - - // If a program is selected, recommend current session - if (state.selectedProgramId) { - const session = get().getCurrentSession(state.selectedProgramId) - if (session) { - return { programId: state.selectedProgramId, session } - } - } - - // Find any in-progress program - for (const programId of PROGRAM_IDS) { - const status = get().getProgramStatus(programId) - if (status === 'in-progress') { - const session = get().getCurrentSession(programId) - if (session) return { programId, session } - } - } - - return null - }, - - // Get program data - getProgram: (programId) => { - return getTabataProgramById(programId) - }, - }), - { - name: 'tabatafit-kine-program-storage', - version: 2, - storage: { - getItem: async (name) => { - const value = await AsyncStorage.getItem(name) - return value ? JSON.parse(value) : null - }, - setItem: async (name, value) => { - await AsyncStorage.setItem(name, JSON.stringify(value)) - }, - removeItem: async (name) => { - await AsyncStorage.removeItem(name) - }, - }, - migrate: (persisted, version): TabataProgramState => { - // Migrate from v1 (old 3-program model) to v2 (tabata 4-program model) - if (version === undefined || version < 2) { - // Old format had upper-body/lower-body/full-body keys — reset entirely - return { - selectedProgramId: null, - programsProgress: createAllProgress(), - } as TabataProgramState - } - return persisted as TabataProgramState - }, - }, - ) -) diff --git a/supabase/seed.ts b/supabase/seed.ts deleted file mode 100644 index 1a6f2ab..0000000 --- a/supabase/seed.ts +++ /dev/null @@ -1,227 +0,0 @@ -/** - * TabataFit Seed Script - * - * This script seeds your Supabase database with the initial data. - * Run this after setting up your Supabase project. - * - * Usage: - * 1. Set your Supabase credentials in .env - * 2. Run: npx ts-node supabase/seed.ts - */ - -import { createClient } from '@supabase/supabase-js' -import { WORKOUTS } from '../src/shared/data/workouts' -import { TRAINERS } from '../src/shared/data/trainers' -import { PROGRAMS } from '../src/shared/data/programs' -import { ACHIEVEMENTS } from '../src/shared/data/achievements' - -/** - * Seed data for collections — used only for initial database seeding. - * The app fetches collections from Supabase at runtime. - */ -const SEED_COLLECTIONS = [ - { - id: 'morning-energizer', - title: 'Morning Energizer', - description: 'Start your day right', - icon: '🌅', - workoutIds: ['4', '6', '43', '47', '10'], - }, - { - id: 'no-equipment', - title: 'No Equipment', - description: 'Workout anywhere', - icon: '💪', - workoutIds: ['1', '4', '6', '11', '13', '16', '17', '19', '23', '26', '31', '38', '42', '43', '45'], - }, - { - id: '7-day-burn', - title: '7-Day Burn Challenge', - description: 'Transform in one week', - icon: '🔥', - workoutIds: ['1', '11', '31', '42', '6', '17', '23'], - gradient: ['#FF6B35', '#FF3B30'], - }, - { - id: 'quick-intense', - title: 'Quick & Intense', - description: 'Max effort in 4 minutes', - icon: '⚡', - workoutIds: ['1', '11', '23', '35', '38', '42', '6', '17'], - }, - { - id: 'core-focus', - title: 'Core Focus', - description: 'Build a solid foundation', - icon: '🎯', - workoutIds: ['11', '12', '13', '14', '16', '17'], - }, - { - id: 'leg-day', - title: 'Leg Day', - description: 'Never skip leg day', - icon: '🦵', - workoutIds: ['31', '32', '33', '34', '35', '36', '37'], - }, -] - -const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_URL -const supabaseKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY - -if (!supabaseUrl || !supabaseKey) { - console.error('Missing Supabase credentials. Please set EXPO_PUBLIC_SUPABASE_URL and EXPO_PUBLIC_SUPABASE_ANON_KEY') - process.exit(1) -} - -const supabase = createClient(supabaseUrl, supabaseKey) - -async function seedTrainers() { - console.log('Seeding trainers...') - - const trainers = TRAINERS.map(t => ({ - id: t.id, - name: t.name, - specialty: t.specialty, - color: t.color, - avatar_url: t.avatarUrl || null, - workout_count: t.workoutCount, - })) - - const { error } = await supabase.from('trainers').upsert(trainers) - if (error) throw error - console.log(`✅ Seeded ${trainers.length} trainers`) -} - -async function seedWorkouts() { - console.log('Seeding workouts...') - - const workouts = WORKOUTS.map(w => ({ - id: w.id, - title: w.title, - trainer_id: w.trainerId, - category: w.category, - level: w.level, - duration: w.duration, - calories: w.calories, - rounds: w.rounds, - prep_time: w.prepTime, - work_time: w.workTime, - rest_time: w.restTime, - equipment: w.equipment, - music_vibe: w.musicVibe, - exercises: w.exercises, - thumbnail_url: w.thumbnailUrl || null, - video_url: w.videoUrl || null, - is_featured: w.isFeatured || false, - })) - - const { error } = await supabase.from('workouts').upsert(workouts) - if (error) throw error - console.log(`✅ Seeded ${workouts.length} workouts`) -} - -async function seedCollections() { - console.log('Seeding collections...') - - const collections = SEED_COLLECTIONS.map(c => ({ - id: c.id, - title: c.title, - description: c.description, - icon: c.icon, - gradient: c.gradient || null, - })) - - const { error } = await supabase.from('collections').upsert(collections) - if (error) throw error - - // Seed collection-workout relationships - const collectionWorkouts = SEED_COLLECTIONS.flatMap(c => - c.workoutIds.map((workoutId, index) => ({ - collection_id: c.id, - workout_id: workoutId, - sort_order: index, - })) - ) - - const { error: linkError } = await supabase.from('collection_workouts').upsert(collectionWorkouts) - if (linkError) throw linkError - - console.log(`✅ Seeded ${collections.length} collections with ${collectionWorkouts.length} workout links`) -} - -async function seedPrograms() { - console.log('Seeding programs...') - - const programs = Object.values(PROGRAMS).map(p => ({ - id: p.id, - title: p.title, - description: p.description, - weeks: p.weeks, - workouts_per_week: p.workoutsPerWeek, - })) - - const { error } = await supabase.from('programs').upsert(programs) - if (error) throw error - - // Seed program-workout relationships - let programWorkouts: { program_id: string; workout_id: string; week_number: number; day_number: number }[] = [] - - Object.values(PROGRAMS).forEach(program => { - program.weeks.forEach((week) => { - week.workouts.forEach((workout, dayIndex) => { - programWorkouts.push({ - program_id: program.id, - workout_id: workout.id, - week_number: week.weekNumber, - day_number: dayIndex + 1, - }) - }) - }) - }) - - const { error: linkError } = await supabase.from('program_workouts').upsert(programWorkouts) - if (linkError) throw linkError - - console.log(`✅ Seeded ${programs.length} programs with ${programWorkouts.length} workout links`) -} - -async function seedAchievements() { - console.log('Seeding achievements...') - - const achievements = ACHIEVEMENTS.map(a => ({ - id: a.id, - title: a.title, - description: a.description, - icon: a.icon, - requirement: a.requirement, - type: a.type, - })) - - const { error } = await supabase.from('achievements').upsert(achievements) - if (error) throw error - console.log(`✅ Seeded ${achievements.length} achievements`) -} - -async function main() { - try { - console.log('🌱 Starting database seed...\n') - - await seedTrainers() - await seedWorkouts() - await seedCollections() - await seedPrograms() - await seedAchievements() - - console.log('\n✨ Database seeded successfully!') - console.log('\nNext steps:') - console.log('1. Set up storage buckets in Supabase Dashboard') - console.log('2. Upload video and thumbnail files') - console.log('3. Create an admin user in the admin_users table') - console.log('4. Access the admin dashboard at /admin') - } catch (error) { - console.error('\n❌ Seeding failed:', error) - process.exit(1) - } -} - -main()