@extends('layouts.dashboard')
@section('content')
@php
/**
* Operation Analytics → Customers: who is ordering — new vs returning, guest
* share, the channels they arrive through, and the restaurant's best customers.
*
* @var array $kpis @var array $dayChart @var array $dayMeta @var array $mixChart @var array $mixMeta
* @var array $identityChart @var array $identityMeta @var array $sourceChart @var array $sourceMeta
* @var array $spendChart @var array $spendMeta @var array $topCustomers @var array $custPager
* @var int $rangeDays @var array $rangeLinks @var array $clientLocations
*/
$loyLabel = (string) ($restaurant['loyalty_points_label'] ?? 'points');
$clientPoints = [];
foreach ($clientLocations as $cl) {
if ($cl['delivery_lat'] === null || $cl['delivery_lng'] === null) {
continue;
}
$addr = trim((string) ($cl['delivery_address'] ?? ''));
$clientPoints[] = [
'lat' => (float) $cl['delivery_lat'],
'lng' => (float) $cl['delivery_lng'],
'label' => $cl['name'] . ($addr !== '' ? ' — ' . $addr : ''),
// The customer's own avatar (or initials monogram) - same brandmark
// used everywhere else a person's avatar appears.
'iconHtml' => brandmark_html($cl['avatar'] ?? null, (string) $cl['name'], 'sm'),
];
}
$clientMapCenter = $clientPoints ? $clientPoints[0] : ['lat' => 37.7749, 'lng' => -122.4194];
@endphp
@php /* .qm-d2: the dashboard density standard (app.css §35) */
@endphp
{{ t_raw('dashboard.sec.snapshot') }}
{{ t_raw('vendor.analytics.subtitle_customers') }}
@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('common.customers'),
'value' => number_format($kpis['customers']['value']), 'spark' => $kpis['customers']['spark'], 'meta' => $kpis['customers']['meta']])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'green', 'icon' => 'fa-user-plus', 'label' => t_raw('vendor.analytics.kpi_new_customers'),
'value' => number_format($kpis['new']['value']), 'meta' => $kpis['new']['meta']])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'violet', 'icon' => 'fa-redo', 'label' => t_raw('common.returning'),
'value' => number_format($kpis['returning']['value']), 'meta' => $kpis['returning']['meta']])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'amber', 'icon' => 'fa-user-clock', 'label' => t_raw('common.guest_orders'),
'value' => number_format($kpis['guests']['value']), 'spark' => $kpis['guests']['spark'], 'meta' => $kpis['guests']['meta']])
@php /* Spend per head reads from the covers keyed in at the till; with none
recorded the card shows an em-dash rather than dividing by nothing. */
@endphp
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'teal', 'icon' => 'fa-user-friends', 'label' => t_raw('vendor.analytics.kpi_spend_per_head'),
'value' => $kpis['perHead']['value'] !== null ? money($kpis['perHead']['value']) : '—',
'spark' => $kpis['perHead']['spark'], 'meta' => $kpis['perHead']['meta']])
{{ t_raw('dashboard.sec.trends') }}
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_customers_per_day'), 'sub' => t_raw('vendor.analytics.chart_customers_per_day_caption'), 'cfg' => $dayChart, 'meta' => $dayMeta, 'accent' => 'blue', 'opts' => ['id' => 'custDayChart', 'url' => route('vendor.chart-series', ['chart' => 'custPerDay']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_new_vs_returning'), 'sub' => t_raw('vendor.analytics.chart_new_vs_returning_caption'), 'cfg' => $mixChart, 'meta' => $mixMeta, 'icon' => 'fa-chart-pie', 'accent' => 'green'])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_account_vs_guest'), 'sub' => t_raw('vendor.analytics.chart_account_vs_guest_sub'), 'cfg' => $identityChart, 'meta' => $identityMeta, 'icon' => 'fa-chart-pie', 'accent' => 'violet'])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_order_channels'), 'sub' => t_raw('vendor.analytics.chart_order_channels_sub'), 'cfg' => $sourceChart, 'meta' => $sourceMeta, 'icon' => 'fa-chart-pie', 'accent' => 'teal'])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_top_customers_spend'), 'sub' => t_raw('vendor.analytics.chart_collected_period_sub'), 'cfg' => $spendChart, 'meta' => $spendMeta, 'icon' => 'fa-chart-bar', 'accent' => 'amber', 'opts' => ['id' => 'custSpendChart', 'url' => route('vendor.chart-series', ['chart' => 'custTop']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
{{ t_raw('dashboard.sec.breakdown') }}
{{ t_raw('vendor.analytics.heading_client_locations') }}
{{ t_raw('vendor.analytics.hint_client_locations') }}
@if ($clientPoints)
@else
{{ t_raw('vendor.analytics.empty_no_client_locations') }}
@endif
{{ t_raw('vendor.analytics.heading_best_customers') }}
{{ t_raw('vendor.analytics.caption_best_customers') }}
| {{ t_raw('common.customer') }} |
{{ t_raw('common.orders') }} |
{{ t_raw('admin.analytics_customers.col_spend') }} |
{{ t_raw('common.average_order') }} |
{{ t_raw('vendor.analytics.kpi_covers') }} |
{{ t_raw('vendor.analytics.col_per_head') }} |
{{ t_raw('vendor.analytics.col_loyalty_balance') }} |
{{ t_raw('vendor.analytics.col_last_order') }} |
@if ($topCustomers)
@foreach ($topCustomers as $c)
@php $orders = (int) $c['orders_c']; $covers = (int) $c['covers']; @endphp
{!! brandmark_html($c['avatar'] ?? null, (string) $c['name'], 'md', 'qm-brandmark--round') !!}
{{ $c['name'] }}
{{ $c['email'] }}
|
{{ number_format($orders) }} |
{{ money($c['spend']) }} |
{!! $orders > 0 ? money((float) $c['spend'] / $orders) : dash() !!} |
{!! $covers > 0 ? number_format($covers) : dash() !!} |
{!! $covers > 0 ? money((float) $c['spend'] / $covers) : dash() !!} |
{!! $c['points'] !== null ? number_format((int) $c['points']) . ' ' . e($loyLabel) : dash() !!} |
{!! fmt_datetime($c['last_order']) !!} |
@endforeach
@else
@partial('table-empty', ['colspan' => 8, 'icon' => 'fa-users', 'msg' => t_raw('vendor.analytics.empty_no_account_customers')])
@endif
@partial('table-toolbar', ['pager' => $custPager, 'base' => '/vendor/analytics/customers'])
@php /* /.qm-d2 */
@endphp
@endsection