Files
calvana/temp_files/sg/scheduled-giving-dashboard.blade.php
Omair Saleh e852250ce0 Landing page philosophy across ALL dashboard pages
Home:
- Empty state: 2-column with 'How it works' 5-step guide
- Has data: 7/5 grid — pledges left, education right
- Right column: status breakdown, sources, 'What to do next' contextual links, 'What the statuses mean' guide

Money:
- 8/4 two-column layout: table left, education right
- Right column: 'How matching works' 4-step guide, status explainer, collection tips, quick action buttons
- No more wasted right margin

Reports:
- 7/5 two-column layout: downloads left, education right
- Right column: 'For your treasurer' 3-step guide, Gift Aid FAQ, 'Understanding your numbers' explainer
- Activity log moved to right column

Settings:
- Removed max-w-2xl constraint, now uses full width
- 7/5 two-column: checklist left, education right
- Right column: 'What you're setting up' (5 items with Required badges), Privacy & data assurance, Common questions FAQ, 'Need help?' CTA
- Every setting explained in human language
2026-03-05 03:35:08 +08:00

200 lines
10 KiB
PHP

<x-filament-panels::page>
@php
$global = $this->getGlobalStats();
$campaigns = $this->getCampaignData();
$failed = $this->getFailedPayments();
$upcoming = $this->getUpcomingPayments();
@endphp
{{-- ── Global Overview ──────────────────────────────────────── --}}
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
<x-filament::section>
<div class="text-center">
<div class="text-3xl font-bold text-primary-600">{{ number_format($global['active_subscribers']) }}</div>
<div class="text-sm text-gray-500 mt-1">Active Subscribers</div>
</div>
</x-filament::section>
<x-filament::section>
<div class="text-center">
<div class="text-3xl font-bold text-success-600">£{{ number_format($global['collected'], 2) }}</div>
<div class="text-sm text-gray-500 mt-1">Total Collected</div>
</div>
</x-filament::section>
<x-filament::section>
<div class="text-center">
<div class="text-3xl font-bold text-warning-600">£{{ number_format($global['pending'], 2) }}</div>
<div class="text-sm text-gray-500 mt-1">Pending Collection</div>
</div>
</x-filament::section>
<x-filament::section>
<div class="text-center">
<div class="text-3xl font-bold {{ $global['collection_rate'] >= 80 ? 'text-success-600' : ($global['collection_rate'] >= 60 ? 'text-warning-600' : 'text-danger-600') }}">
{{ $global['collection_rate'] }}%
</div>
<div class="text-sm text-gray-500 mt-1">Collection Rate</div>
</div>
</x-filament::section>
</div>
{{-- ── Campaign Cards ──────────────────────────────────────── --}}
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
@foreach ($campaigns as $data)
@php
$c = $data['campaign'];
$isActive = $c->active;
$progressPct = $data['total_payments'] > 0
? round($data['paid_payments'] / $data['total_payments'] * 100)
: 0;
@endphp
<x-filament::section>
<x-slot name="heading">
<div class="flex items-center justify-between">
<span>{{ $c->title }}</span>
@if ($isActive)
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800"> Live</span>
@else
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-gray-100 text-gray-600"> Ended</span>
@endif
</div>
</x-slot>
{{-- Stats grid --}}
<div class="grid grid-cols-2 gap-3 mb-4">
<div>
<div class="text-xs text-gray-500 uppercase tracking-wide">Subscribers</div>
<div class="text-lg font-semibold">{{ number_format($data['active']) }} <span class="text-xs text-gray-400 font-normal">/ {{ number_format($data['subscribers']) }}</span></div>
</div>
<div>
<div class="text-xs text-gray-500 uppercase tracking-wide">Avg / Night</div>
<div class="text-lg font-semibold">£{{ number_format($data['avg_per_night'], 2) }}</div>
</div>
<div>
<div class="text-xs text-gray-500 uppercase tracking-wide">Collected</div>
<div class="text-lg font-semibold text-success-600">£{{ number_format($data['collected'], 2) }}</div>
</div>
<div>
<div class="text-xs text-gray-500 uppercase tracking-wide">Pending</div>
<div class="text-lg font-semibold text-warning-600">£{{ number_format($data['pending_amount'], 2) }}</div>
</div>
</div>
{{-- Payment progress bar --}}
<div class="mb-3">
<div class="flex justify-between text-xs text-gray-500 mb-1">
<span>{{ number_format($data['paid_payments']) }} / {{ number_format($data['total_payments']) }} payments</span>
<span>{{ $progressPct }}%</span>
</div>
<div class="w-full bg-gray-200 rounded-full h-2.5">
<div class="h-2.5 rounded-full {{ $progressPct >= 80 ? 'bg-success-500' : ($progressPct >= 50 ? 'bg-warning-500' : 'bg-primary-500') }}"
style="width: {{ $progressPct }}%"></div>
</div>
</div>
{{-- Key metrics --}}
<div class="grid grid-cols-3 gap-2 text-center border-t pt-3">
<div>
<div class="text-xs text-gray-500">Nights</div>
<div class="font-semibold">{{ $data['total_nights'] }}</div>
</div>
<div>
<div class="text-xs text-gray-500">Completed</div>
<div class="font-semibold text-success-600">{{ $data['fully_completed'] ?? 0 }}</div>
</div>
<div>
<div class="text-xs text-gray-500">Failed</div>
<div class="font-semibold {{ $data['failed_payments'] > 0 ? 'text-danger-600' : 'text-gray-400' }}">{{ $data['failed_payments'] }}</div>
</div>
</div>
{{-- Quick links --}}
<div class="flex gap-2 mt-3 pt-3 border-t">
<a href="{{ url('/admin/scheduled-giving-donations?tableFilters[scheduled_giving_campaign_id][value]=' . $c->id) }}"
class="text-xs text-primary-600 hover:underline">View Subscribers </a>
<a href="{{ url('/admin/scheduled-giving-campaigns/' . $c->id . '/edit') }}"
class="text-xs text-gray-500 hover:underline ml-auto">Edit Campaign</a>
</div>
</x-filament::section>
@endforeach
</div>
{{-- ── Upcoming Payments ───────────────────────────────────── --}}
@if (count($upcoming) > 0)
<x-filament::section>
<x-slot name="heading">
<div class="flex items-center gap-2">
<x-heroicon-o-clock class="w-5 h-5 text-primary-500" />
Upcoming Payments (Next 48 Hours)
</div>
</x-slot>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
@foreach ($upcoming as $u)
<div class="flex items-center justify-between p-3 bg-primary-50 rounded-lg">
<div>
<div class="font-semibold">{{ $u->campaign }}</div>
<div class="text-sm text-gray-500">{{ $u->payment_count }} payments</div>
</div>
<div class="text-right">
<div class="font-bold text-primary-600">£{{ number_format($u->total_amount, 2) }}</div>
<div class="text-xs text-gray-500">{{ \Carbon\Carbon::parse($u->earliest)->diffForHumans() }}</div>
</div>
</div>
@endforeach
</div>
</x-filament::section>
@endif
{{-- ── Failed Payments (Needs Attention) ───────────────────── --}}
@if (count($failed) > 0)
<x-filament::section class="mt-6">
<x-slot name="heading">
<div class="flex items-center gap-2">
<x-heroicon-o-exclamation-triangle class="w-5 h-5 text-danger-500" />
Failed Payments Needs Attention ({{ count($failed) }})
</div>
</x-slot>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="text-left text-xs text-gray-500 uppercase border-b">
<th class="pb-2">Donor</th>
<th class="pb-2">Campaign</th>
<th class="pb-2">Amount</th>
<th class="pb-2">Expected</th>
<th class="pb-2">Attempts</th>
<th class="pb-2"></th>
</tr>
</thead>
<tbody>
@foreach ($failed as $f)
<tr class="border-b border-gray-100 hover:bg-gray-50">
<td class="py-2">
<div class="font-medium">{{ $f->donor_name }}</div>
<div class="text-xs text-gray-400">{{ $f->donor_email }}</div>
</td>
<td class="py-2">{{ $f->campaign }}</td>
<td class="py-2 font-semibold">£{{ number_format($f->amount / 100, 2) }}</td>
<td class="py-2 text-gray-500">{{ \Carbon\Carbon::parse($f->expected_at)->format('d M Y') }}</td>
<td class="py-2">
<span class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-danger-100 text-danger-800">
{{ $f->attempts }}x failed
</span>
</td>
<td class="py-2">
<a href="{{ url('/admin/scheduled-giving-donations/' . $f->donation_id . '/edit') }}"
class="text-xs text-primary-600 hover:underline">View </a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</x-filament::section>
@endif
</x-filament-panels::page>