Files

59 lines
6.2 KiB
PHP
Executable File

@php
$trendMax = max(1, (int) $trend->max(fn($row) => max($row['created'], $row['resolved'])));
$pointCount = max(1, $trend->count() - 1);
$createdPoints = $trend->map(fn($row, $i) => ($i * (100 / $pointCount)).','. (88 - (($row['created'] / $trendMax) * 68)))->implode(' ');
$resolvedPoints = $trend->map(fn($row, $i) => ($i * (100 / $pointCount)).','. (88 - (($row['resolved'] / $trendMax) * 68)))->implode(' ');
$palette = ['#ef4444', '#f59e0b', '#3b82f6', '#8b5cf6'];
$priorityTotal = max(1, $priorityBreakdown->sum('count'));
$offset = 0;
$segments = [];
$donutSegments = [];
foreach($priorityBreakdown as $index => $priority) {
$percent = ($priority['count'] / $priorityTotal) * 100;
$segments[] = $palette[$index % count($palette)].' '.$offset.'% '.($offset + $percent).'%';
$donutSegments[] = [
'colour' => $palette[$index % count($palette)],
'length' => $percent,
'offset' => -$offset,
];
$offset += $percent;
}
@endphp
<div class="hd-dashboard space-y-5" dusk="helpdesk-dashboard-widget">
<section class="hd-dashboard-heading">
<div><h1>Dashboard</h1><p>Overview of your helpdesk system</p></div>
<label class="hd-range-select"><svg class="hd-svg-icon hd-icon-outline" viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="5" width="18" height="16" rx="2"/><path d="M16 3v4M8 3v4M3 10h18"/></svg><select wire:model.live="days"><option value="7">Last 7 days</option><option value="14">Last 14 days</option><option value="30">Last 30 days</option></select></label>
</section>
<div class="hd-metric-grid">
<article class="hd-metric-card hd-metric-blue"><span class="hd-metric-icon"><svg class="hd-svg-icon hd-icon-outline" viewBox="0 0 24 24" aria-hidden="true"><path d="M9 5h6M9 3h6v4H9z"/><rect x="5" y="5" width="14" height="16" rx="2"/><path d="M9 11h6M9 15h6"/></svg></span><div><small>Total Tickets</small><strong>{{ $totalCount }}</strong><em>All visible tickets</em></div></article>
<article class="hd-metric-card hd-metric-green"><span class="hd-metric-icon"><svg class="hd-svg-icon hd-icon-outline" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="m8 12 2.6 2.6L16.5 9"/></svg></span><div><small>Resolved</small><strong>{{ $closedCount }}</strong><em>Completed workload</em></div></article>
<article class="hd-metric-card hd-metric-amber"><span class="hd-metric-icon"><svg class="hd-svg-icon hd-icon-outline" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></svg></span><div><small>In Progress</small><strong>{{ $inProgressCount }}</strong><em>Actively being worked</em></div></article>
<article class="hd-metric-card hd-metric-red"><span class="hd-metric-icon"><svg class="hd-svg-icon hd-icon-outline" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v6M12 17h.01"/></svg></span><div><small>Open</small><strong>{{ $openCount }}</strong><em>Awaiting resolution</em></div></article>
</div>
<div class="hd-dashboard-grid">
<section class="hd-dashboard-card hd-chart-card">
<header><h2>Tickets Over Time</h2><span>{{ $days }} days</span></header>
<div class="hd-chart-legend"><span><b class="bg-blue-500"></b>Created</span><span><b class="bg-emerald-500"></b>Resolved</span></div>
<div class="hd-line-chart"><svg viewBox="0 0 100 100" preserveAspectRatio="none" aria-label="Ticket trend chart"><g class="hd-chart-grid-lines"><line x1="0" y1="20" x2="100" y2="20"/><line x1="0" y1="42" x2="100" y2="42"/><line x1="0" y1="64" x2="100" y2="64"/><line x1="0" y1="88" x2="100" y2="88"/></g><polyline class="hd-chart-line hd-chart-line-blue" points="{{ $createdPoints }}"/><polyline class="hd-chart-line hd-chart-line-green" points="{{ $resolvedPoints }}"/></svg></div>
<div class="hd-chart-labels">@foreach($trend as $row)<span>{{ $row['label'] }}</span>@endforeach</div>
</section>
<section class="hd-dashboard-card hd-priority-card">
<header><h2>Tickets by Priority</h2></header>
<div class="hd-priority-body"><div class="hd-donut"><svg class="hd-donut-svg" viewBox="0 0 42 42" aria-hidden="true"><circle class="hd-donut-track" cx="21" cy="21" r="15.9155" fill="none" stroke-width="10"></circle>@foreach($donutSegments as $segment)<circle cx="21" cy="21" r="15.9155" fill="none" stroke="{{ $segment['colour'] }}" stroke-width="10" stroke-dasharray="{{ $segment['length'] }} {{ 100 - $segment['length'] }}" stroke-dashoffset="{{ $segment['offset'] }}" transform="rotate(-90 21 21)"></circle>@endforeach</svg><span>{{ $priorityTotal }}</span></div><div class="hd-priority-legend">@foreach($priorityBreakdown as $i => $priority)<div><span><b style="background: {{ $palette[$i % count($palette)] }}"></b>{{ $priority['name'] }}</span><strong>{{ $priority['count'] }} ({{ round(($priority['count']/$priorityTotal)*100, 1) }}%)</strong></div>@endforeach</div></div>
</section>
<section class="hd-dashboard-card hd-latest-card">
<header><h2>Latest Tickets</h2><a href="{{ route('helpdesk.tickets.index') }}" wire:navigate>View all</a></header>
<div class="hd-latest-list">@forelse($recentTickets as $ticket)<a href="{{ route('helpdesk.tickets.show', $ticket) }}" wire:navigate><span class="hd-priority-mini">{{ $ticket->priority?->name ?? 'Normal' }}</span><div><strong>{{ $ticket->subject }}</strong><small>#{{ $ticket->reference }} · {{ $ticket->user?->name ?? 'Unknown' }}</small></div><time>{{ optional($ticket->last_activity_at)->diffForHumans() }}</time><span class="hd-status-mini">{{ $ticket->status?->name ?? 'Open' }}</span></a>@empty<div class="hd-empty">No tickets yet.</div>@endforelse</div>
</section>
<section class="hd-dashboard-card hd-requester-card">
<header><h2>Top Requesters</h2></header>
<div class="hd-requester-list">@forelse($topRequesters as $row)<div><span class="hd-user-avatar">{{ $row['user']->initials() }}</span><strong>{{ $row['user']->name }}</strong><em>{{ $row['count'] }} tickets</em></div>@empty<div class="hd-empty">No requester data yet.</div>@endforelse</div>
</section>
</div>
</div>