MCPcopy Create free account
hub / github.com/Cawlumm/lyftr / AddProgram

Function AddProgram

web/src/pages/AddProgram.tsx:22–288  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

20 const [loading, setLoading] = useState(false)
21 const [error, setError] = useState('')
22 const [pickerExercises, setPickerExercises] = useState<Record<number, types.Exercise>>({})
23 const [formData, setFormData] = useState<ProgramFormData>({ name: '', notes: '', days: [] })
24
25 useEffect(() => { if (error) window.scrollTo({ top: 0, behavior: 'smooth' }) }, [error])
26
27 const cacheExercise = (ex: types.Exercise) => setPickerExercises(prev => ({ ...prev, [ex.id]: ex }))
28
29 const handleSubmit = async (e: React.FormEvent) => {
30 e.preventDefault()
31 if (!formData.name.trim()) { setError('Program name required'); return }
32 if (formData.days.length === 0) { setError('Add at least one day'); return }
33 const hasAnyExercise = hasWorkoutExercises(formData.days)
34 if (!hasAnyExercise) { setError('Add at least one exercise to a workout day'); return }
35 setLoading(true)
36 try {
37 const payload = {
38 name: formData.name,
39 notes: formData.notes,
40 days: formData.days.map(d => ({
41 ...d,
42 exercises: d.exercises.map(ex => ({
43 ...ex,
44 sets: ex.sets.map(s => ({ ...s, target_weight: displayToLbs(s.target_weight, settings.weight_unit) })),
45 })),
46 })),
47 }
48 await programAPI.create(payload)
49 navigate('/programs')
50 } catch (err: any) {
51 setError(err.response?.data?.error || 'Failed to create program')
52 } finally {
53 setLoading(false)
54 }
55 }
56
57 const totalExercises = formData.days.reduce((s, d) => s + d.exercises.length, 0)
58 const totalSets = formData.days.reduce((s, d) => s + d.exercises.reduce((s2, ex) => s2 + ex.sets.length, 0), 0)
59
60 return (
61 <div className="space-y-6 animate-slide-up pb-10">
62 <div className="flex items-center gap-3">
63 <button aria-label="Go back" onClick={() => navigate(-1)} className="p-2 hover:bg-surface-muted rounded-lg transition-colors">
64 <ArrowLeft className="w-5 h-5 text-tx-muted" />
65 </button>
66 <div>
67 <h1 className="font-display font-bold text-2xl text-tx-primary">New Program</h1>
68 <p className="text-xs text-tx-muted">
69 {formData.days.length} day{formData.days.length === 1 ? '' : 's'} • {totalExercises} exercise{totalExercises === 1 ? '' : 's'} • {totalSets} set{totalSets === 1 ? '' : 's'}
70 </p>
71 </div>
72 </div>
73
74 <form onSubmit={handleSubmit} className="space-y-6">
75 {error && (
76 <div className="alert-error">
77 <AlertCircle className="w-4 h-4 flex-shrink-0" />
78 <span>{error}</span>
79 </div>

Callers

nothing calls this directly

Calls 6

weightShortFunction · 0.90
removeExerciseFunction · 0.70
setExRestFunction · 0.70
updateSetFunction · 0.70
removeSetFunction · 0.70
addSetFunction · 0.70

Tested by

no test coverage detected