198 lines
5.1 KiB
PHP
198 lines
5.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Livewire\Admin;
|
|
|
|
use App\Models\Player;
|
|
use App\Models\GameMetric;
|
|
use App\Models\ModerationAlert;
|
|
use App\Services\AnalyticsService;
|
|
use App\Services\EconomyMonitorService;
|
|
use Livewire\Component;
|
|
use Livewire\Attributes\Layout;
|
|
use Livewire\Attributes\Rule;
|
|
|
|
/**
|
|
* Admin Dashboard Livewire Component
|
|
*
|
|
* Laravel 11 Livewire dashboard for game administration
|
|
*
|
|
* Features:
|
|
* - Real-time player analytics via polling
|
|
* - Moderation alerts display
|
|
* - Economy health monitoring
|
|
* - Ethical engagement tracking
|
|
*
|
|
* @see https://laravel livewire.com
|
|
* @security PHP 8.3+ type safety, readonly properties
|
|
* @accessibility ARIA labels, semantic HTML, keyboard navigation
|
|
*/
|
|
#[Layout('layouts.admin')]
|
|
final class Dashboard extends Component
|
|
{
|
|
/**
|
|
* Current authenticated admin user
|
|
*/
|
|
public readonly ?\App\Models\AdminUser $admin;
|
|
|
|
/**
|
|
* Dashboard metrics (cached via Redis)
|
|
*/
|
|
private AnalyticsService $analyticsService;
|
|
|
|
/**
|
|
* Economy monitoring service
|
|
*/
|
|
private EconomyMonitorService $economyService;
|
|
|
|
/**
|
|
* Filter parameters
|
|
*/
|
|
#[Rule('nullable|string|in:24h,7d,30d')]
|
|
public string $timeframe = '24h';
|
|
|
|
#[Rule('nullable|string|in:na,eu,apac')]
|
|
public string $region = '';
|
|
|
|
#[Rule('nullable|string')]
|
|
public string $playerSegment = '';
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct(
|
|
AnalyticsService $analyticsService,
|
|
EconomyMonitorService $economyService
|
|
) {
|
|
this.analyticsService = $analyticsService;
|
|
this.economyService = $economyService;
|
|
this.admin = auth()->user();
|
|
}
|
|
|
|
/**
|
|
* Mount the dashboard component
|
|
*
|
|
* @param string|null $timeframe Filter timeframe
|
|
* @param string|null $region Filter region
|
|
*/
|
|
public function mount(?string $timeframe = null, ?string $region = null): void
|
|
{
|
|
this.timeframe = $timeframe ?? '24h';
|
|
this.region = $region ?? '';
|
|
}
|
|
|
|
/**
|
|
* Render the dashboard view
|
|
*
|
|
* @return \Illuminate\View\View
|
|
*/
|
|
public function render(): \Illuminate\View\View
|
|
{
|
|
return view('livewire.admin.dashboard', [
|
|
'metrics' => this.getMetrics(),
|
|
'alerts' => this.getAlerts(),
|
|
'players' => this.getPlayers(),
|
|
'economyHealth' => this.economyService->getHealthIndex(),
|
|
'ethicalStatus' => this.getEthicalEngagementStatus(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Get dashboard metrics from analytics service
|
|
*
|
|
* @return array{active_players: int, retention_d1: float, economy_index: float}
|
|
*/
|
|
private function getMetrics(): array
|
|
{
|
|
return this.analyticsService->getDashboardMetrics(
|
|
timeframe: this.timeframe,
|
|
region: this.region
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get active moderation alerts
|
|
*
|
|
* @return \Illuminate\Database\Eloquent\Collection<ModerationAlert>
|
|
*/
|
|
private function getAlerts(): \Illuminate\Database\Eloquent\Collection
|
|
{
|
|
return ModerationAlert::active()
|
|
->limit(10)
|
|
->ordered()
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* Get filtered player list
|
|
*
|
|
* @return \Illuminate\Database\Eloquent\Collection<Player>
|
|
*/
|
|
private function getPlayers(): \Illuminate\Database\Eloquent\Collection
|
|
{
|
|
return Player::scopeFilters([
|
|
'timeframe' => this.timeframe,
|
|
'region' => this.region,
|
|
'segment' => this.playerSegment,
|
|
])
|
|
->limit(50)
|
|
->ordered()
|
|
->get();
|
|
}
|
|
|
|
/**
|
|
* Get ethical engagement status
|
|
*
|
|
* @return array{loot_tables_compliant: int, spending_warnings: int}
|
|
*/
|
|
private function getEthicalEngagementStatus(): array
|
|
{
|
|
return [
|
|
'loot_tables_compliant' => \App\Models\LootTable::compliant()->count(),
|
|
'spending_warnings' => \App\Models\PlayerSpending::warningCount(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Update filters (called by Alpine.js)
|
|
*
|
|
* @param string $timeframe New timeframe
|
|
* @param string $region New region
|
|
*/
|
|
public function updateFilters(string $timeframe, string $region): void
|
|
{
|
|
this.timeframe = $timeframe;
|
|
this.region = $region;
|
|
|
|
this.dispatch('filtersUpdated');
|
|
}
|
|
|
|
/**
|
|
* Refresh metrics via polling
|
|
*
|
|
* @return array{metrics: array}
|
|
*/
|
|
public function refreshMetrics(): array
|
|
{
|
|
return ['metrics' => this.getMetrics()];
|
|
}
|
|
|
|
/**
|
|
* Export dashboard data
|
|
*
|
|
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
|
|
*/
|
|
public function export(): \Symfony\Component\HttpFoundation\BinaryFileResponse
|
|
{
|
|
$data = [
|
|
'metrics' => this.getMetrics(),
|
|
'alerts' => this.getAlerts()->toArray(),
|
|
'economy' => this.economyService->exportData(),
|
|
];
|
|
|
|
$filename = 'dashboard-export-' . date('Y-m-d') . '.json';
|
|
|
|
return response()->json($data, 200, ['Content-Disposition' => 'attachment; filename=' . $filename]);
|
|
}
|
|
} |