@php use App\Enum\Dsar\DsarStatus; /** * Week-on-week delta badge. $lowerIsBetter inverts the colouring for metrics * like response time, where a fall is an improvement. */ $trend = function ($current, $previous, bool $lowerIsBetter = false) { if (!$previous) { return null; // no baseline — nothing meaningful to show } $change = round((($current - $previous) / $previous) * 100, 1); $good = $lowerIsBetter ? $change <= 0 : $change >= 0; return [ 'change' => $change, 'class' => $good ? 'text-success' : 'text-danger', 'icon' => $change >= 0 ? 'bi-arrow-up-right' : 'bi-arrow-down-right', ]; }; @endphp

DSAR Report

Overview of all Data Subject Access Requests

{{-- Headline cards --}}
@php $sentTrend = $trend($sentThisWeek, $sentLastWeek); @endphp

Total Sent (All Time)

{{ number_format($totalAll) }}

{{ $totalMonth }} this month
@if($sentTrend) {{ abs($sentTrend['change']) }}% @endif {{ $sentThisWeek }} this week vs {{ $sentLastWeek }} last week
@php $completedTrend = $trend($completedThisWeek, $completedLastWeek); @endphp

Completed

{{ number_format($completedCount) }}

@if($totalAll > 0) {{ round(($completedCount / $totalAll) * 100, 1) }}% completion rate @else — @endif
@if($completedTrend) {{ abs($completedTrend['change']) }}% @endif {{ $completedThisWeek }} this week vs {{ $completedLastWeek }} last week
@php $avgTrend = $trend($avgThisWeek, $avgLastWeek, lowerIsBetter: true); @endphp

Avg Response Time

{{ $avgResponseDays ? round($avgResponseDays, 1) . ' days' : '—' }}

From send to response
@if($avgTrend) {{ abs($avgTrend['change']) }}% @endif {{ $avgThisWeek ? round($avgThisWeek, 1) . 'd' : '—' }} this week vs {{ $avgLastWeek ? round($avgLastWeek, 1) . 'd' : '—' }} last week
{{-- Status Breakdown — every status in the enum --}}
Status Breakdown
@foreach(DsarStatus::cases() as $case) @php $count = $byStatus->get($case->value, 0); @endphp @endforeach
Status Count %
{{ DsarStatus::label($case->value) }} {{ $count }} {{ $grandTotal > 0 ? round(($count / $grandTotal) * 100, 1) : 0 }}%
{{-- Response Types — outcome statuses as a share of DSARs responded to --}}
Response Types
@if($totalResponded > 0) @foreach($responded as $status) @php $count = $byStatus->get($status, 0); $pct = round(($count / $totalResponded) * 100); @endphp
{{ DsarStatus::label($status) }} {{ $count }} ({{ $pct }}%)
@endforeach @else

No responses received yet.

@endif
{{-- Sent per month, rolling 6 months --}}
DSARs Sent per Month
{{-- wire:ignore — the sort/search filters below are wire:model.live, so Livewire re-renders this component and would otherwise morph the canvas out from under Chart.js. @script only runs once. maintainAspectRatio:false, so the chart sizes to this box. --}}
{{-- DSARs by Target --}}
DSARs by Target
@forelse($byTarget as $row) @php $highBacklog = $row->stated_backlog !== null && $row->stated_backlog >= 100; $agedOutstand = $row->oldest_age_days !== null && $row->oldest_age_days >= 60; @endphp @empty @endforelse
Institution Outstanding Oldest (days) Avg Response Stated Backlog Sent Completed Completion %
@if($row->institution) {{ $row->display_name }} @else {{ $row->display_name }} @endif @if($row->outstanding > 0) {{ $row->outstanding }} @if($row->institution) @endif @else 0 @endif {{ $row->oldest_age_days !== null ? $row->oldest_age_days : '—' }} {{ $row->avg_response_days !== null ? $row->avg_response_days . ' d' : '—' }} @if($row->stated_backlog !== null) {{ number_format($row->stated_backlog) }} @if($row->backlog_updated_at)
as of {{ $row->backlog_updated_at->format('d M Y') }}
@endif @else @endif
{{ $row->total_sent }} {{ $row->total_completed }}
{{ $row->completion_rate }}%
No DSARs found.
@script @endscript