feature (stats in broker dashboard):

show individual brokers total likes, view and click per deal andin stats
This commit is contained in:
kusowl 2026-01-22 16:36:22 +05:30
parent 3cd2644582
commit 9e7fda4ea2
9 changed files with 58 additions and 14 deletions

View File

@ -0,0 +1,22 @@
<?php
namespace App\Actions;
use App\Enums\InteractionType;
use App\Models\User;
final readonly class GetBrokerStatsAction
{
/**
* @return array<string, int>
*/
public function execute(User $user): array
{
return [
'listings' => $user->deals()->count(),
'likes' => $user->dealsInteractions()->where('type', InteractionType::Like)->count(),
'views' => $user->dealsInteractions()->where('type', InteractionType::View)->sum('count'),
'clicks' => $user->dealsInteractions()->where('type', InteractionType::Redirection)->sum('count'),
];
}
}

View File

@ -2,15 +2,17 @@
namespace App\Http\Controllers\Broker; namespace App\Http\Controllers\Broker;
use App\Actions\GetBrokerStatsAction;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
class BrokerDashboardController extends Controller class BrokerDashboardController extends Controller
{ {
public function index() public function index(GetBrokerStatsAction $getBrokerStatsAction)
{ {
return view('dashboards.broker.index') return view('dashboards.broker.index')
->with('deals', $this->deals()); ->with('deals', $this->deals())
->with('stats', $getBrokerStatsAction->execute(Auth::user()));
} }
protected function deals() protected function deals()
@ -28,6 +30,9 @@ protected function deals()
'deal_category_id', 'deal_category_id',
]) ])
->with('category:id,name') ->with('category:id,name')
->WithLikePerDeal()
->WithRedirectionPerDeal()
->withViewPerDeal()
->latest() ->latest()
->paginate(); ->paginate();
} }

View File

@ -99,7 +99,6 @@ public function redirect(Deal $deal)
public function view(Deal $deal) public function view(Deal $deal)
{ {
ds('hi');
try { try {
$interaction = $deal->interactions()->firstOrCreate([ $interaction = $deal->interactions()->firstOrCreate([
'type' => InteractionType::View, 'type' => InteractionType::View,
@ -109,7 +108,6 @@ public function view(Deal $deal)
if (! $interaction->wasRecentlyCreated) { if (! $interaction->wasRecentlyCreated) {
$interaction->increment('count'); $interaction->increment('count');
} }
ds($interaction);
} catch (\Throwable $e) { } catch (\Throwable $e) {
Log::error('Error when view a deal', Log::error('Error when view a deal',

View File

@ -86,6 +86,19 @@ public function WithRedirectionPerDeal(Builder $query): Builder
], 'count'); ], 'count');
} }
/**
* Scope a query to get a view count per deal
*/
#[Scope]
public function withViewPerDeal(Builder $query): Builder
{
return $query->withSum([
'interactions as total_views' => function ($query) {
$query->where('type', InteractionType::View);
},
], 'count');
}
/** /**
* Scope a search in a query * Scope a search in a query
*/ */
@ -105,4 +118,5 @@ public function filterByCategory(Builder $query, string $category): Builder
{ {
return $query->where('deal_category_id', $category); return $query->where('deal_category_id', $category);
} }
} }

View File

@ -6,6 +6,7 @@
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\MorphTo; use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable; use Illuminate\Notifications\Notifiable;
@ -78,4 +79,9 @@ public function recentSearches(): HasMany
{ {
return $this->hasMany(RecentSearch::class); return $this->hasMany(RecentSearch::class);
} }
public function dealsInteractions(): HasManyThrough
{
return $this->hasManyThrough(Interaction::class, Deal::class);
}
} }

View File

