@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.h_restaurant_performance') }}

{{ t_raw('admin.analytics.manage_restaurants_link') }}
@if ($rows) @foreach ($rows as $row) @php $c = (int) $row['orders_c']; @endphp @endforeach @else @partial('table-empty', ['colspan' => 8, 'icon' => 'fa-store', 'msg' => t('admin.restaurants.empty_none')]) @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') }}
{!! 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']) !!}
@partial('table-toolbar', ['pager' => $perfPager, 'base' => '/admin/analytics/restaurants'])
@php /* /.qm-d2 */ @endphp @endsection