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.
This commit is contained in:
parent
a82e1b6b06
commit
16c9ff3cee
@ -10,4 +10,5 @@ enum InteractionType: string
|
||||
|
||||
case Like = 'like';
|
||||
case Favorite = 'favorite';
|
||||
case Redirection = 'redirect';
|
||||
}
|
||||
|
||||
47
app/Http/Controllers/InteractionController.php
Normal file
47
app/Http/Controllers/InteractionController.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Enums\InteractionType;
|
||||
use App\Models\Deal;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class InteractionController extends Controller
|
||||
{
|
||||
public function like(Deal $deal)
|
||||
{
|
||||
try {
|
||||
// Check for existing like of the user with deal
|
||||
$user = Auth::user();
|
||||
$existingLike = $deal->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.']);
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,4 +68,9 @@ public function type(): MorphTo
|
||||
{
|
||||
return $this->morphTo('role');
|
||||
}
|
||||
|
||||
public function interactions(): HasMany
|
||||
{
|
||||
return $this->hasMany(User::class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
14
resources/js/interaction.js
Normal file
14
resources/js/interaction.js
Normal file
@ -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;
|
||||
@ -1,6 +1,8 @@
|
||||
@props(['id'])
|
||||
<div class="">
|
||||
<x-ui.button-sm class="text-accent-600">
|
||||
<x-heroicon-o-heart class="w-4"/>
|
||||
<x-ui.button-sm class="text-accent-600" onclick="like(this, {{$id}})">
|
||||
<x-heroicon-o-heart class="like w-4"/>
|
||||
<x-heroicon-s-heart class="like w-4 hidden text-red-500"/>
|
||||
</x-ui.button-sm>
|
||||
|
||||
<x-ui.button-sm class="text-accent-600">
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<x-ui.button-sm variant="neutral">
|
||||
{{$deal->category->name}}
|
||||
</x-ui.button-sm>
|
||||
<x-dashboard.user.action-toolbar />
|
||||
<x-dashboard.user.action-toolbar :id="$deal->id" />
|
||||
</div>
|
||||
|
||||
<p class="font-bold text-lg ">{{$deal->title}}</p>
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
@props(['deals' => []])
|
||||
<div class="grid md:grid-cols-2 gap-6">
|
||||
@forelse($deals as $deal)
|
||||
@ds($deal)
|
||||
<x-dashboard.user.listing-card :deal="$deal" :broker="$deal->broker"/>
|
||||
@empty
|
||||
<p class="col-span-2 text-sm text-center text-accent-600">No Deals found till now !</p>
|
||||
|
||||
@ -88,5 +88,5 @@
|
||||
|
||||
<x-dashboard.user.listing :deals="$deals"/>
|
||||
</section>
|
||||
@vite('resources/js/menu.js')
|
||||
@vite(['resources/js/menu.js', 'resources/js/interaction.js'])
|
||||
</x-layout>
|
||||
|
||||
@ -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');
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user