@ -1,5 +1,4 @@
@props(['deal']) @props(['deal'])
<x-ui.image-card :image="asset('storage/'.$deal->image)"> <x-ui.image-card :image="asset('storage/'.$deal->image)">
<div class="bg-white pt-8 p-4 h-full space-y-4 flex flex-col justify-between"> <div class="bg-white pt-8 p-4 h-full space-y-4 flex flex-col justify-between">
<div class="flex justify-between items-start"> <div class="flex justify-between items-start">
@ -27,7 +26,7 @@ class="text-xs underline text-accent-601 mt-1">
<div class="flex flex-col space-y-4"> <div class="flex flex-col space-y-4">
<p class="text-accent-600">{{$deal->category->name}}</p> <p class="text-accent-600">{{$deal->category->name}}</p>
<x-dashboard.broker.listing-stats impression="0" likes="0" clicks="0"/> <x-dashboard.broker.listing-stats :views="$deal->total_views ?? 0" :likes="$deal->total_likes ?? 0" :clicks="$deal->total_redirection ?? 0"/>
<div class="flex justify-between space-x-4"> <div class="flex justify-between space-x-4">
<x-ui.button :link="route('broker.deals.edit', $deal->id)" class="w-full border border-accent-600/30" <x-ui.button :link="route('broker.deals.edit', $deal->id)" class="w-full border border-accent-600/30"

View File

@ -1,8 +1,8 @@
@props(['impression' => 0, 'likes' => 0, 'clicks' => 0]) @props(['views' => 0, 'likes' => 0, 'clicks' => 0])
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div class=" text-accent-600 flex space-x-2"> <div class=" text-accent-600 flex space-x-2">
<x-heroicon-o-eye class="w-4"/> <x-heroicon-o-eye class="w-4"/>
<p class="text-sm">{{$impression}}</p> <p class="text-sm">{{$views}}</p>
</div> </div>
<div class=" text-accent-600 flex space-x-2"> <div class=" text-accent-600 flex space-x-2">

View File

@ -1,22 +1,22 @@
@props(['list_count' => 0]) @props(['stats' => []])
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 wrapper gap-y-4 gap-x-8"> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 wrapper gap-y-4 gap-x-8">
<x-dashboard.stats-card title="My Listings" :score="$list_count"> <x-dashboard.stats-card title="My Listings" :score="$stats['listings']">
<x-icon-square variant="blue"> <x-icon-square variant="blue">
<x-heroicon-o-document-text class="w-8" /> <x-heroicon-o-document-text class="w-8" />
</x-icon-square> </x-icon-square>
</x-dashboard.stats-card> </x-dashboard.stats-card>
<x-dashboard.stats-card title="Total Views" score="12,483"> <x-dashboard.stats-card title="Total Views" :score="$stats['views'] ?? 0">
<x-icon-square variant="purple"> <x-icon-square variant="purple">
<x-heroicon-o-eye class="w-8" /> <x-heroicon-o-eye class="w-8" />
</x-icon-square> </x-icon-square>
</x-dashboard.stats-card> </x-dashboard.stats-card>
<x-dashboard.stats-card title="Total Likes" score="1,847"> <x-dashboard.stats-card title="Total Likes" :score="$stats['likes'] ?? 0">
<x-icon-square variant="pink"> <x-icon-square variant="pink">
<x-heroicon-o-heart class="w-8" /> <x-heroicon-o-heart class="w-8" />
</x-icon-square> </x-icon-square>
</x-dashboard.stats-card> </x-dashboard.stats-card>
<x-dashboard.stats-card title="Total Clicks" score="3,246"> <x-dashboard.stats-card title="Total Clicks" :score="$stats['clicks'] ?? 0">
<x-icon-square variant="green"> <x-icon-square variant="green">
<x-heroicon-o-cursor-arrow-rays class="w-8" /> <x-heroicon-o-cursor-arrow-rays class="w-8" />
</x-icon-square> </x-icon-square>

View File

@ -2,6 +2,6 @@
<x-slot:heading> <x-slot:heading>
<x-dashboard.broker.navbar/> <x-dashboard.broker.navbar/>
</x-slot:heading> </x-slot:heading>
<x-dashboard.broker.stats :list_count="$deals->count()"/> <x-dashboard.broker.stats :stats="$stats"/>
<x-dashboard.broker.listing :deals="$deals"/> <x-dashboard.broker.listing :deals="$deals"/>
</x-dashboard.broker.layout> </x-dashboard.broker.layout>