@extends('layouts.dashboard')
@section('content')
@php
/**
* Platform Analytics → Restaurants: partner growth, the approval pipeline,
* the volume each partner transacts and where they all trade from.
*
* @var array $counts @var array $estate @var array $joined @var array $pending
* @var array $traders @var array $gmv @var array $commission
* @var array $rows @var array $perfPager @var array $locations
* @var array $growthChart @var array $growthMeta @var array $moneyChart @var array $moneyMeta
* @var array $statusChart @var array $statusMeta @var array $activeChart @var array $activeMeta
* @var array $cuisineChart @var array $cuisineMeta
* @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 . ' ';
$statusPill = static fn (string $s): string => $s === 'approved' ? 'qm-pill-green' : ($s === 'pending' ? 'qm-pill-amber' : 'qm-pill-red');
$statusColor = static fn (string $s): string => $s === 'approved' ? 'var(--ok)' : ($s === 'pending' ? 'var(--warn)' : 'var(--danger)');
$restaurantPoints = [];
foreach ($locations as $loc) {
if ($loc['lat'] === null || $loc['lng'] === null) {
continue;
}
$ring = $statusColor((string) $loc['status']);
$restaurantPoints[] = [
'lat' => (float) $loc['lat'],
'lng' => (float) $loc['lng'],
'label' => $loc['name'] . (!empty($loc['city']) ? ' — ' . $loc['city'] : ''),
'url' => url('/admin/restaurants?q=' . rawurlencode((string) $loc['name'])),
// The restaurant's own logo (or initials monogram), ringed in its status
// colour - same brandmark used everywhere else the logo appears.
'iconHtml' => restaurant_logo_html($loc, 'sm', '', 'style="box-shadow:0 0 0 3px ' . e($ring) . '"'),
];
}
$restaurantMapCenter = $restaurantPoints ? $restaurantPoints[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('admin.analytics.restaurants_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-store', 'label' => t_raw('admin.analytics.kpi_on_platform'),
'value' => number_format((int) $counts['total']), 'href' => route('admin.restaurants'), 'spark' => $estate['cur'],
'meta' => $kpiMeta($estate, t('admin.analytics.meta_all_restaurants'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'violet', 'icon' => 'fa-plus-circle', 'label' => t_raw('admin.analytics.kpi_new_this_period'),
'value' => number_format($joined['total']), 'spark' => $joined['cur'],
'meta' => $kpiMeta($joined, t('admin.analytics.meta_vs_prior'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'amber', 'icon' => 'fa-hourglass-half', 'label' => t_raw('admin.dashboard.pending_approval'),
'value' => number_format((int) $counts['pending']), 'href' => route('admin.restaurants'), 'spark' => $pending['cur'],
'meta' => $kpiMeta($pending, t('admin.analytics.meta_awaiting_review'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'green', 'icon' => 'fa-store-alt', 'label' => t_raw('admin.analytics.kpi_trading_partners'),
'value' => number_format($traders['total']), 'spark' => $traders['cur'],
'meta' => $kpiMeta($traders, t('admin.analytics.meta_took_orders'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'teal', 'icon' => 'fa-coins', 'label' => t_raw('admin.analytics.series_gmv'),
'value' => money($gmv['total']), 'href' => route('admin.analytics.sales'), 'spark' => $gmv['cur'],
'meta' => $kpiMeta($gmv, t('admin.analytics.meta_transacted_by_partners'))])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'orange', 'icon' => 'fa-percentage', 'label' => t_raw('common.commission'),
'value' => money($commission['total']), 'href' => route('admin.analytics.revenue'), 'spark' => $commission['cur'],
'meta' => $kpiMeta($commission, t('admin.analytics.meta_stamped_rate'))])
{{ t_raw('dashboard.sec.trends') }}
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_partner_growth'), 'sub' => t_raw('admin.analytics.chart_partner_growth_caption'), 'cfg' => $growthChart, 'meta' => $growthMeta, 'icon' => 'fa-chart-line', 'accent' => 'violet', 'opts' => ['id' => 'admRestGrowthChart', 'url' => route('admin.chart-series', ['chart' => 'restGrowth']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_partner_volume'), 'sub' => t_raw('admin.analytics.chart_partner_volume_caption'), 'cfg' => $moneyChart, 'meta' => $moneyMeta, 'accent' => 'green', 'opts' => ['id' => 'admRestMoneyChart', 'url' => route('admin.chart-series', ['chart' => 'restMoney']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
{{ t_raw('dashboard.sec.breakdown') }}
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_status_mix'), 'sub' => t_raw('admin.analytics.chart_approval_pipeline'), 'cfg' => $statusChart, 'meta' => $statusMeta, 'icon' => 'fa-chart-pie', 'accent' => 'green'])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_cuisine_mix'), 'sub' => t_raw('admin.analytics.chart_cuisine_mix_caption'), 'cfg' => $cuisineChart, 'meta' => $cuisineMeta, 'icon' => 'fa-chart-pie', 'accent' => 'teal'])
@partial('chart-card', ['heading' => t_raw('admin.analytics.chart_most_active_restaurants'), 'sub' => t_raw('admin.analytics.chart_most_active_caption'), 'cfg' => $activeChart, 'meta' => $activeMeta, 'icon' => 'fa-chart-bar', 'accent' => 'blue', 'opts' => ['id' => 'admRestActiveChart', 'url' => route('admin.chart-series', ['chart' => 'restActive']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@php /* Same title-and-tip pair the Restaurant performance card below uses: what the
map covers is an aside, not a caption the reader has to clear on every visit.
mb-3 resolves to 8px inside .qm-d2 - the same gap that card's head leaves
above its own content, so the two heading rows sit on one rhythm. */
@endphp
{{ t_raw('admin.analytics.h_restaurant_locations') }}
@if ($restaurantPoints)
@else
{{ t_raw('admin.analytics.empty_no_locations') }}
@endif
{{ t_raw('admin.analytics.caption_perf') }}
{{ t_raw('common.restaurant') }}
{{ t_raw('common.status') }}
{{ t_raw('common.orders') }}
{{ t_raw('admin.analytics.col_collected') }}
{{ t_raw('common.average_order') }}
{{ t_raw('common.commission') }}
{{ t_raw('admin.analytics.col_last_order') }}
{{ t_raw('common.joined') }}
@if ($rows)
@foreach ($rows as $row)
@php $c = (int) $row['orders_c']; @endphp
{!! restaurant_brandmark($row, 'md') !!}
{{ $row['name'] }} @if (!empty($row['cuisine_name']) || !empty($row['city'])){{ trim(($row['cuisine_name'] ?? '') . (!empty($row['cuisine_name']) && !empty($row['city']) ? ' · ' : '') . ($row['city'] ?? '')) }} @endif
{{ status_label('restaurant', $row['status']) }}
{{ number_format($c) }}
{{ money($row['collected']) }}
{!! $c > 0 ? money((float) $row['collected'] / $c) : dash() !!}
{!! (float) $row['commission'] > 0 ? money($row['commission']) : dash() !!}
{!! fmt_day($row['last_order']) !!}
{!! fmt_day($row['created_at']) !!}
@endforeach
@else
@partial('table-empty', ['colspan' => 8, 'icon' => 'fa-store', 'msg' => t('admin.restaurants.empty_none')])
@endif
@partial('table-toolbar', ['pager' => $perfPager, 'base' => '/admin/analytics/restaurants'])
@php /* /.qm-d2 */
@endphp
@endsection