Merge branch 'feature/broker-dashboard'

# Conflicts:
#	app/Models/User.php
This commit is contained in:
kusowl 2026-01-22 19:14:15 +05:30
commit 45196cba56
8 changed files with 59 additions and 12 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;
use App\Actions\GetBrokerStatsAction;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
class BrokerDashboardController extends Controller
{
public function index()
public function index(GetBrokerStatsAction $getBrokerStatsAction)
{
return view('dashboards.broker.index')
->with('deals', $this->deals());
->with('deals', $this->deals())
->with('stats', $getBrokerStatsAction->execute(Auth::user()));
}
protected function deals()
@ -28,6 +30,9 @@ protected function deals()
'deal_category_id',
])
->with('category:id,name')
->WithLikePerDeal()
->WithRedirectionPerDeal()
->withViewPerDeal()
->latest()
->paginate();
}

View File

@ -86,6 +86,19 @@ public function WithRedirectionPerDeal(Builder $query): Builder
], '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
*/
@ -105,4 +118,5 @@ public function filterByCategory(Builder $query, string $category): Builder
{
return $query->where('deal_category_id', $category);
}
}

View File

@ -4,7 +4,9 @@
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
@ -82,4 +84,9 @@ public function isCustomer(): bool
{
return $this->type instanceof Customer;
}
public function dealsInteractions(): HasManyThrough
{
return $this->hasManyThrough(Interaction::class, Deal::class);
}
}

View File

@ -1,5 +1,4 @@
@props(['deal'])
<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="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">
<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">
<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=" text-accent-600 flex space-x-2">
<x-heroicon-o-eye class="w-4"/>
<p class="text-sm">{{$impression}}</p>
<p class="text-sm">{{$views}}</p>
</div>
<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">
<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-heroicon-o-document-text class="w-8" />
</x-icon-square>
</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-heroicon-o-eye class="w-8" />
</x-icon-square>
</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-heroicon-o-heart class="w-8" />
</x-icon-square>
</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-heroicon-o-cursor-arrow-rays class="w-8" />
</x-icon-square>

View File

@ -2,6 +2,6 @@
<x-slot:heading>
<x-dashboard.broker.navbar/>
</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.layout>