'use client'; import React, { useState, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { motion } from 'framer-motion'; import { Plus, Trash2, Save, ArrowLeft, Copy, Layers, GripVertical } from 'lucide-react'; import Link from 'next/link'; import { useAuth, AuthProvider } from '@/lib/auth'; interface ExerciseItem { id: string; name: string; reps: number; weight: number; rest_time_seconds: number; } interface RoundData { id: string; exercises: ExerciseItem[]; } export default function CreateMenuPageWrap() { return ( ); } function CreateMenuPage() { const router = useRouter(); const { user } = useAuth(); const [isSubmitting, setIsSubmitting] = useState(false); const [menuName, setMenuName] = useState(''); // Round-Based State const [rounds, setRounds] = useState([ { id: 'round-1', exercises: [ { id: 'ex-1', name: 'Squat', reps: 10, weight: 20, rest_time_seconds: 30 } ] } ]); const [clients, setClients] = useState([]); const [selectedClient, setSelectedClient] = useState(''); useEffect(() => { if (user) { fetch(`/api/users?coachId=${encodeURIComponent(user.id)}`) .then(res => res.json()) .then(data => { if (Array.isArray(data)) setClients(data); }); } }, [user]); // --- Actions --- const addRound = () => { setRounds([...rounds, { id: Math.random().toString(36).substr(2, 9), exercises: [] }]); }; const duplicateRound = (sourceIndex: number) => { const source = rounds[sourceIndex]; const newExercises = source.exercises.map(ex => ({ ...ex, id: Math.random().toString(36).substr(2, 9) })); setRounds([...rounds, { id: Math.random().toString(36).substr(2, 9), exercises: newExercises }]); }; const removeRound = (index: number) => { setRounds(rounds.filter((_, i) => i !== index)); }; const addExerciseToRound = (roundIndex: number) => { const newRounds = [...rounds]; newRounds[roundIndex].exercises.push({ id: Math.random().toString(36).substr(2, 9), name: 'Bicep Curl', reps: 10, weight: 10, rest_time_seconds: 30 }); setRounds(newRounds); }; const removeExerciseFromRound = (roundIndex: number, exIndex: number) => { const newRounds = [...rounds]; newRounds[roundIndex].exercises = newRounds[roundIndex].exercises.filter((_, i) => i !== exIndex); setRounds(newRounds); }; const updateExercise = (roundIndex: number, exIndex: number, field: keyof ExerciseItem, value: any) => { const newRounds = [...rounds]; newRounds[roundIndex].exercises[exIndex] = { ...newRounds[roundIndex].exercises[exIndex], [field]: value }; setRounds(newRounds); }; // --- Submit Logic (Flattening) --- // We assume the user creates rounds sequentially: Set 1, Set 2. // So distinct Sets of "Squat" will imply Set 1, Set 2 logic naturally in the list. const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); setIsSubmitting(true); try { if (!selectedClient) { alert("Please select a client."); setIsSubmitting(false); return; } // FLATTEN ROUNDS const flatList: any[] = []; const counts: Record = {}; const totals: Record = {}; // 1. Calculate Totals (First Pass) rounds.forEach(round => { round.exercises.forEach(ex => { totals[ex.name] = (totals[ex.name] || 0) + 1; }); }); // 2. Flatten and Assign Indices rounds.forEach((round, roundIndex) => { round.exercises.forEach(ex => { counts[ex.name] = (counts[ex.name] || 0) + 1; flatList.push({ name: ex.name, reps: ex.reps, weight: ex.weight, rest_time_seconds: ex.rest_time_seconds, // This corresponds to "Which instance of Squat is this?" -> Set Number set_index: counts[ex.name], total_sets: totals[ex.name] }); }); }); const res = await fetch('/api/menus', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-user-id': user?.id || '' }, body: JSON.stringify({ name: menuName, exercises: flatList, client_id: selectedClient }) }); if (!res.ok) throw new Error('Failed'); router.push('/coach/dashboard'); } catch (error) { alert('Error creating menu'); } finally { setIsSubmitting(false); } }; const EXERCISE_OPTIONS = [ "Bicep Curl", "Hammer Curl", "Squat", "Deadlift", "Lunges", "Overhead Press", "Lateral Raises" ]; return (

Program Composer

Design training blocks set-by-set.

{/* Meta Info */}
setMenuName(e.target.value)} className="w-full text-xl font-bold border-b-2 border-zinc-100 focus:border-primary outline-none py-2 transition-colors placeholder:font-normal" />
{/* Rounds */}
{rounds.map((round, roundIndex) => (

#{ (roundIndex + 1).toString().padStart(2, '0') } SET

{/* Exercises in Round */}
{round.exercises.map((ex, exIndex) => (
updateExercise(roundIndex, exIndex, 'reps', parseInt(e.target.value))} className="w-full md:w-16 bg-zinc-50 border border-zinc-100 rounded-lg px-2 py-1.5 text-center font-mono text-sm focus:border-primary outline-none" />
updateExercise(roundIndex, exIndex, 'weight', parseFloat(e.target.value))} className="w-full md:w-16 bg-zinc-50 border border-zinc-100 rounded-lg px-2 py-1.5 text-center font-mono text-sm focus:border-primary outline-none" />
updateExercise(roundIndex, exIndex, 'rest_time_seconds', parseFloat(e.target.value))} className="w-full md:w-16 bg-zinc-50 border border-zinc-100 rounded-lg px-2 py-1.5 text-center font-mono text-sm focus:border-primary outline-none" />
))}
))}
); }