2025-10-04 17:55:30 +03:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
|
|
|
|
|
|
use App\Models\Workout;
|
|
|
|
|
use App\Models\WorkoutExercise;
|
|
|
|
|
use App\Models\WorkoutSession;
|
|
|
|
|
use App\Models\WorkoutSessionItem;
|
|
|
|
|
use Illuminate\Http\RedirectResponse;
|
|
|
|
|
use Illuminate\Http\Request;
|
|
|
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
|
use Illuminate\View\View;
|
|
|
|
|
|
|
|
|
|
class WorkoutSessionController extends Controller
|
|
|
|
|
{
|
|
|
|
|
public function store(Request $request, Workout $workout): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeWorkout($workout);
|
|
|
|
|
|
|
|
|
|
$session = WorkoutSession::create([
|
|
|
|
|
'user_id' => Auth::id(),
|
|
|
|
|
'workout_id' => $workout->id,
|
|
|
|
|
'started_at' => now(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
// Pre-create items for convenience
|
|
|
|
|
$workout->loadMissing('items');
|
|
|
|
|
foreach ($workout->items as $item) {
|
|
|
|
|
WorkoutSessionItem::create([
|
|
|
|
|
'session_id' => $session->id,
|
|
|
|
|
'workout_exercise_id' => $item->id,
|
|
|
|
|
'done' => false,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return redirect()->route('sessions.show', $session);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function show(WorkoutSession $session): View
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeSession($session);
|
|
|
|
|
$session->load(['workout.items.exercise', 'items']);
|
|
|
|
|
|
|
|
|
|
// Index session items by workout_exercise_id for quick lookup
|
|
|
|
|
$doneByItemId = $session->items->keyBy('workout_exercise_id');
|
|
|
|
|
|
|
|
|
|
return view('workouts.session', [
|
|
|
|
|
'session' => $session,
|
|
|
|
|
'workout' => $session->workout,
|
|
|
|
|
'doneByItemId' => $doneByItemId,
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function toggleItem(Request $request, WorkoutSession $session, WorkoutExercise $item): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeSession($session);
|
|
|
|
|
if ($item->workout_id !== $session->workout_id) {
|
|
|
|
|
abort(404);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-10 12:15:14 +03:00
|
|
|
$data = $request->validate([
|
|
|
|
|
'actual_weight' => ['nullable', 'numeric', 'min:0', 'max:9999.99'],
|
|
|
|
|
'actual_reps' => ['nullable', 'integer', 'min:0', 'max:1000'],
|
|
|
|
|
]);
|
|
|
|
|
|
2025-10-04 17:55:30 +03:00
|
|
|
$si = WorkoutSessionItem::firstOrCreate([
|
|
|
|
|
'session_id' => $session->id,
|
|
|
|
|
'workout_exercise_id' => $item->id,
|
|
|
|
|
], [
|
|
|
|
|
'done' => false,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
$si->done = !$si->done;
|
2026-08-10 12:15:14 +03:00
|
|
|
if ($si->done) {
|
|
|
|
|
if (array_key_exists('actual_weight', $data) && $data['actual_weight'] !== null) {
|
|
|
|
|
$si->actual_weight = $data['actual_weight'];
|
|
|
|
|
}
|
|
|
|
|
if (array_key_exists('actual_reps', $data) && $data['actual_reps'] !== null) {
|
|
|
|
|
$si->actual_reps = $data['actual_reps'];
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-10-04 17:55:30 +03:00
|
|
|
$si->save();
|
|
|
|
|
|
|
|
|
|
return back();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function complete(WorkoutSession $session): RedirectResponse
|
|
|
|
|
{
|
|
|
|
|
$this->authorizeSession($session);
|
|
|
|
|
$session->completed_at = now();
|
|
|
|
|
$session->save();
|
|
|
|
|
return redirect()->route('workouts.show', $session->workout)->with('status', __('app.sessions.completed'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function authorizeWorkout(Workout $workout): void
|
|
|
|
|
{
|
|
|
|
|
if ($workout->user_id !== Auth::id()) {
|
|
|
|
|
abort(403);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function authorizeSession(WorkoutSession $session): void
|
|
|
|
|
{
|
|
|
|
|
if ($session->user_id !== Auth::id()) {
|
|
|
|
|
abort(403);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|