@extends('layouts.dashboard')
@section('content')
@php
/**
* Platform Analytics → Customers: who is ordering across the platform —
* first-timers vs regulars, guest checkouts, how well each intake month is
* retained, and the customers who matter most.
*
* @var array $active @var array $newAccounts @var array $newCustomers @var array $returning
* @var array $guestOrders @var array $guestShare @var array $orders
* @var array $bandRows @var array $top @var array $topPager
* @var array $dayChart @var array $dayMeta @var array $mixChart @var array $mixMeta
* @var array $cohortChart @var array $cohortMeta @var array $bandChart @var array $bandMeta
* @var array $splitChart @var array $splitMeta @var array $guestChart @var array $guestMeta
* @var array $spendChart @var array $spendMeta
* @var int $rangeDays @var string $rangeMode @var array $rangeLinks
*/
$kpiMeta = static fn (array $m, string $caption): string =>
kpi_trend((int) $m['pct'], (string) $m['dir']) . '' . $caption . '';
$activeCount = max(1, (int) $active['total']);
$totalBandCustomers = 0;
foreach ($bandRows as $bandRow) {
$totalBandCustomers += (int) $bandRow['customers'];
}
@endphp
@php /* .qm-d2: the dashboard density standard (app.css §35) */
@endphp
{{ t_raw('dashboard.sec.snapshot') }}
{{ t_raw('admin.analytics.customers_sub') }}
@foreach ($rangeLinks['options'] as $val => $text)
@php $on = ((string) $val === $rangeLinks['selected']); @endphp
{{ $text }}
@endforeach
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'blue', 'icon' => 'fa-users', 'label' => t_raw('nav.customers'),
'value' => number_format($active['total']), 'spark' => $active['cur'],
'meta' => $kpiMeta($active, t('admin.analytics.meta_account_holders'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'teal', 'icon' => 'fa-user-plus', 'label' => t_raw('admin.analytics.kpi_new_accounts'),
'value' => number_format($newAccounts['total']), 'href' => route('admin.users'), 'spark' => $newAccounts['cur'],
'meta' => $kpiMeta($newAccounts, t('admin.analytics.meta_registered_in_period'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'green', 'icon' => 'fa-user-check', 'label' => t_raw('admin.analytics.kpi_new_customers'),
'value' => number_format($newCustomers['total']), 'spark' => $newCustomers['cur'],
'meta' => $kpiMeta($newCustomers, t('admin.analytics.meta_first_order_period'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'amber', 'icon' => 'fa-redo', 'label' => t_raw('common.returning'),
'value' => number_format($returning['total']), 'spark' => $returning['cur'],
'meta' => $kpiMeta($returning, t('admin.analytics.meta_pct_of_customers', [':pct' => number_format($returning['total'] / $activeCount * 100)]))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'orange', 'icon' => 'fa-user-secret', 'label' => t_raw('common.guest_orders'),
'value' => number_format($guestOrders['total']), 'spark' => $guestOrders['cur'],
'meta' => $kpiMeta($guestOrders, t('admin.analytics.meta_pct_of_orders', [':pct' => number_format($guestShare['total'])]))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'violet', 'icon' => 'fa-shopping-basket', 'label' => t_raw('common.orders'),
'value' => number_format($orders['total']), 'href' => route('admin.orders'), 'spark' => $orders['cur'],
'meta' => $kpiMeta($orders, t('admin.analytics.meta_vs_prior'))])
{{ t_raw('dashboard.sec.trends') }}
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_customers_per_day'), 'sub' => t_raw('admin.analytics.chart_customers_per_day_caption'), 'cfg' => $dayChart, 'meta' => $dayMeta, 'accent' => 'blue', 'opts' => ['id' => 'admCustDayChart', 'url' => route('admin.chart-series', ['chart' => 'custDay']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_account_vs_guest'), 'sub' => t_raw('admin.analytics.chart_account_vs_guest_caption'), 'cfg' => $mixChart, 'meta' => $mixMeta, 'icon' => 'fa-user-secret', 'accent' => 'violet', 'opts' => ['id' => 'admCustMixChart', 'url' => route('admin.chart-series', ['chart' => 'custMix']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_cohort_retention'), 'sub' => t_raw('admin.analytics.chart_cohort_retention_caption'), 'cfg' => $cohortChart, 'meta' => $cohortMeta, 'icon' => 'fa-th', 'accent' => 'teal'])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_order_frequency'), 'sub' => t_raw('admin.analytics.chart_order_frequency_caption'), 'cfg' => $bandChart, 'meta' => $bandMeta, 'icon' => 'fa-chart-bar', 'accent' => 'green'])
{{ t_raw('dashboard.sec.breakdown') }}
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_new_vs_returning'), 'sub' => t_raw('admin.analytics.chart_new_vs_returning_caption'), 'cfg' => $splitChart, 'meta' => $splitMeta, 'icon' => 'fa-chart-pie', 'accent' => 'green'])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_revenue_by_identity'), 'sub' => t_raw('admin.analytics.chart_revenue_by_identity_caption'), 'cfg' => $guestChart, 'meta' => $guestMeta, 'icon' => 'fa-chart-pie', 'accent' => 'violet'])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_top_customers_by_spend'), 'sub' => t_raw('admin.analytics.chart_top_customers_caption'), 'cfg' => $spendChart, 'meta' => $spendMeta, 'icon' => 'fa-chart-bar', 'accent' => 'amber', 'opts' => ['id' => 'admCustSpendChart', 'url' => route('admin.chart-series', ['chart' => 'custSpend']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
{{ t_raw('admin.analytics.h_order_frequency') }}
{{ t_raw('admin.analytics.caption_order_frequency') }}
| {{ t_raw('admin.analytics.col_band') }} |
{{ t_raw('nav.customers') }} |
{{ t_raw('admin.analytics.col_share') }} |
{{ t_raw('common.orders') }} |
{{ t_raw('admin.analytics.col_spend') }} |
{{ t_raw('common.average_order') }} |
@if ($totalBandCustomers > 0)
@foreach ($bandRows as $row)
@php $n = (int) $row['customers']; @endphp
| {{ $row['label'] }} |
{{ number_format($n) }} |
{!! $n > 0 ? number_format($n / $totalBandCustomers * 100, 1) . '%' : dash() !!} |
{!! (int) $row['orders'] > 0 ? number_format((int) $row['orders']) : dash() !!} |
{!! (float) $row['spend'] > 0 ? money($row['spend']) : dash() !!} |
{!! (int) $row['orders'] > 0 ? money((float) $row['spend'] / (int) $row['orders']) : dash() !!} |
@endforeach
@else
@partial('table-empty', ['colspan' => 6, 'icon' => 'fa-layer-group', 'msg' => t('admin.analytics.empty_no_customer_orders')])
@endif
{{ t_raw('admin.analytics.caption_best_customers') }}
| {{ t_raw('common.customer') }} |
{{ t_raw('common.orders') }} |
{{ t_raw('admin.analytics.col_spend') }} |
{{ t_raw('common.average_order') }} |
{{ t_raw('nav.restaurants') }} |
{{ t_raw('admin.analytics.col_last_order') }} |
@if ($top)
@foreach ($top as $t)
@php $c = (int) $t['orders_c']; @endphp
{!! brandmark_html($t['avatar'] ?? null, (string) $t['name'], 'md', 'qm-brandmark--round') !!}
{{ $t['name'] }}{{ $t['email'] }}
|
{{ number_format($c) }} |
{{ money($t['spend']) }} |
{!! $c > 0 ? money((float) $t['spend'] / $c) : dash() !!} |
{{ number_format((int) $t['restaurants_c']) }} {{ t_raw('admin.analytics.ordered_from_suffix') }} |
{!! fmt_day($t['last_order']) !!} |
@endforeach
@else
@partial('table-empty', ['colspan' => 6, 'icon' => 'fa-users', 'msg' => t('admin.analytics.empty_no_customer_orders')])
@endif
@partial('table-toolbar', ['pager' => $topPager, 'base' => '/admin/analytics/customers'])
@php /* /.qm-d2 */
@endphp
@endsection