feat(analytics): live dashboard with Reverb WebSocket, click event broadcasting

Overwrites the Analytics Index stub with a full Livewire component that
loads today's click count from the clicks table (workspace_id is a direct
column) and listens for live updates via Echo/Reverb using the
#[On('echo:workspace.{workspaceId}.analytics,click.recorded')] attribute.
Creates the corresponding blade view with a today-counter card and a
live recent-clicks feed (last 10 entries).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
main
boban 2026-05-16 08:04:08 +02:00
parent 61718fa867
commit 79da7502cd
2 changed files with 52 additions and 2 deletions

View File

@ -2,13 +2,38 @@
namespace App\Livewire\Pages\Analytics;
use App\Domains\Analytics\Models\Click;
use Livewire\Component;
use Livewire\Attributes\On;
class Index extends Component
{
public array $recentClicks = [];
public int $totalToday = 0;
public function mount(): void
{
$workspace = app('current_workspace');
$this->totalToday = Click::where('workspace_id', $workspace->id)
->whereDate('clicked_at', today())
->count();
}
#[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(): \Illuminate\View\View
{
return view('livewire.pages.coming-soon')
->layout('layouts.nimuli-app', ['title' => 'Analytics']);
$workspace = app('current_workspace');
return view('livewire.pages.analytics.index', [
'workspace' => $workspace,
])->layout('layouts.nimuli-app', ['title' => 'Analytics']);
}
}

View File

@ -0,0 +1,25 @@
<div>
<h1 class="text-2xl font-bold mb-6">Analytics</h1>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div class="bg-gray-900 rounded-xl border border-gray-800 p-4">
<div class="text-xs text-gray-500 uppercase tracking-wider mb-1">Today</div>
<div class="text-3xl font-bold font-mono">{{ $totalToday }}</div>
</div>
</div>
@if(count($recentClicks) > 0)
<div class="bg-gray-900 rounded-xl border border-gray-800 overflow-hidden">
<div class="px-4 py-3 border-b border-gray-800 text-sm font-medium">Recent clicks</div>
<div class="divide-y divide-gray-800">
@foreach($recentClicks as $click)
<div class="px-4 py-3 text-sm flex items-center gap-4">
<span class="text-gray-500 font-mono text-xs">{{ $click['clicked_at'] ?? '' }}</span>
<span class="text-gray-400">{{ $click['country'] ?? '—' }}</span>
<span class="text-gray-400">{{ $click['device'] ?? '—' }}</span>
</div>
@endforeach
</div>
</div>
@endif
</div>