142 lines
3.8 KiB
PHP
142 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Livewire\Pages\Analytics;
|
|
|
|
use App\Domains\Analytics\Models\Click;
|
|
use App\Domains\Link\Models\Link;
|
|
use Carbon\Carbon;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\View\View;
|
|
use Livewire\Attributes\On;
|
|
use Livewire\Attributes\Url;
|
|
use Livewire\Component;
|
|
|
|
class Index extends Component
|
|
{
|
|
#[Url(as: 'range')]
|
|
public string $range = '7d';
|
|
|
|
#[Url(as: 'country')]
|
|
public string $country = '';
|
|
|
|
#[Url(as: 'device')]
|
|
public string $device = '';
|
|
|
|
#[Url(as: 'link')]
|
|
public string $linkId = '';
|
|
|
|
public int $totalToday = 0;
|
|
|
|
public int $workspaceId = 0;
|
|
|
|
/** @var array<int, array<string, mixed>> */
|
|
public array $recentClicks = [];
|
|
|
|
public function mount(): void
|
|
{
|
|
$workspace = require_workspace();
|
|
$this->workspaceId = $workspace->id;
|
|
$this->totalToday = Click::where('workspace_id', $workspace->id)
|
|
->whereDate('clicked_at', today())
|
|
->count();
|
|
}
|
|
|
|
public function setRange(string $range): void
|
|
{
|
|
$this->range = in_array($range, ['24h', '7d', '30d', '90d']) ? $range : '7d';
|
|
}
|
|
|
|
private function rangeStart(): Carbon
|
|
{
|
|
return match ($this->range) {
|
|
'24h' => now()->subHours(24),
|
|
'30d' => now()->subDays(30),
|
|
'90d' => now()->subDays(90),
|
|
default => now()->subDays(7),
|
|
};
|
|
}
|
|
|
|
/** @return Builder<Click> */
|
|
private function baseQuery(): Builder
|
|
{
|
|
$wsId = $this->workspaceId;
|
|
|
|
$q = Click::where('workspace_id', $wsId)
|
|
->where('clicked_at', '>=', $this->rangeStart());
|
|
|
|
if ($this->country) {
|
|
$q->where('country', $this->country);
|
|
}
|
|
if ($this->device) {
|
|
$q->where('device', $this->device);
|
|
}
|
|
if ($this->linkId) {
|
|
$link = Link::where('workspace_id', $wsId)->where('ulid', $this->linkId)->first();
|
|
if ($link) {
|
|
$q->where('link_id', $link->id);
|
|
}
|
|
}
|
|
|
|
return $q;
|
|
}
|
|
|
|
/** @param array<string, mixed> $data */
|
|
#[On('echo:workspace.{workspaceId}.analytics,click.recorded')]
|
|
public function handleNewClick(array $data): void
|
|
{
|
|
array_unshift($this->recentClicks, $data);
|
|
$this->recentClicks = array_slice($this->recentClicks, 0, 10);
|
|
$this->totalToday++;
|
|
}
|
|
|
|
public function render(): View
|
|
{
|
|
$wsId = $this->workspaceId;
|
|
|
|
$totalFiltered = $this->baseQuery()->count();
|
|
|
|
$allTime = Click::where('workspace_id', $wsId)->count();
|
|
|
|
$byCountry = (clone $this->baseQuery())
|
|
->whereNotNull('country')
|
|
->selectRaw('country, COUNT(*) as total')
|
|
->groupBy('country')
|
|
->orderByDesc('total')
|
|
->limit(10)
|
|
->get();
|
|
|
|
$byDevice = (clone $this->baseQuery())
|
|
->selectRaw('device, COUNT(*) as total')
|
|
->groupBy('device')
|
|
->orderByDesc('total')
|
|
->get();
|
|
|
|
$countries = Click::where('workspace_id', $wsId)
|
|
->whereNotNull('country')
|
|
->distinct()
|
|
->pluck('country')
|
|
->sort()
|
|
->values();
|
|
|
|
$devices = Click::where('workspace_id', $wsId)
|
|
->whereNotNull('device')
|
|
->distinct()
|
|
->pluck('device')
|
|
->values();
|
|
|
|
$links = Link::where('workspace_id', $wsId)
|
|
->orderBy('slug')
|
|
->get(['ulid', 'slug', 'title']);
|
|
|
|
return view('livewire.pages.analytics.index', compact(
|
|
'totalFiltered',
|
|
'allTime',
|
|
'byCountry',
|
|
'byDevice',
|
|
'countries',
|
|
'devices',
|
|
'links',
|
|
))->layout('layouts.nimuli-app', ['title' => 'Analytics']);
|
|
}
|
|
}
|