programs()->withCount('workouts')->latest()->paginate(10); return response()->json([ 'data' => ProgramResource::collection($programs->items()), 'meta' => [ 'current_page' => $programs->currentPage(), 'last_page' => $programs->lastPage(), 'per_page' => $programs->perPage(), 'total' => $programs->total(), ], ]); } public function store(Request $request): JsonResponse { $data = $request->validate([ 'title' => ['required', 'string', 'max:255'], 'description' => ['nullable', 'string'], 'weeks' => ['required', 'integer', 'min:1', 'max:52'], ]); $program = Auth::user()->programs()->create($data); return response()->json(['program' => new ProgramResource($program)], 201); } public function show(Program $program): JsonResponse { $this->authorizeProgram($program); $program->load('workouts'); $completedWorkoutIds = WorkoutSession::query() ->where('user_id', Auth::id()) ->whereIn('workout_id', $program->workouts->pluck('id')) ->whereNotNull('completed_at') ->pluck('workout_id') ->unique(); $totalWorkouts = $program->workouts->count(); $completedCount = $completedWorkoutIds->count(); $progressPct = $totalWorkouts > 0 ? (int) round(($completedCount / $totalWorkouts) * 100) : 0; return response()->json([ 'program' => new ProgramResource($program), 'completed_workout_ids' => $completedWorkoutIds->values(), 'progress_pct' => $progressPct, 'completed_count' => $completedCount, 'total_workouts' => $totalWorkouts, ]); } public function destroy(Program $program): JsonResponse { $this->authorizeProgram($program); $program->delete(); return response()->json(['message' => 'Program deleted']); } public function addWorkout(Request $request, Program $program): JsonResponse { $this->authorizeProgram($program); $data = $request->validate([ 'title' => ['required', 'string', 'max:255'], 'week_number' => ['required', 'integer', 'min:1', 'max:'.$program->weeks], 'day_number' => ['required', 'integer', 'min:1', 'max:14'], 'estimated_minutes' => ['nullable', 'integer', 'min:1', 'max:600'], ]); $workout = $program->workouts()->create([ 'user_id' => Auth::id(), 'title' => $data['title'], 'estimated_minutes' => $data['estimated_minutes'] ?? null, 'week_number' => $data['week_number'], 'day_number' => $data['day_number'], ]); return response()->json(['workout_id' => $workout->id, 'message' => 'Workout added to program'], 201); } protected function authorizeProgram(Program $program): void { if ($program->user_id !== Auth::id()) { abort(403); } } }