Files
ladill-qr-plus/resources/views/qr/analytics/index.blade.php
T
isaaccladandCursor 03fffa04be
Deploy Ladill QR Plus / deploy (push) Successful in 39s
Add account-level Analytics page to QR Plus.
Aggregates scan metrics across all codes with charts, breakdowns, and a sidebar nav item.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-19 00:57:08 +00:00

116 lines
6.1 KiB
PHP

<x-user-layout>
<x-slot name="title">Analytics</x-slot>
<div class="space-y-6">
<div>
<h1 class="text-xl font-semibold text-slate-900">Analytics</h1>
<p class="mt-1 text-sm text-slate-500">Scan activity across all your QR Plus codes.</p>
</div>
<div class="grid grid-cols-2 gap-4 sm:grid-cols-4">
<div class="rounded-2xl border border-slate-200/80 bg-white p-5 shadow-sm">
<p class="text-2xl font-bold text-slate-900">{{ number_format($summary['total_scans']) }}</p>
<p class="mt-0.5 text-xs text-slate-400">Total scans</p>
</div>
<div class="rounded-2xl border border-slate-200/80 bg-white p-5 shadow-sm">
<p class="text-2xl font-bold text-slate-900">{{ number_format($summary['unique_scans']) }}</p>
<p class="mt-0.5 text-xs text-slate-400">Unique scans</p>
</div>
<div class="rounded-2xl border border-slate-200/80 bg-white p-5 shadow-sm">
<p class="text-2xl font-bold text-slate-900">{{ number_format($summary['scans_7d']) }}</p>
<p class="mt-0.5 text-xs text-slate-400">Last 7 days</p>
</div>
<div class="rounded-2xl border border-slate-200/80 bg-white p-5 shadow-sm">
<p class="text-2xl font-bold text-slate-900">{{ number_format($summary['scans_30d']) }}</p>
<p class="mt-0.5 text-xs text-slate-400">Last 30 days</p>
</div>
</div>
<div class="rounded-2xl border border-slate-200/80 bg-white p-6 shadow-sm">
<h2 class="text-sm font-semibold text-slate-900">Scans last 30 days</h2>
@php $maxDaily = max(1, $dailyScans->max('total')); @endphp
<div class="mt-5 flex h-28 items-end gap-px">
@foreach($dailyScans as $day)
<div class="group relative flex flex-1 flex-col items-center justify-end"
title="{{ $day->date }}: {{ $day->total }}">
<div class="w-full rounded-t-sm bg-indigo-400/70 transition-colors group-hover:bg-indigo-600"
style="height: {{ max(2, ($day->total / $maxDaily) * 100) }}%"></div>
</div>
@endforeach
</div>
</div>
<div class="grid gap-4 sm:grid-cols-2">
<div class="rounded-2xl border border-slate-200/80 bg-white p-5 shadow-sm">
<h2 class="text-sm font-semibold text-slate-900">Devices</h2>
<ul class="mt-4 space-y-2.5">
@forelse($devices as $row)
<li class="flex items-center justify-between text-sm">
<span class="text-slate-600">{{ ucfirst($row['label']) }}</span>
<span class="font-semibold text-slate-900">{{ number_format($row['total']) }}</span>
</li>
@empty
<li class="text-sm text-slate-400">No scans yet</li>
@endforelse
</ul>
</div>
<div class="rounded-2xl border border-slate-200/80 bg-white p-5 shadow-sm">
<h2 class="text-sm font-semibold text-slate-900">Browsers</h2>
<ul class="mt-4 space-y-2.5">
@forelse($browsers as $row)
<li class="flex items-center justify-between text-sm">
<span class="text-slate-600">{{ $row['label'] }}</span>
<span class="font-semibold text-slate-900">{{ number_format($row['total']) }}</span>
</li>
@empty
<li class="text-sm text-slate-400">No scans yet</li>
@endforelse
</ul>
</div>
</div>
<div class="grid gap-6 lg:grid-cols-2">
<div class="rounded-2xl border border-slate-200 bg-white">
<div class="border-b border-slate-100 px-6 py-4">
<h2 class="font-semibold text-slate-900">Top codes</h2>
</div>
@if($topCodes->isEmpty())
<p class="px-6 py-8 text-sm text-slate-500">No scan data yet.</p>
@else
<div class="divide-y divide-slate-100">
@foreach($topCodes as $code)
<div class="flex items-center justify-between px-6 py-4">
<a href="{{ route('user.qr-codes.show', $code) }}" class="font-medium text-indigo-600 hover:text-indigo-800">{{ $code->label }}</a>
<span class="text-sm text-slate-600">{{ number_format($code->scans_total) }}</span>
</div>
@endforeach
</div>
@endif
</div>
<div class="rounded-2xl border border-slate-200 bg-white">
<div class="border-b border-slate-100 px-6 py-4">
<h2 class="font-semibold text-slate-900">Recent scans</h2>
</div>
@if($recentScans->isEmpty())
<p class="px-6 py-8 text-sm text-slate-500">No scans recorded yet.</p>
@else
<div class="divide-y divide-slate-100">
@foreach($recentScans as $event)
<div class="px-6 py-4">
<p class="text-sm font-medium text-slate-900">{{ $event->qrCode?->label ?? 'QR code' }}</p>
<p class="text-xs text-slate-500">
{{ ucfirst($event->device_type ?? 'unknown') }}
@if($event->browser)
· {{ $event->browser }}
@endif
· {{ $event->scanned_at->diffForHumans() }}
</p>
</div>
@endforeach
</div>
@endif
</div>
</div>
</div>
</x-user-layout>