Add multi-week workout programs

A Workout was a single flat session with no way to schedule several
across weeks/days as a structured plan (e.g. Push/Pull/Legs over 4
weeks) - every user started from a blank builder each time, and there
was no template concept at all.

Adds a Program (title, description, week count) that Workouts can
optionally belong to via nullable program_id/week_number/day_number
columns, reusing all existing workout and session-tracking
infrastructure rather than building a parallel system. The program show
page lays out the schedule week by week and derives progress (completed
vs total) from the user's existing WorkoutSession completions - no new
enrollment/progress-tracking concept needed. Deleting a program
unschedules its workouts (nullOnDelete) rather than destroying them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-10 12:21:47 +03:00
co-authored by Claude Sonnet 5
parent fa8bf46f8a
commit ebd0578dc9
15 changed files with 564 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
<x-app-layout>
<section class="bg-white dark:bg-gray-900 border-b border-gray-100 dark:border-gray-800">
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-8">
<div class="flex items-center justify-between">
<div>
<h1 class="text-2xl sm:text-3xl font-extrabold tracking-tight text-gray-900 dark:text-white">My Programs</h1>
<p class="mt-2 text-gray-600 dark:text-gray-300">Multi-week training plans built from your workouts.</p>
</div>
<a href="{{ route('programs.create') }}" class="inline-flex items-center rounded-xl bg-gradient-to-r from-fuchsia-600 to-indigo-600 px-4 py-2 text-sm font-semibold text-white shadow hover:from-fuchsia-500 hover:to-indigo-500">New Program</a>
</div>
</div>
</section>
<section class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-6">
@if(session('status'))
<div class="mb-4 rounded-xl bg-emerald-50 text-emerald-700 px-4 py-3">{{ session('status') }}</div>
@endif
@if($programs->count() === 0)
<div class="rounded-2xl border border-dashed border-gray-300 dark:border-gray-700 p-8 text-center text-gray-600 dark:text-gray-300">No programs yet. Build a multi-week plan to schedule your workouts across weeks.</div>
@else
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
@foreach($programs as $program)
<a href="{{ route('programs.show', $program) }}" class="rounded-2xl ring-1 ring-gray-200 dark:ring-gray-700 bg-white dark:bg-gray-800 p-5 hover:shadow-lg transition">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">{{ $program->title }}</h3>
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">{{ $program->weeks }} weeks &middot; {{ $program->workouts_count }} workouts</p>
@if($program->description)
<p class="mt-2 text-sm text-gray-600 dark:text-gray-300 line-clamp-3">{{ $program->description }}</p>
@endif
</a>
@endforeach
</div>
<div class="mt-6">{{ $programs->links() }}</div>
@endif
</section>
</x-app-layout>