From 1ed9235451bd7b6f9e767a8894688880613947e8 Mon Sep 17 00:00:00 2001 From: DoarMihai Date: Thu, 2 Oct 2025 23:52:07 +0300 Subject: [PATCH] favorites --- app/Http/Controllers/FavoriteController.php | 47 +++++++++++++++++++ app/Models/Exercise.php | 5 ++ app/Models/User.php | 21 +++++++++ app/Models/Workout.php | 5 ++ ...000003_create_exercise_favorites_table.php | 24 ++++++++++ ..._000004_create_workout_favorites_table.php | 24 ++++++++++ resources/views/exercises/show.blade.php | 20 +++++++- resources/views/layouts/app.blade.php | 15 ++++++ resources/views/layouts/navigation.blade.php | 10 ++++ resources/views/workouts/show.blade.php | 20 +++++++- routes/web.php | 4 ++ tailwind.config.js | 1 + 12 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 app/Http/Controllers/FavoriteController.php create mode 100644 database/migrations/2025_10_02_000003_create_exercise_favorites_table.php create mode 100644 database/migrations/2025_10_02_000004_create_workout_favorites_table.php diff --git a/app/Http/Controllers/FavoriteController.php b/app/Http/Controllers/FavoriteController.php new file mode 100644 index 0000000..7ca7a3d --- /dev/null +++ b/app/Http/Controllers/FavoriteController.php @@ -0,0 +1,47 @@ +middleware('auth'); + } + + public function toggleExercise(Exercise $exercise): RedirectResponse + { + $user = Auth::user(); + $exists = $user->favoriteExercises()->where('exercise_id', $exercise->id)->exists(); + if ($exists) { + $user->favoriteExercises()->detach($exercise->id); + $msg = 'Removed from favorites'; + } else { + $user->favoriteExercises()->attach($exercise->id); + $msg = 'Added to favorites'; + } + return back()->with('status', $msg); + } + + public function toggleWorkout(Workout $workout): RedirectResponse + { + $user = Auth::user(); + if ($workout->user_id && $workout->user_id !== $user->id) { + // Users can still favorite others' workouts if shared later; for now no restriction besides existence + } + $exists = $user->favoriteWorkouts()->where('workout_id', $workout->id)->exists(); + if ($exists) { + $user->favoriteWorkouts()->detach($workout->id); + $msg = 'Removed from favorites'; + } else { + $user->favoriteWorkouts()->attach($workout->id); + $msg = 'Added to favorites'; + } + return back()->with('status', $msg); + } +} diff --git a/app/Models/Exercise.php b/app/Models/Exercise.php index 0602485..084262b 100644 --- a/app/Models/Exercise.php +++ b/app/Models/Exercise.php @@ -39,4 +39,9 @@ class Exercise extends Model { return $this->hasMany(WorkoutExercise::class); } + + public function favoritedBy() + { + return $this->belongsToMany(User::class, 'exercise_favorites')->withTimestamps(); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 9c81b89..072caa3 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -51,4 +51,25 @@ class User extends Authenticatable { return $this->hasMany(Workout::class); } + + public function favoriteExercises() + { + return $this->belongsToMany(Exercise::class, 'exercise_favorites')->withTimestamps(); + } + + public function favoriteWorkouts() + { + return $this->belongsToMany(Workout::class, 'workout_favorites')->withTimestamps(); + } + + // Helpers + public function hasFavoritedExercise(Exercise $exercise): bool + { + return $this->favoriteExercises()->where('exercise_id', $exercise->id)->exists(); + } + + public function hasFavoritedWorkout(Workout $workout): bool + { + return $this->favoriteWorkouts()->where('workout_id', $workout->id)->exists(); + } } diff --git a/app/Models/Workout.php b/app/Models/Workout.php index 81cbb53..e5d821b 100644 --- a/app/Models/Workout.php +++ b/app/Models/Workout.php @@ -40,4 +40,9 @@ class Workout extends Model ->withTimestamps() ->orderBy('workout_exercises.position'); } + + public function favoritedBy() + { + return $this->belongsToMany(User::class, 'workout_favorites')->withTimestamps(); + } } diff --git a/database/migrations/2025_10_02_000003_create_exercise_favorites_table.php b/database/migrations/2025_10_02_000003_create_exercise_favorites_table.php new file mode 100644 index 0000000..d72cfff --- /dev/null +++ b/database/migrations/2025_10_02_000003_create_exercise_favorites_table.php @@ -0,0 +1,24 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('exercise_id')->constrained('exercises')->cascadeOnDelete(); + $table->timestamps(); + $table->unique(['user_id', 'exercise_id']); + }); + } + + public function down(): void + { + Schema::dropIfExists('exercise_favorites'); + } +}; diff --git a/database/migrations/2025_10_02_000004_create_workout_favorites_table.php b/database/migrations/2025_10_02_000004_create_workout_favorites_table.php new file mode 100644 index 0000000..3187cc6 --- /dev/null +++ b/database/migrations/2025_10_02_000004_create_workout_favorites_table.php @@ -0,0 +1,24 @@ +id(); + $table->foreignId('user_id')->constrained()->cascadeOnDelete(); + $table->foreignId('workout_id')->constrained('workouts')->cascadeOnDelete(); + $table->timestamps(); + $table->unique(['user_id', 'workout_id']); + }); + } + + public function down(): void + { + Schema::dropIfExists('workout_favorites'); + } +}; diff --git a/resources/views/exercises/show.blade.php b/resources/views/exercises/show.blade.php index 26aa825..ad75a4a 100644 --- a/resources/views/exercises/show.blade.php +++ b/resources/views/exercises/show.blade.php @@ -8,7 +8,25 @@ ← Back -

{{ $exercise->name }}

+
+

{{ $exercise->name }}

+ @auth + @php $isFav = auth()->user()->hasFavoritedExercise($exercise); @endphp +
+ @csrf + +
+ @endauth +
@foreach($exercise->bodyParts as $bp) {{ $bp->name }} diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 0a471a4..d1ac6be 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -11,6 +11,21 @@ + + @vite(['resources/css/app.css', 'resources/js/app.js']) diff --git a/resources/views/layouts/navigation.blade.php b/resources/views/layouts/navigation.blade.php index 3d38223..e6cc75c 100644 --- a/resources/views/layouts/navigation.blade.php +++ b/resources/views/layouts/navigation.blade.php @@ -20,6 +20,10 @@