From 16c9ff3cee47ce0df2e58378c0bb060641ce20a9 Mon Sep 17 00:00:00 2001 From: kusowl Date: Thu, 15 Jan 2026 19:09:24 +0530 Subject: [PATCH] feat: implement user interaction system with like functionality - Updated interaction models and relations for handling of user-deal interactions. - Added frontend interactivity with `interaction.js` for toggling like buttons. --- app/Enums/InteractionType.php | 1 + .../Controllers/InteractionController.php | 47 +++++++++++++++++++ .../Controllers/RegisteredUserController.php | 1 - app/Models/Deal.php | 6 +-- app/Models/Interaction.php | 19 ++++++-- app/Models/User.php | 5 ++ ...01_14_134306_create_interactions_table.php | 3 +- resources/js/interaction.js | 14 ++++++ .../dashboard/user/action-toolbar.blade.php | 6 ++- .../dashboard/user/listing-card.blade.php | 2 +- .../dashboard/user/listing.blade.php | 1 - resources/views/explore.blade.php | 2 +- routes/web.php | 9 +++- 13 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 app/Http/Controllers/InteractionController.php create mode 100644 resources/js/interaction.js diff --git a/app/Enums/InteractionType.php b/app/Enums/InteractionType.php index e644591..e545e96 100644 --- a/app/Enums/InteractionType.php +++ b/app/Enums/InteractionType.php @@ -10,4 +10,5 @@ enum InteractionType: string case Like = 'like'; case Favorite = 'favorite'; + case Redirection = 'redirect'; } diff --git a/app/Http/Controllers/InteractionController.php b/app/Http/Controllers/InteractionController.php new file mode 100644 index 0000000..a73c74d --- /dev/null +++ b/app/Http/Controllers/InteractionController.php @@ -0,0 +1,47 @@ +interactions() + ->where('user_id', $user->id) + ->where('type', InteractionType::Like) + ->first(); + + // Delete the existing like if exists + if ($existingLike) { + $existingLike->delete(); + + return response()->json(['message' => 'Successfully unliked the post.']); + } + + // Else, create a new like + $data = [ + 'type' => InteractionType::Like, + 'user_id' => Auth::user()->id, + ]; + + Deal::unguard(); + $deal->interactions()->create($data); + Deal::reguard(); + + } catch (\Throwable $e) { + Log::error('Error when liked a deal: id'.$deal->id.$e->getMessage(), $e->getTrace()); + + return response()->json(['error' => 'Something went wrong.'], 500); + } + + return response()->json(['message' => 'Successfully liked the post.']); + } +} diff --git a/app/Http/Controllers/RegisteredUserController.php b/app/Http/Controllers/RegisteredUserController.php index c432273..90a830e 100644 --- a/app/Http/Controllers/RegisteredUserController.php +++ b/app/Http/Controllers/RegisteredUserController.php @@ -20,7 +20,6 @@ public function create() public function store(StoreRegisterdUser $request) { $data = $request->validated(); - try { DB::transaction(function () use ($data) { if ($data['role'] === UserTypes::Broker->value) { diff --git a/app/Models/Deal.php b/app/Models/Deal.php index fd58a98..342e58b 100644 --- a/app/Models/Deal.php +++ b/app/Models/Deal.php @@ -4,7 +4,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Illuminate\Database\Eloquent\Relations\MorphMany; +use Illuminate\Database\Eloquent\Relations\HasMany; class Deal extends Model { @@ -18,8 +18,8 @@ public function category(): BelongsTo return $this->belongsTo(DealCategory::class, 'deal_category_id'); } - public function interactions(): MorphMany + public function interactions(): HasMany { - return $this->morphMany(Interaction::class, 'interactable'); + return $this->hasMany(Interaction::class); } } diff --git a/app/Models/Interaction.php b/app/Models/Interaction.php index 9e8417b..43b8ff0 100644 --- a/app/Models/Interaction.php +++ b/app/Models/Interaction.php @@ -2,13 +2,26 @@ namespace App\Models; +use App\Enums\InteractionType; use Illuminate\Database\Eloquent\Model; -use Illuminate\Database\Eloquent\Relations\MorphTo; +use Illuminate\Database\Eloquent\Relations\BelongsTo; class Interaction extends Model { - public function interactable(): MorphTo + public function user(): BelongsTo { - return $this->morphTo(); + return $this->belongsTo(Deal::class); + } + + public function deal(): BelongsTo + { + return $this->belongsTo(Deal::class); + } + + protected function casts(): array + { + return [ + 'type' => InteractionType::class, + ]; } } diff --git a/app/Models/User.php b/app/Models/User.php index 27d0737..09d60d8 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -68,4 +68,9 @@ public function type(): MorphTo { return $this->morphTo('role'); } + + public function interactions(): HasMany + { + return $this->hasMany(User::class); + } } diff --git a/database/migrations/2026_01_14_134306_create_interactions_table.php b/database/migrations/2026_01_14_134306_create_interactions_table.php index 28a4fa6..7471bbe 100644 --- a/database/migrations/2026_01_14_134306_create_interactions_table.php +++ b/database/migrations/2026_01_14_134306_create_interactions_table.php @@ -19,7 +19,8 @@ public function up(): void $table->foreignIdFor(User::class); $table->foreignIdFor(Deal::class); $table->enum('type', InteractionType::values()); - $table->timestamp('created_at')->useCurrent(); + $table->unsignedBigInteger('count')->default(1); + $table->timestamps(); }); } diff --git a/resources/js/interaction.js b/resources/js/interaction.js new file mode 100644 index 0000000..d778326 --- /dev/null +++ b/resources/js/interaction.js @@ -0,0 +1,14 @@ +async function like(e, id){ + try { + let response = await axios.post('/like/' + id); + + if (response.status === 200) { + let likeBtns = e.querySelectorAll('.like'); + likeBtns.forEach((e) => e.classList.toggle('hidden')) + } + } catch (e) { + console.error(e); + } +} + +document.like = like; diff --git a/resources/views/components/dashboard/user/action-toolbar.blade.php b/resources/views/components/dashboard/user/action-toolbar.blade.php index 7f32ab6..2d7135c 100644 --- a/resources/views/components/dashboard/user/action-toolbar.blade.php +++ b/resources/views/components/dashboard/user/action-toolbar.blade.php @@ -1,6 +1,8 @@ +@props(['id'])
- - + + diff --git a/resources/views/components/dashboard/user/listing-card.blade.php b/resources/views/components/dashboard/user/listing-card.blade.php index 00a815e..437f153 100644 --- a/resources/views/components/dashboard/user/listing-card.blade.php +++ b/resources/views/components/dashboard/user/listing-card.blade.php @@ -5,7 +5,7 @@ {{$deal->category->name}} - +

