import { useState, useEffect } from 'react'; import { useNavigate, useLocation, Link } from 'react-router-dom'; import { FaPlus, FaSave, FaArrowLeft, FaTrash, FaArrowUp, FaArrowDown, FaFilter, } from 'react-icons/fa'; import type { Routine, Exercise, RoutineItem } from '../types/models'; import { RoutineService, ExerciseService } from '../services/api'; const NewRoutinePage = () => { const navigate = useNavigate(); const location = useLocation(); // State for exercises const [exercises, setExercises] = useState([]); const [selectedItems, setSelectedItems] = useState([]); const [searchTerm, setSearchTerm] = useState(''); const [muscleFilter, setMuscleFilter] = useState(''); // State for routine data const [routineName, setRoutineName] = useState(''); const [routineDescription, setRoutineDescription] = useState(''); const [estimatedDuration, setEstimatedDuration] = useState(0); // UI state const [isLoading, setIsLoading] = useState(true); const [isSaving, setIsSaving] = useState(false); const [error, setError] = useState(null); const [successMessage, setSuccessMessage] = useState(null); // Track if we're editing an existing routine const [isEditMode, setIsEditMode] = useState(false); const [routineToEdit, setRoutineToEdit] = useState(null); // Fetch available exercises and check if we're in edit mode useEffect(() => { const fetchExercises = async () => { try { setIsLoading(true); const data = await ExerciseService.getAll(); setExercises(data); // Check if we're editing an existing routine if (location.state && location.state.editRoutine) { const routine = location.state.editRoutine as Routine; setRoutineName(routine.name); setRoutineDescription(routine.description); // Set selected items from the routine if (routine.routineItems && routine.routineItems.length > 0) { setSelectedItems(routine.routineItems); } setRoutineToEdit(routine); setIsEditMode(true); } setError(null); } catch (err) { console.error('Failed to fetch exercises:', err); setError('Could not load exercises. Please try again later.'); } finally { setIsLoading(false); } }; fetchExercises(); }, [location]); // Find unique muscle groups for filtering const muscleGroups = [...new Set(exercises.flatMap(ex => ex.muscleGroups.map(mg => mg.name) ))].sort(); // Filter exercises based on search and muscle filter const filteredExercises = exercises.filter(ex => { const matchesSearch = ex.name.toLowerCase().includes(searchTerm.toLowerCase()) || ex.description.toLowerCase().includes(searchTerm.toLowerCase()); const matchesMuscle = !muscleFilter || ex.muscleGroups.some(mg => mg.name === muscleFilter); return matchesSearch && matchesMuscle; }); // Handle adding an exercise to the routine const handleAddExercise = (exercise: Exercise) => { const newItem: RoutineItem = { routineId: routineToEdit?.id || 0, exerciseId: exercise.id, superSetId: null, restTime: 60, // Default rest time 60 seconds orderIndex: selectedItems.length, exercise: exercise, superSet: null, }; setSelectedItems([...selectedItems, newItem]); }; // Handle removing an exercise from the routine const handleRemoveItem = (index: number) => { const newSelectedItems = [...selectedItems]; newSelectedItems.splice(index, 1); // Update order values const reorderedItems = newSelectedItems.map((item, i) => ({ ...item, orderIndex: i, })); setSelectedItems(reorderedItems); }; // Handle updating exercise details const handleItemChange = (index: number, field: string, value: any) => { const newSelectedItems = [...selectedItems]; // @ts-ignore newSelectedItems[index][field] = value; setSelectedItems(newSelectedItems); }; // Handle moving exercises up/down in the order const handleMoveItem = (index: number, direction: 'up' | 'down') => { if ( (direction === 'up' && index === 0) || (direction === 'down' && index === selectedItems.length - 1) ) { return; } const newSelectedItems = [...selectedItems]; const swapIndex = direction === 'up' ? index - 1 : index + 1; // Swap items [newSelectedItems[index], newSelectedItems[swapIndex]] = [newSelectedItems[swapIndex], newSelectedItems[index]]; // Update order values const reorderedItems = newSelectedItems.map((item, i) => ({ ...item, orderIndex: i, })); setSelectedItems(reorderedItems); }; // Calculate estimated duration based on exercises and rest times useEffect(() => { let totalMinutes = 0; selectedItems.forEach(item => { if (item.exercise) { // Estimate time for each set (1 min per set) + rest time const setCount = item.exercise.sets?.length || 3; // Default to 3 if no sets defined const restTime = item.restTime / 60; // Convert seconds to minutes totalMinutes += setCount + restTime; } else if (item.superSet) { // For supersets, account for both exercises const primarySets = item.superSet.primaryExercise?.sets?.length || 3; const secondarySets = item.superSet.secondaryExercise?.sets?.length || 3; const restTime = item.superSet.restTime / 60; totalMinutes += primarySets + secondarySets + restTime; } }); // Add some buffer time for transitions between exercises totalMinutes += selectedItems.length > 0 ? Math.ceil(selectedItems.length / 3) : 0; setEstimatedDuration(Math.ceil(totalMinutes)); }, [selectedItems]); // Handle saving the routine const handleSaveRoutine = async (e: React.FormEvent) => { e.preventDefault(); if (selectedItems.length === 0) { setError('Please add at least one exercise to your routine.'); return; } setIsSaving(true); setError(null); // Prepare the routineItems by removing circular references const sanitizedItems = selectedItems.map(item => { const { exercise, superSet, ...rest } = item; return rest; }); const routineData: Routine = { name: routineName, description: routineDescription, routineItems: sanitizedItems, }; try { if (isEditMode && routineToEdit?.id) { // Update existing routine await RoutineService.update(routineToEdit.id, routineData); setSuccessMessage('Routine updated successfully!'); } else { // Create new routine await RoutineService.create(routineData); setSuccessMessage('Routine created successfully!'); } // Show success message briefly then redirect setTimeout(() => { navigate('/workouts'); }, 1500); } catch (err) { console.error('Failed to save routine:', err); setError('Failed to save routine. Please try again.'); } finally { setIsSaving(false); } }; return (

{isEditMode ? 'Edit Routine' : 'Create Routine'}

{error &&
{error}
} {successMessage &&
{successMessage}
} {isLoading ? (
Loading exercises...
) : (

Routine Details

setRoutineName(e.target.value)} placeholder="e.g. Upper Body Strength" required disabled={isSaving} />