@extends('admin.layout') @section('title', 'Trends') @section('content') @php $kpi = $trends['kpi']; $ser = $trends['series']; $grain = $trends['grain']; $axis = $trends['axis']; $periodLabels = ['30d' => '30 dagen', '3m' => '3 maanden', '6m' => '6 maanden', '9m' => '9 maanden', '12m' => '12 maanden']; $axisLabel = fn(string $d) => match($grain) { 'month' => \Carbon\Carbon::parse($d)->translatedFormat('M'), 'week' => \Carbon\Carbon::parse($d)->format('d M'), default => \Carbon\Carbon::parse($d)->format('d'), }; $tooltipLabel = fn(string $d) => match($grain) { 'month' => \Carbon\Carbon::parse($d)->translatedFormat('F Y'), 'week' => 'Week ' . \Carbon\Carbon::parse($d)->format('d M'), default => \Carbon\Carbon::parse($d)->translatedFormat('d F'), }; $charts = [ 'total_users' => ['label' => 'Gebruikers', 'data' => $ser['usersTimeline']->toArray(), 'color' => '#6366f1', 'unit' => '', 'section' => 'growth', 'cumulative' => true], 'total_premium' => ['label' => 'Premium', 'data' => $ser['premiumTimeline']->toArray(), 'color' => '#8b5cf6', 'unit' => '', 'section' => 'growth', 'cumulative' => true], 'total_pro' => ['label' => 'PRO', 'data' => $ser['proTimeline']->toArray(), 'color' => '#f59e0b', 'unit' => '', 'section' => 'growth', 'cumulative' => true], 'total_org' => ['label' => 'Org', 'data' => $ser['orgTimeline']->toArray(), 'color' => '#14b8a6', 'unit' => '', 'section' => 'growth', 'cumulative' => true], 'churn' => ['label' => 'Opzeggingen', 'data' => $ser['churnSeries']->toArray(), 'color' => '#f43f5e', 'unit' => '', 'section' => 'growth'], 'dau' => ['label' => 'DAU', 'data' => $ser['dau']->toArray(), 'color' => '#6366f1', 'unit' => '', 'section' => 'commercial'], 'guest_sessions' => ['label' => 'Guest-sessies', 'data' => $ser['guestSessions']->toArray(), 'color' => '#94a3b8', 'unit' => '', 'section' => 'commercial'], 'signups' => ['label' => 'Registraties', 'data' => $ser['signups']->toArray(), 'color' => '#10b981', 'unit' => '', 'section' => 'commercial'], 'new_subs' => ['label' => 'Nieuwe abonnees','data' => $ser['newSubs']->toArray(), 'color' => '#8b5cf6', 'unit' => '', 'section' => 'commercial'], 'conversion' => ['label' => 'Conversie', 'data' => $ser['conversionSeries']->toArray(), 'color' => '#f59e0b', 'unit' => '%', 'section' => 'commercial'], 'profile_views' => ['label' => 'Bezochte profielen', 'data' => $ser['profileViews']->toArray(), 'color' => '#14b8a6', 'unit' => '', 'section' => 'engagement'], 'messages_sent' => ['label' => 'Berichten', 'data' => $ser['messagesSent']->toArray(), 'color' => '#0ea5e9', 'unit' => '', 'section' => 'engagement'], 'likes_sent' => ['label' => 'Likes', 'data' => $ser['likesSeries']->toArray(), 'color' => '#f43f5e', 'unit' => '', 'section' => 'engagement'], 'matches' => ['label' => 'Matches', 'data' => $ser['matchesSeries']->toArray(), 'color' => '#ec4899', 'unit' => '', 'section' => 'engagement'], 'posts_created' => ['label' => 'Posts', 'data' => $ser['postsCreated']->toArray(), 'color' => '#a78bfa', 'unit' => '', 'section' => 'engagement'], 'resp_time' => ['label' => 'Gem. resp.tijd', 'data' => $ser['respTime']->toArray(), 'color' => '#f59e0b', 'unit' => ' ms', 'section' => 'technical', 'avg' => true], 'req_vol' => ['label' => 'Verzoeken', 'data' => $ser['reqVolume']->toArray(), 'color' => '#0ea5e9', 'unit' => '', 'section' => 'technical'], 'err5xx' => ['label' => '5xx fouten', 'data' => $ser['err5xx']->toArray(), 'color' => '#ef4444', 'unit' => '', 'section' => 'technical'], 'err4xx' => ['label' => '4xx fouten', 'data' => $ser['err4xx']->toArray(), 'color' => '#f97316', 'unit' => '', 'section' => 'technical'], 'failed' => ['label' => 'Mislukte logins', 'data' => $ser['failedLogins']->toArray(), 'color' => '#dc2626', 'unit' => '', 'section' => 'technical'], ]; $sparkline = function(array $chart) use ($axis, $axisLabel, $tooltipLabel): string { $data = $chart['data']; $max = max(1, max($data)); $vals = array_values($data); $n = count($vals); $sum = array_sum($vals); $last = end($vals); $prev = $n >= 2 ? $vals[$n - 2] : 0; $arrow = $last > $prev ? '↑' : ($last < $prev ? '↓' : '='); $arrowColor = ($chart['section'] === 'technical' && in_array($chart['label'], ['5xx fouten','4xx fouten','Mislukte logins','Gem. resp.tijd'])) ? ($last > $prev ? 'color:#ef4444' : ($last < $prev ? 'color:#22c55e' : 'color:#9ca3af')) : ($last >= $prev ? 'color:' . $chart['color'] : 'color:#9ca3af'); $summaryVal = ($chart['cumulative'] ?? false) ? $last . $chart['unit'] : (($chart['avg'] ?? false) && $sum > 0 ? 'gem. ' . round(array_sum(array_filter($vals)) / max(1, count(array_filter($vals)))) . $chart['unit'] : $sum . $chart['unit'] . ' totaal'); $bars = ''; foreach ($data as $d => $v) { $h = max($v > 0 ? 2 : 0, (int) round($v / $max * 58)); $tip = $tooltipLabel($d) . ': ' . $v . $chart['unit']; $bars .= "
"; } $firstLabel = $axisLabel(array_key_first($data)); $lastLabel = $axisLabel(array_key_last($data)); return "
{$chart['label']} {$summaryVal}
{$bars}
{$firstLabel} {$last}{$chart['unit']} {$arrow}
"; }; @endphp
{{-- Header + periodeselector --}}

Trends

@foreach ($periodLabels as $key => $lbl) {{ $lbl }} @endforeach
{{-- KPI-strip --}}
@foreach ([ ['Conversieratio', number_format($kpi['conv_rate'], 1) . '%', $kpi['conv_rate'] >= 5 ? 'text-violet-600' : 'text-gray-700'], ['DAU gem. (30d)', number_format($kpi['dau_avg'], 1), $kpi['dau_avg'] >= 10 ? 'text-indigo-600' : 'text-gray-700'], ['Gem. resp. (30d)', $kpi['avg_resp_ms'] . ' ms', $kpi['avg_resp_ms'] < 500 ? 'text-green-600' : ($kpi['avg_resp_ms'] < 1500 ? 'text-yellow-600' : 'text-red-600')], ['P95 resp. (30d)', $kpi['p95_resp_ms'] . ' ms', $kpi['p95_resp_ms'] < 1000 ? 'text-green-600' : ($kpi['p95_resp_ms'] < 3000 ? 'text-yellow-600' : 'text-red-600')], ['5xx (30d)', (string) $kpi['err5xx_total'], $kpi['err5xx_total'] === 0 ? 'text-green-600' : ($kpi['err5xx_total'] < 20 ? 'text-yellow-600' : 'text-red-600')], ['Mislukte logins', (string) $kpi['failed_logins'], $kpi['failed_logins'] < 5 ? 'text-green-600' : 'text-red-600'], ['Opzeggingen (30d)', (string) $kpi['churn_30'], $kpi['churn_30'] === 0 ? 'text-green-600' : 'text-red-600'], ] as [$lbl, $val, $cls])

{{ $lbl }}

{{ $val }}

@endforeach
{{-- Ledengroei --}}

Ledengroei

@foreach (array_filter($charts, fn($c) => $c['section'] === 'growth') as $chart) {!! $sparkline($chart) !!} @endforeach
{{-- Commercieel --}}

Commercieel

@foreach (array_filter($charts, fn($c) => $c['section'] === 'commercial') as $chart) {!! $sparkline($chart) !!} @endforeach
{{-- Activiteit --}}

Activiteit

@foreach (array_filter($charts, fn($c) => $c['section'] === 'engagement') as $chart) {!! $sparkline($chart) !!} @endforeach
{{-- Technisch --}}

Technisch

@foreach (array_filter($charts, fn($c) => $c['section'] === 'technical') as $chart) {!! $sparkline($chart) !!} @endforeach
@endsection