'use client'; import React, { useState } from 'react'; import { Dumbbell, Flame, Zap, Activity, Droplets, Plus, Trash2, Scale, Info, CheckCircle2, X, Sparkles, Calculator, ShieldCheck, TrendingUp, Target, Utensils, Check } from 'lucide-react'; import { WorkoutSession, DailyNutrition, MuscleRecovery, WorkoutExercise } from '@/lib/types'; import { SCIENCE_TIPS, getFormattedDate } from '@/lib/initialData'; import { playNotificationChime } from '@/lib/audio'; interface FitnessViewProps { workouts: WorkoutSession[]; nutrition: DailyNutrition; muscleRecovery: MuscleRecovery[]; onAddWorkout: (workout: Omit) => void; onDeleteWorkout: (id: string) => void; onUpdateNutrition: (updates: Partial) => void; } export const FitnessView: React.FC = ({ workouts, nutrition, muscleRecovery, onAddWorkout, onDeleteWorkout, onUpdateNutrition, }) => { // Modal states const [isWorkoutModalOpen, setIsWorkoutModalOpen] = useState(false); const [isNutritionModalOpen, setIsNutritionModalOpen] = useState(false); // 1RM Calculator state const [calcWeight, setCalcWeight] = useState(85); const [calcReps, setCalcReps] = useState(6); // Calculate 1RM via Epley Formula: 1RM = Weight * (1 + Reps / 30) const estimated1RM = Math.max(1, Math.round(calcWeight * (1 + calcReps / 30))); // Daily Macro & TDEE Calculator state const [macroWeight, setMacroWeight] = useState(nutrition.bodyweightKg || 78.5); const [macroGoal, setMacroGoal] = useState<'cut' | 'maintain' | 'bulk'>('maintain'); const [macroActivity, setMacroActivity] = useState<'sedentary' | 'moderate' | 'intense'>('moderate'); const [isSynced, setIsSynced] = useState(false); // Scientific Macro Calculations: // Activity Multipliers on bodyweight: Sedentary: 30 kcal/kg, Moderate: 33 kcal/kg, Intense: 36 kcal/kg const activityMultiplier = macroActivity === 'sedentary' ? 30 : macroActivity === 'intense' ? 36 : 33; const maintenanceTDEE = Math.round(macroWeight * activityMultiplier); let calcTargetCalories = maintenanceTDEE; let calcTargetProtein = Math.round(macroWeight * 2.0); // g (optimal 2.0g/kg) let calcTargetFats = Math.round(macroWeight * 0.9); // g if (macroGoal === 'cut') { calcTargetCalories = Math.round(maintenanceTDEE * 0.80); // 20% deficit calcTargetProtein = Math.round(macroWeight * 2.3); // High protein to preserve lean body mass in a cut calcTargetFats = Math.round(macroWeight * 0.75); } else if (macroGoal === 'bulk') { calcTargetCalories = Math.round(maintenanceTDEE * 1.10); // 10% clean surplus for hypertrophy calcTargetProtein = Math.round(macroWeight * 2.0); calcTargetFats = Math.round(macroWeight * 1.0); } // Carbs = Remaining calories / 4 kcal per gram (primary glycogen driver) const caloriesFromProteinAndFat = (calcTargetProtein * 4) + (calcTargetFats * 9); const calcTargetCarbs = Math.max(40, Math.round((calcTargetCalories - caloriesFromProteinAndFat) / 4)); const handleApplyMacroTargets = () => { onUpdateNutrition({ calorieTarget: calcTargetCalories, proteinTarget: calcTargetProtein, carbsTarget: calcTargetCarbs, fatsTarget: calcTargetFats, bodyweightKg: macroWeight, }); setIsSynced(true); playNotificationChime('complete'); setTimeout(() => setIsSynced(false), 2500); }; // Log Workout Form State const [workoutName, setWorkoutName] = useState('Push Hypertrophy'); const [workoutDate, setWorkoutDate] = useState(getFormattedDate(0)); const [workoutMuscles, setWorkoutMuscles] = useState('Chest, Shoulders, Triceps'); const [workoutNotes, setWorkoutNotes] = useState(''); const [exerciseList, setExerciseList] = useState<{ name: string; muscleGroup: string; weight: number; reps: number; rpe: number; setsCount: number; }[]>([ { name: 'Incline Dumbbell Press', muscleGroup: 'Chest', weight: 32, reps: 8, rpe: 8.5, setsCount: 3 }, ]); const addExerciseRow = () => { setExerciseList([ ...exerciseList, { name: '', muscleGroup: 'Chest', weight: 60, reps: 8, rpe: 8, setsCount: 3 }, ]); }; const removeExerciseRow = (index: number) => { setExerciseList(exerciseList.filter((_, i) => i !== index)); }; const handleCreateWorkout = (e: React.FormEvent) => { e.preventDefault(); if (!workoutName.trim() || exerciseList.length === 0) return; let totalVolume = 0; const constructedExercises: WorkoutExercise[] = exerciseList.map((ex) => { const sets = []; for (let s = 1; s <= ex.setsCount; s++) { sets.push({ setNumber: s, weight: ex.weight, reps: ex.reps, rpe: ex.rpe, }); totalVolume += ex.weight * ex.reps; } return { name: ex.name || 'Exercise', muscleGroup: ex.muscleGroup, sets, }; }); onAddWorkout({ name: workoutName.trim(), date: workoutDate, muscleGroups: workoutMuscles.split(',').map((m) => m.trim()), volumeLoad: totalVolume, exercises: constructedExercises, notes: workoutNotes.trim() || undefined, }); setIsWorkoutModalOpen(false); playNotificationChime('streak'); }; // Water Increment / Decrement const handleWaterChange = (delta: number) => { const updated = Math.max(0, parseFloat((nutrition.waterLiters + delta).toFixed(2))); onUpdateNutrition({ waterLiters: updated }); playNotificationChime('click'); }; // Creatine Toggle const handleCreatineToggle = () => { onUpdateNutrition({ creatineTaken: !nutrition.creatineTaken }); playNotificationChime(nutrition.creatineTaken ? 'click' : 'complete'); }; // Nutrition Form State const [editCalories, setEditCalories] = useState(nutrition.calories); const [editProtein, setEditProtein] = useState(nutrition.protein); const [editCarbs, setEditCarbs] = useState(nutrition.carbs); const [editFats, setEditFats] = useState(nutrition.fats); const [editWeight, setEditWeight] = useState(nutrition.bodyweightKg); const handleSaveNutrition = (e: React.FormEvent) => { e.preventDefault(); onUpdateNutrition({ calories: Number(editCalories), protein: Number(editProtein), carbs: Number(editCarbs), fats: Number(editFats), bodyweightKg: Number(editWeight), }); setIsNutritionModalOpen(false); playNotificationChime('click'); }; const proteinRatio = (nutrition.protein / nutrition.bodyweightKg).toFixed(2); const isOptimalProtein = parseFloat(proteinRatio) >= 1.6; return (
{/* Header Banner */}
Evidence-Based Hypertrophy & Metabolism Lab

Science of Progressive Overload

Tension over guesswork. Track volume load (kg × reps), monitor your Muscle Protein Synthesis (MPS) recovery windows, and hit precise macronutrient thresholds for optimal adaptation.

{/* SECTION 1: MACRONUTRIENT & METABOLIC FUEL STATION */}

Daily Macronutrient Fuel Station

Bodyweight: {nutrition.bodyweightKg} kg
{/* Calories Card */}
Total Energy (Calories) {Math.round((nutrition.calories / nutrition.calorieTarget) * 100)}%
{nutrition.calories} / {nutrition.calorieTarget} kcal
{/* Protein Card (Scientific g/kg metric) */}
Protein (MPS) {proteinRatio} g/kg
{nutrition.protein}g / {nutrition.proteinTarget}g target

Optimal range: 1.6 - 2.2 g/kg

{/* Carbohydrates & Fats */}
Glycogen & Hormones Carbs & Fats
{nutrition.carbs}g

Carbs (Glycogen)

{nutrition.fats}g

Fats (Lipids)

{/* Hydration & Creatine Station */}
Hydration & Ergogenics
{nutrition.waterLiters}L

Water Intake

{/* Creatine Checkbox */}
{/* SECTION 2: MUSCLE RECOVERY & PROTEIN SYNTHESIS MATRIX */}

Muscle Protein Synthesis (MPS) & Recovery Matrix

Based on the 48–72h physiological recovery window required for tissue remodeling.

Hypertrophy Window
{muscleRecovery.map((rec) => { const isReady = rec.status === 'ready'; const isRecovering = rec.status === 'recovering'; return (
{rec.muscle} {rec.status}
Readiness: {rec.percentRecovered}% Trained {rec.lastTrainedDaysAgo === 0 ? 'Today' : `${rec.lastTrainedDaysAgo}d ago`}
); })}
{/* SECTION 3: INTERACTIVE SCIENTIFIC FITNESS TOOLS & CALCULATORS */}

Interactive Scientific Fitness Tools

Precision Biometrics & Training Zones
{/* TOOL 1: 1RM & Percentage Training Zones Calculator */}

One-Rep Max (1RM) Calculator

Epley Formula

Calculate estimated max strength without injury risk and identify your exact percentage training zones.

{/* Weight Input with Steppers & Quick Chips */}
{calcWeight} kg
setCalcWeight(Number(e.target.value))} className="w-full accent-cyan-400 cursor-pointer" /> {/* Quick Presets */}
Presets: {[60, 80, 100, 120, 140].map((w) => ( ))}
{/* Reps Input with Segmented Pills */}
{calcReps} reps
{[1, 2, 3, 4, 5, 6, 8, 10, 12].map((r) => ( ))}
{/* Estimated 1RM Readout */}
Estimated 1-Rep Max
{estimated1RM} kg