{{$deal->title}}

diff --git a/resources/views/components/dashboard/user/listing.blade.php b/resources/views/components/dashboard/user/listing.blade.php index a2de9dd..7bcb3de 100644 --- a/resources/views/components/dashboard/user/listing.blade.php +++ b/resources/views/components/dashboard/user/listing.blade.php @@ -1,7 +1,6 @@ @props(['deals' => []])
@forelse($deals as $deal) - @ds($deal) @empty

No Deals found till now !

diff --git a/resources/views/explore.blade.php b/resources/views/explore.blade.php index 971f587..7458624 100644 --- a/resources/views/explore.blade.php +++ b/resources/views/explore.blade.php @@ -88,5 +88,5 @@ - @vite('resources/js/menu.js') + @vite(['resources/js/menu.js', 'resources/js/interaction.js']) diff --git a/routes/web.php b/routes/web.php index 37938e3..17a0890 100644 --- a/routes/web.php +++ b/routes/web.php @@ -7,6 +7,7 @@ use App\Http\Controllers\BrokerDealController; use App\Http\Controllers\ExplorePageController; use App\Http\Controllers\HomeController; +use App\Http\Controllers\InteractionController; use App\Http\Controllers\RegisteredUserController; use App\Http\Middleware\HasRole; use Illuminate\Support\Facades\Route; @@ -14,7 +15,9 @@ Route::get('/', HomeController::class)->name('home'); Route::middleware('guest')->group(function () { - Route::resource('/login', AuthenticatedUserController::class)->only(['create', 'store']); + Route::resource('/login', AuthenticatedUserController::class) + ->middleware('throttle:6,1') + ->only(['create', 'store']); Route::resource('/register', RegisteredUserController::class)->only(['create', 'store']); }); @@ -37,4 +40,8 @@ Route::resource('profile', BrokerProfileController::class)->except('index', 'store', 'create'); }); + + Route::post('/like/{deal}', [InteractionController::class, 'like']) + ->middleware('throttle:30,1') + ->name('like'); });