libra/resources/views/livewire/admin/dashboard.blade.php

260 lines
13 KiB
PHP

<?php
use App\Enums\ConsultationStatus;
use App\Enums\ConsultationType;
use App\Enums\PostStatus;
use App\Enums\TimelineStatus;
use App\Enums\UserStatus;
use App\Enums\UserType;
use App\Models\Consultation;
use App\Models\Post;
use App\Models\Timeline;
use App\Models\TimelineUpdate;
use App\Models\User;
use Illuminate\Support\Facades\Cache;
use Livewire\Volt\Component;
new class extends Component
{
public function getTitle(): string
{
return __('admin_metrics.title');
}
public function with(): array
{
return [
'userMetrics' => $this->getUserMetrics(),
'bookingMetrics' => $this->getBookingMetrics(),
'timelineMetrics' => $this->getTimelineMetrics(),
'postMetrics' => $this->getPostMetrics(),
];
}
private function getUserMetrics(): array
{
return Cache::remember('admin.metrics.users', 300, fn () => [
'total_active' => User::query()
->where('status', UserStatus::Active)
->whereIn('user_type', [UserType::Individual, UserType::Company])
->count(),
'individual' => User::query()
->where('user_type', UserType::Individual)
->where('status', UserStatus::Active)
->count(),
'company' => User::query()
->where('user_type', UserType::Company)
->where('status', UserStatus::Active)
->count(),
'deactivated' => User::query()
->where('status', UserStatus::Deactivated)
->whereIn('user_type', [UserType::Individual, UserType::Company])
->count(),
'new_this_month' => User::query()
->whereIn('user_type', [UserType::Individual, UserType::Company])
->whereMonth('created_at', now()->month)
->whereYear('created_at', now()->year)
->count(),
]);
}
private function getBookingMetrics(): array
{
return Cache::remember('admin.metrics.bookings', 300, function () {
$total = Consultation::query()
->whereIn('status', [ConsultationStatus::Completed, ConsultationStatus::NoShow])
->count();
$noShows = Consultation::query()
->where('status', ConsultationStatus::NoShow)
->count();
return [
'pending' => Consultation::query()
->where('status', ConsultationStatus::Pending)
->count(),
'today' => Consultation::query()
->whereDate('booking_date', today())
->where('status', ConsultationStatus::Approved)
->count(),
'this_week' => Consultation::query()
->whereBetween('booking_date', [now()->startOfWeek(), now()->endOfWeek()])
->whereIn('status', [ConsultationStatus::Approved, ConsultationStatus::Pending])
->count(),
'this_month' => Consultation::query()
->whereMonth('booking_date', now()->month)
->whereYear('booking_date', now()->year)
->count(),
'free' => Consultation::query()
->where('consultation_type', ConsultationType::Free)
->count(),
'paid' => Consultation::query()
->where('consultation_type', ConsultationType::Paid)
->count(),
'no_show_rate' => $total > 0 ? round(($noShows / $total) * 100, 1) : 0,
];
});
}
private function getTimelineMetrics(): array
{
return Cache::remember('admin.metrics.timelines', 300, fn () => [
'active' => Timeline::query()
->where('status', TimelineStatus::Active)
->count(),
'archived' => Timeline::query()
->where('status', TimelineStatus::Archived)
->count(),
'updates_this_week' => TimelineUpdate::query()
->where('created_at', '>=', now()->subWeek())
->count(),
]);
}
private function getPostMetrics(): array
{
return Cache::remember('admin.metrics.posts', 300, fn () => [
'total_published' => Post::query()
->where('status', PostStatus::Published)
->count(),
'this_month' => Post::query()
->where('status', PostStatus::Published)
->whereMonth('published_at', now()->month)
->whereYear('published_at', now()->year)
->count(),
]);
}
}; ?>
<div>
<div class="mb-6">
<flux:heading size="xl">{{ __('admin_metrics.title') }}</flux:heading>
<flux:text class="mt-1 text-zinc-500 dark:text-zinc-400">{{ __('admin_metrics.subtitle') }}</flux:text>
</div>
<div class="grid grid-cols-1 gap-6 md:grid-cols-2 xl:grid-cols-4">
{{-- User Metrics Card --}}
<div class="rounded-lg border border-zinc-200 bg-white p-6 dark:border-zinc-700 dark:bg-zinc-800">
<div class="mb-4 flex items-center gap-3">
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-[#0A1F44] text-white dark:bg-[#D4AF37] dark:text-zinc-900">
<flux:icon name="users" class="h-5 w-5" />
</div>
<flux:heading size="lg">{{ __('admin_metrics.clients') }}</flux:heading>
</div>
<div class="space-y-3">
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.total_active') }}</flux:text>
<span class="text-xl font-semibold text-zinc-900 dark:text-zinc-100">{{ $userMetrics['total_active'] }}</span>
</div>
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.individual') }}</flux:text>
<span class="font-medium text-zinc-700 dark:text-zinc-300">{{ $userMetrics['individual'] }}</span>
</div>
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.company') }}</flux:text>
<span class="font-medium text-zinc-700 dark:text-zinc-300">{{ $userMetrics['company'] }}</span>
</div>
<div class="border-t border-zinc-200 pt-3 dark:border-zinc-700">
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.deactivated') }}</flux:text>
<span class="font-medium text-zinc-500 dark:text-zinc-400">{{ $userMetrics['deactivated'] }}</span>
</div>
</div>
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.new_this_month') }}</flux:text>
<flux:badge color="lime" size="sm">{{ $userMetrics['new_this_month'] }}</flux:badge>
</div>
</div>
</div>
{{-- Booking Metrics Card --}}
<div class="rounded-lg border border-zinc-200 bg-white p-6 dark:border-zinc-700 dark:bg-zinc-800">
<div class="mb-4 flex items-center gap-3">
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-[#0A1F44] text-white dark:bg-[#D4AF37] dark:text-zinc-900">
<flux:icon name="calendar" class="h-5 w-5" />
</div>
<flux:heading size="lg">{{ __('admin_metrics.consultations') }}</flux:heading>
</div>
<div class="space-y-3">
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.pending_requests') }}</flux:text>
<flux:badge color="amber" size="sm">{{ $bookingMetrics['pending'] }}</flux:badge>
</div>
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.today') }}</flux:text>
<span class="font-medium text-zinc-700 dark:text-zinc-300">{{ $bookingMetrics['today'] }}</span>
</div>
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.this_week') }}</flux:text>
<span class="font-medium text-zinc-700 dark:text-zinc-300">{{ $bookingMetrics['this_week'] }}</span>
</div>
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.this_month') }}</flux:text>
<span class="font-medium text-zinc-700 dark:text-zinc-300">{{ $bookingMetrics['this_month'] }}</span>
</div>
<div class="border-t border-zinc-200 pt-3 dark:border-zinc-700">
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.free') }}</flux:text>
<span class="font-medium text-zinc-700 dark:text-zinc-300">{{ $bookingMetrics['free'] }}</span>
</div>
<div class="mt-2 flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.paid') }}</flux:text>
<span class="font-medium text-zinc-700 dark:text-zinc-300">{{ $bookingMetrics['paid'] }}</span>
</div>
</div>
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.no_show_rate') }}</flux:text>
<span class="font-medium text-zinc-700 dark:text-zinc-300">{{ $bookingMetrics['no_show_rate'] }}%</span>
</div>
</div>
</div>
{{-- Timeline Metrics Card --}}
<div class="rounded-lg border border-zinc-200 bg-white p-6 dark:border-zinc-700 dark:bg-zinc-800">
<div class="mb-4 flex items-center gap-3">
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-[#0A1F44] text-white dark:bg-[#D4AF37] dark:text-zinc-900">
<flux:icon name="clipboard-document-list" class="h-5 w-5" />
</div>
<flux:heading size="lg">{{ __('admin_metrics.timelines') }}</flux:heading>
</div>
<div class="space-y-3">
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.active_cases') }}</flux:text>
<span class="text-xl font-semibold text-zinc-900 dark:text-zinc-100">{{ $timelineMetrics['active'] }}</span>
</div>
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.archived') }}</flux:text>
<span class="font-medium text-zinc-500 dark:text-zinc-400">{{ $timelineMetrics['archived'] }}</span>
</div>
<div class="border-t border-zinc-200 pt-3 dark:border-zinc-700">
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.updates_this_week') }}</flux:text>
<flux:badge color="lime" size="sm">{{ $timelineMetrics['updates_this_week'] }}</flux:badge>
</div>
</div>
</div>
</div>
{{-- Posts Metrics Card --}}
<div class="rounded-lg border border-zinc-200 bg-white p-6 dark:border-zinc-700 dark:bg-zinc-800">
<div class="mb-4 flex items-center gap-3">
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-[#0A1F44] text-white dark:bg-[#D4AF37] dark:text-zinc-900">
<flux:icon name="document-text" class="h-5 w-5" />
</div>
<flux:heading size="lg">{{ __('admin_metrics.posts') }}</flux:heading>
</div>
<div class="space-y-3">
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.total_published') }}</flux:text>
<span class="text-xl font-semibold text-zinc-900 dark:text-zinc-100">{{ $postMetrics['total_published'] }}</span>
</div>
<div class="border-t border-zinc-200 pt-3 dark:border-zinc-700">
<div class="flex items-center justify-between">
<flux:text class="text-zinc-600 dark:text-zinc-400">{{ __('admin_metrics.published_this_month') }}</flux:text>
<flux:badge color="lime" size="sm">{{ $postMetrics['this_month'] }}</flux:badge>
</div>
</div>
</div>
</div>
</div>
</div>