1RM = {calcWeight}kg × (1 + {calcReps}/30)

{/* Explicit Percentage Training Zones: 90%, 80%, 70% */}
Percentage Training Zones
{/* 90% Zone */}
90% 1RM
{Math.round(estimated1RM * 0.90)}kg
3 - 4 Reps Max Strength & Power
{/* 80% Zone */}
80% 1RM
{Math.round(estimated1RM * 0.80)}kg
6 - 8 Reps Heavy Hypertrophy
{/* 70% Zone */}
70% 1RM
{Math.round(estimated1RM * 0.70)}kg
10 - 12 Reps Volume & Endurance
{/* TOOL 2: Daily Macro Calculator */}

Scientific Daily Macro Calculator

TDEE + MPS

Calculate custom macronutrient requirements based on your current bodyweight and physique goal.

{/* Bodyweight Input */}
{macroWeight} kg
setMacroWeight(Number(e.target.value))} className="w-full accent-lime-400 cursor-pointer" />
{/* Goal Selector: Cut, Maintain, Lean Bulk */}
{/* Activity Level Selector */}
{/* Calculated Targets Output */}
Target Daily Calories {calcTargetCalories} kcal
Protein {calcTargetProtein}g {(calcTargetProtein / macroWeight).toFixed(1)} g/kg
Carbs {calcTargetCarbs}g Glycogen
Fats {calcTargetFats}g Hormones
{/* Macro Distribution Bar */}
{/* Sync Button */}
{/* Evidence-Based Science Principles */}

