nimuli/resources/views/livewire/pages/analytics/index.blade.php

139 lines
7.4 KiB
PHP

<div>
{{-- Header --}}
<div class="flex flex-wrap items-center justify-between gap-3 mb-6 nim-reveal nim-reveal-1">
<div>
<h1 class="text-t1">Analytics</h1>
<p class="text-xs text-t3 mt-0.5">Click-through data for your workspace</p>
</div>
{{-- Range buttons --}}
<div class="flex gap-1 bg-s2 border border-white/[.06] rounded-lg p-0.5">
@foreach(['24h' => '24h', '7d' => '7d', '30d' => '30d', '90d' => '90d'] as $key => $label)
<button wire:click="setRange('{{ $key }}')"
class="px-3 py-1.5 text-xs rounded-md font-semibold transition-all
{{ $range === $key
? 'bg-accent-gradient text-white shadow-sm'
: 'text-t2 hover:text-t1' }}">
{{ $label }}
</button>
@endforeach
</div>
</div>
{{-- Filter bar --}}
<div class="flex flex-wrap gap-2 mb-6">
<select wire:model.live="country"
class="px-3 py-2 bg-s1 border border-white/[.06] rounded-lg text-xs text-t1 focus:outline-none focus:ring-1 focus:ring-blue/50 min-w-[130px]">
<option value="">All Countries</option>
@foreach($countries as $c)
<option value="{{ $c }}" @selected($country === $c)>{{ $c }}</option>
@endforeach
</select>
<select wire:model.live="device"
class="px-3 py-2 bg-s1 border border-white/[.06] rounded-lg text-xs text-t1 focus:outline-none focus:ring-1 focus:ring-blue/50 min-w-[130px]">
<option value="">All Devices</option>
@foreach($devices as $d)
<option value="{{ $d }}" @selected($device === $d)>{{ ucfirst($d) }}</option>
@endforeach
</select>
<select wire:model.live="linkId"
class="px-3 py-2 bg-s1 border border-white/[.06] rounded-lg text-xs text-t1 focus:outline-none focus:ring-1 focus:ring-blue/50 min-w-[150px]">
<option value="">All Links</option>
@foreach($links as $l)
<option value="{{ $l->ulid }}" @selected($linkId === $l->ulid)>{{ $l->slug }}{{ $l->title ? ' — ' . $l->title : '' }}</option>
@endforeach
</select>
@if($country || $device || $linkId)
<button wire:click="$set('country', ''); $set('device', ''); $set('linkId', '')"
class="px-3 py-2 text-xs text-red hover:opacity-80 transition-opacity flex items-center gap-1">
<x-heroicon-o-x-mark class="w-3 h-3" />
Clear filters
</button>
@endif
</div>
{{-- Summary metrics --}}
<div class="grid grid-cols-2 md:grid-cols-3 gap-3 mb-6">
<div class="bg-s1 border border-white/[.06] rounded-xl p-4 card-shadow card-accent-top nim-reveal nim-reveal-1">
<div class="text-xs font-semibold text-t3 uppercase tracking-widest mb-3">{{ strtoupper($range) }}</div>
<div class="metric-num text-3xl text-t1">{{ number_format($totalFiltered) }}</div>
<div class="text-xs text-t3 mt-1.5">filtered clicks</div>
</div>
<div class="bg-s1 border border-white/[.06] rounded-xl p-4 card-shadow nim-reveal nim-reveal-2">
<div class="text-xs font-semibold text-t3 uppercase tracking-widest mb-3">All-time</div>
<div class="metric-num text-3xl text-t1">{{ number_format($allTime) }}</div>
<div class="text-xs text-t3 mt-1.5">total clicks</div>
</div>
<div class="bg-s1 border border-white/[.06] rounded-xl p-4 card-shadow nim-reveal nim-reveal-3">
<div class="text-xs font-semibold text-t3 uppercase tracking-widest mb-3">Today</div>
<div class="metric-num text-3xl text-t1">{{ number_format($totalToday) }}</div>
<div class="text-xs text-t3 mt-1.5">since midnight</div>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
{{-- Top Countries --}}
<div class="bg-s1 border border-white/[.06] rounded-xl overflow-hidden card-shadow nim-reveal nim-reveal-4">
<div class="px-5 py-3.5 border-b border-white/[.06] flex items-center justify-between">
<div class="text-xs font-semibold text-t1 uppercase tracking-wide">Top Countries</div>
@if($country)
<button wire:click="$set('country', '')" class="text-xs text-t3 hover:text-red transition-colors flex items-center gap-1">
<x-heroicon-o-x-mark class="w-3 h-3" />
Clear
</button>
@endif
</div>
@forelse($byCountry as $row)
@php $pct = $totalFiltered > 0 ? round(($row->total / $totalFiltered) * 100) : 0; @endphp
<div class="px-5 py-2.5 border-b border-white/[.03] last:border-0 group">
<div class="flex items-center justify-between mb-1">
<button wire:click="$set('country', '{{ $row->country }}')"
class="text-sm text-t1 hover:text-blue transition-colors {{ $country === $row->country ? 'text-blue font-semibold' : '' }}">
{{ $row->country }}
</button>
<span class="font-mono text-xs text-t2 tabular-nums">{{ number_format($row->total) }}</span>
</div>
<div class="h-0.5 bg-s3 rounded-full overflow-hidden">
<div class="h-full bg-accent-gradient rounded-full transition-all" style="width: {{ $pct }}%"></div>
</div>
</div>
@empty
<div class="px-5 py-8 text-center text-xs text-t3">No data for this period</div>
@endforelse
</div>
{{-- By Device --}}
<div class="bg-s1 border border-white/[.06] rounded-xl overflow-hidden card-shadow nim-reveal nim-reveal-5">
<div class="px-5 py-3.5 border-b border-white/[.06] flex items-center justify-between">
<div class="text-xs font-semibold text-t1 uppercase tracking-wide">By Device</div>
@if($device)
<button wire:click="$set('device', '')" class="text-xs text-t3 hover:text-red transition-colors flex items-center gap-1">
<x-heroicon-o-x-mark class="w-3 h-3" />
Clear
</button>
@endif
</div>
@forelse($byDevice as $row)
@php $pct = $totalFiltered > 0 ? round(($row->total / $totalFiltered) * 100) : 0; @endphp
<div class="px-5 py-2.5 border-b border-white/[.03] last:border-0">
<div class="flex items-center justify-between mb-1">
<button wire:click="$set('device', '{{ $row->device }}')"
class="text-sm text-t1 capitalize hover:text-blue transition-colors {{ $device === $row->device ? 'text-blue font-semibold' : '' }}">
{{ $row->device ?? 'Unknown' }}
</button>
<span class="font-mono text-xs text-t2 tabular-nums">{{ number_format($row->total) }}</span>
</div>
<div class="h-0.5 bg-s3 rounded-full overflow-hidden">
<div class="h-full bg-green/60 rounded-full transition-all" style="width: {{ $pct }}%"></div>
</div>
</div>
@empty
<div class="px-5 py-8 text-center text-xs text-t3">No data for this period</div>
@endforelse
</div>
</div>
</div>