Files
Mark Gregory 76e29fab03 Analytics administration dashboard
* Page-view tracking
* Unique visitor and session metrics
* Content-view events
* Search analytics
* Conversion tracking
* Form-submission events
* Commerce events
* Site-aware analytics
* Privacy-conscious visitor hashing
* Optional IP anonymisation
* Do Not Track support
* Configurable excluded paths
* Daily metric aggregation
* Top-page reporting
* Recent-event activity
* Report definitions
* Scheduled report foundation
* CSV and JSON report formats
* Report execution history schema
* Analytics retention and pruning
* Administration navigation
* Analytics permissions
* Module registration
* Feature test
2026-07-24 13:06:48 +01:00

15 lines
3.8 KiB
PHP

<x-layouts.app :title="__('Analytics')">
<div class="flex h-full w-full flex-1 flex-col gap-6 rounded-xl">
<div class="flex flex-wrap items-center justify-between gap-3"><div><flux:heading size="xl">Analytics</flux:heading><flux:subheading>Visitor, content, search and conversion performance.</flux:subheading></div><form method="GET"><flux:select name="days" onchange="this.form.submit()"><option value="7" @selected($days===7)>7 days</option><option value="30" @selected($days===30)>30 days</option><option value="90" @selected($days===90)>90 days</option></flux:select></form></div>
@if(session('status'))<flux:callout variant="success">{{ session('status') }}</flux:callout>@endif
<div class="grid gap-4 md:grid-cols-4">
@foreach([['Page views',$pageViews],['Visitors',$visitors],['Conversions',$conversions],['Searches',$searches]] as [$label,$value])<div class="rounded-xl border border-neutral-200 p-5 dark:border-neutral-700"><div class="text-sm text-neutral-500">{{ $label }}</div><div class="mt-2 text-3xl font-semibold">{{ number_format($value) }}</div></div>@endforeach
</div>
<div class="grid gap-6 lg:grid-cols-2">
<div class="rounded-xl border border-neutral-200 p-5 dark:border-neutral-700"><flux:heading>Top pages</flux:heading><div class="mt-4 divide-y divide-neutral-200 dark:divide-neutral-700">@forelse($topPages as $page)<div class="flex justify-between gap-4 py-3"><span class="truncate">{{ $page->path ?: '/' }}</span><strong>{{ number_format($page->total) }}</strong></div>@empty<p class="py-4 text-sm text-neutral-500">No page views recorded.</p>@endforelse</div></div>
<div class="rounded-xl border border-neutral-200 p-5 dark:border-neutral-700"><flux:heading>Recent events</flux:heading><div class="mt-4 divide-y divide-neutral-200 dark:divide-neutral-700">@forelse($recentEvents as $event)<div class="py-3"><div class="flex justify-between gap-4"><strong>{{ str($event->event_type)->replace('_',' ')->title() }}</strong><span class="text-xs text-neutral-500">{{ $event->occurred_at?->diffForHumans() }}</span></div><p class="truncate text-sm text-neutral-500">{{ $event->path ?: data_get($event->properties,'query','—') }}</p></div>@empty<p class="py-4 text-sm text-neutral-500">No events recorded.</p>@endforelse</div></div>
</div>
@can('analytics.manage')<div class="rounded-xl border border-neutral-200 p-5 dark:border-neutral-700"><flux:heading>Scheduled reports</flux:heading><form method="POST" action="{{ route('administration.analytics.reports.store') }}" class="mt-4 grid gap-4 md:grid-cols-5">@csrf<flux:input name="name" label="Name" required/><flux:select name="report_type" label="Type"><option value="overview">Overview</option><option value="content">Content</option><option value="search">Search</option><option value="conversion">Conversion</option><option value="commerce">Commerce</option></flux:select><flux:input name="schedule" label="Schedule" placeholder="daily"/><flux:select name="format" label="Format"><option value="csv">CSV</option><option value="json">JSON</option></flux:select><div class="flex items-end"><flux:button type="submit" variant="primary">Create report</flux:button></div></form><div class="mt-4 divide-y divide-neutral-200 dark:divide-neutral-700">@forelse($reports as $report)<div class="flex items-center justify-between py-3"><div><strong>{{ $report->name }}</strong><p class="text-sm text-neutral-500">{{ ucfirst($report->report_type) }} · {{ strtoupper($report->format) }}</p></div><form method="POST" action="{{ route('administration.analytics.reports.destroy',$report) }}">@csrf @method('DELETE')<flux:button type="submit" variant="danger" size="sm">Delete</flux:button></form></div>@empty<p class="py-4 text-sm text-neutral-500">No reports configured.</p>@endforelse</div></div>@endcan
</div>
</x-layouts.app>