Evidence-Based Hypertrophy Principles

{SCIENCE_TIPS.map((tip) => (

{tip.title}

{tip.concept}

{tip.description}

))}
{/* SECTION 4: PROGRESSIVE OVERLOAD WORKOUT LOG */}

Scientific Training Log & Volume Load

Track Volume Load (Sets × Reps × Weight in kg) to ensure progressive overload across weeks.

{workouts.map((session) => (

{session.name}

[{session.date}]
{session.muscleGroups.map((mg) => ( {mg} ))}
Total Volume Load {session.volumeLoad.toLocaleString()} kg
{/* Exercise breakdown grid */}
{session.exercises.map((ex, idx) => (
{ex.name} {ex.muscleGroup}
{ex.sets.map((s) => (
Set {s.setNumber} {s.weight} kg × {s.reps} reps = 9 ? 'bg-red-500/10 text-red-400 border-red-500/30' : 'bg-lime-500/10 text-lime-400 border-lime-500/30' }`}> RPE {s.rpe}
))}
))}
{session.notes && (

💡 {session.notes}

)}
))} {workouts.length === 0 && (
No workouts logged yet. Start recording your sessions to build a progressive overload history!
)}
{/* MODAL: LOG SCIENTIFIC WORKOUT */} {isWorkoutModalOpen && (

Log Scientific Workout Session

setWorkoutName(e.target.value)} className="w-full px-3 py-2 rounded-xl bg-slate-900 border border-slate-800 text-xs text-slate-200 focus:outline-none focus:border-lime-500" />
setWorkoutDate(e.target.value)} className="w-full px-3 py-2 rounded-xl bg-slate-900 border border-slate-800 text-xs text-slate-200 focus:outline-none focus:border-lime-500" />
setWorkoutMuscles(e.target.value)} className="w-full px-3 py-2 rounded-xl bg-slate-900 border border-slate-800 text-xs text-slate-200 focus:outline-none focus:border-lime-500" />
{/* Dynamic Exercise Rows */}
{exerciseList.map((ex, idx) => (
{ const updated = [...exerciseList]; updated[idx].name = e.target.value; setExerciseList(updated); }} className="px-3 py-1.5 rounded-lg bg-slate-950 border border-slate-800 text-xs text-slate-200 focus:outline-none focus:border-lime-500" /> { const updated = [...exerciseList]; updated[idx].muscleGroup = e.target.value; setExerciseList(updated); }} className="px-3 py-1.5 rounded-lg bg-slate-950 border border-slate-800 text-xs text-slate-200 focus:outline-none focus:border-lime-500" />
{ const updated = [...exerciseList]; updated[idx].setsCount = Number(e.target.value); setExerciseList(updated); }} className="w-full px-2 py-1 rounded bg-slate-950 border border-slate-800 text-xs text-slate-200 text-center" />
{ const updated = [...exerciseList]; updated[idx].weight = Number(e.target.value); setExerciseList(updated); }} className="w-full px-2 py-1 rounded bg-slate-950 border border-slate-800 text-xs text-slate-200 text-center" />
{ const updated = [...exerciseList]; updated[idx].reps = Number(e.target.value); setExerciseList(updated); }} className="w-full px-2 py-1 rounded bg-slate-950 border border-slate-800 text-xs text-slate-200 text-center" />
{ const updated = [...exerciseList]; updated[idx].rpe = Number(e.target.value); setExerciseList(updated); }} className="w-full px-2 py-1 rounded bg-slate-950 border border-slate-800 text-xs text-slate-200 text-center" />
{exerciseList.length > 1 && ( )}
))}