@extends('layouts.admin') @section('title', 'Report — ' . $campaign->name) @push('styles') @endpush @section('admin') @php $pct = fn($v) => number_format($v * 100, 2) . '%'; $pctShort = fn($v) => number_format($v * 100, 1) . '%'; // Industry benchmark hints $openBench = 0.25; $clickBench = 0.03; $openColor = $stats['open_rate'] >= $openBench ? '#4ade80' : ($stats['open_rate'] >= $openBench * 0.6 ? '#fcd34d' : '#f87171'); $clickColor = $stats['click_rate'] >= $clickBench ? '#4ade80' : ($stats['click_rate'] >= $clickBench * 0.6 ? '#fcd34d' : '#f87171'); $bounceOk = $stats['bounce_rate'] <= 0.02; $complaintOk = $stats['complaint_rate'] <= 0.003; // For SVG donut rings (circumference = 2πr at r=32 → ≈201) $circ = 201.06; $openDash = round(min($stats['open_rate'] / max(0.001, $openBench * 1.5), 1) * $circ, 2); $clickDash = round(min($stats['click_rate'] / max(0.001, $clickBench * 1.5), 1) * $circ, 2); @endphp
@include('admin._nav') {{-- Breadcrumb --}}

{{ $campaign->name }}

{{ $campaign->subject }}

@if($campaign->sent_at)

Sent {{ $campaign->sent_at->format('M j, Y') }}

@endif
Back
@if($campaign->auto_paused)

Auto-paused

Campaign exceeded the 0.3% complaint-rate threshold and was automatically paused.

@endif {{-- Primary KPIs with donut visuals --}}
{{-- Open rate (with donut) --}}
Open Rate
{{ $pctShort($stats['open_rate']) }}
{{ number_format($stats['unique_opens']) }} unique opens
{{-- Click rate (with donut) --}}
Click Rate
{{ $pctShort($stats['click_rate']) }}
{{ number_format($stats['unique_clicks']) }} unique clicks
{{-- Delivery --}}
Delivered
{{ number_format($stats['delivered']) }}
of {{ number_format($stats['sent']) }} sent
@php $deliveredPct = $stats['sent'] > 0 ? $stats['delivered'] / $stats['sent'] : 0; @endphp
{{-- CTOR --}}
CTOR
{{ $pctShort($stats['ctor']) }}
click-to-open rate
Clicks among openers
{{-- Health metrics row --}}
Bounce Rate
{{ $pct($stats['bounce_rate']) }}
{{ number_format($stats['bounced']) }} bounced · threshold 2%
{{ $bounceOk ? 'Healthy' : 'Above threshold' }}
Complaint Rate
{{ $pct($stats['complaint_rate']) }}
threshold 0.30%
{{ $complaintOk ? 'Within limit' : 'Exceeds limit' }}
Unsubscribes
{{ number_format($stats['unsubscribed']) }}
from this campaign
Total Opens
{{ number_format($stats['total_opens']) }}
incl. repeat opens
{{-- Hourly engagement chart --}}

Engagement by Hour

Opens and clicks in the first 48 h after sending.

@if(empty($hourly))

No engagement events recorded yet.

@else @php $maxHourly = max(1, ...array_map(fn($b) => max($b['opens'], $b['clicks']), $hourly)); @endphp
@foreach($hourly as $b) @php $openW = ($b['opens'] / $maxHourly) * 100; $clickW = ($b['clicks'] / $maxHourly) * 100; @endphp
{{ substr($b['bucket'], -5) }}
{{-- Opens --}}
@if($b['opens'] > 0) {{ $b['opens'] }} opens @endif
{{-- Clicks --}}
@if($b['clicks'] > 0) {{ $b['clicks'] }} clicks @endif
@endforeach
Opens Clicks
@endif
{{-- Top clicked links --}}

Top Clicked Links

Ranked by total clicks.

@if($topLinks->isEmpty())

No link clicks recorded yet.

@else @php $maxClicks = max(1, $topLinks->max('clicks')); @endphp
@foreach($topLinks as $link) @endforeach
@endif
@endsection