@extends('layouts.dashboard')
@section('content')
@php
/**
* Operation Analytics → Menu: menu engineering. Every dish is placed by what it
* sells AND what it earns, so the four classic quadrants (Star, Plough-horse,
* Puzzle, Dog) fall out of the restaurant's own numbers rather than a hunch.
*
* @var array $kpis @var array $trendChart @var array $trendMeta @var array $catChart @var array $catMeta
* @var array $topChart @var array $topMeta @var array $marginChart @var array $marginMeta
* @var array $chanChart @var array $chanMeta @var array $engChart @var array $engMeta
* @var array $dishes @var array $dishPager @var int $totalUnits @var int $costed
* @var int $rangeDays @var array $rangeLinks @var bool $showMoney
*/
// Margin is money, so a manager sees popularity only — the quadrant a dish sits in
// is derived from its margin and travels with it.
$quadrants = [
'star' => ['label' => t_raw('vendor.analytics.quadrant_star'), 'tone' => 'green'],
'plough_horse' => ['label' => t_raw('vendor.analytics.quadrant_plough_horse'), 'tone' => 'blue'],
'puzzle' => ['label' => t_raw('vendor.analytics.quadrant_puzzle'), 'tone' => 'amber'],
'dog' => ['label' => t_raw('vendor.analytics.quadrant_dog'), 'tone' => 'grey'],
];
$cols = 9 + ($showMoney ? 4 : 0);
@endphp
@php /* .qm-d2: the dashboard density standard (app.css §35) */
@endphp
{{ t_raw('dashboard.sec.snapshot') }}
{{ t_raw('vendor.analytics.subtitle_menu') }}
@foreach ($rangeLinks['options'] as $val => $text)
@php $on = ((string) $val === $rangeLinks['selected']); @endphp
{{ $text }}
@endforeach
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'blue', 'icon' => 'fa-utensils', 'label' => t_raw('vendor.analytics.kpi_dishes_sold'),
'value' => number_format($kpis['dishes']['value']), 'spark' => $kpis['dishes']['spark'], 'meta' => $kpis['dishes']['meta']])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'green', 'icon' => 'fa-shopping-basket', 'label' => t_raw('common.units'),
'value' => number_format($kpis['units']['value']), 'spark' => $kpis['units']['spark'], 'meta' => $kpis['units']['meta']])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'rose', 'icon' => 'fa-crown', 'label' => t_raw('vendor.analytics.kpi_best_seller'),
'value' => $kpis['top']['value'] !== null ? $kpis['top']['value'] : '—', 'meta' => $kpis['top']['meta'],
'bgImage' => $kpis['top']['image'] ?? ''])
@if ($showMoney)
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'teal', 'icon' => 'fa-coins', 'label' => t_raw('common.revenue'),
'value' => money($kpis['revenue']['value']), 'spark' => $kpis['revenue']['spark'], 'meta' => $kpis['revenue']['meta']])
@php /* Margin and food cost only count the dishes whose cost has been keyed in;
the caption says how many that is so the figure is never read as the whole menu. */
@endphp
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'violet', 'icon' => 'fa-hand-holding-usd', 'label' => t_raw('vendor.analytics.kpi_gross_margin'),
'value' => $kpis['margin']['value'] !== null ? money($kpis['margin']['value']) : '—',
'spark' => $kpis['margin']['spark'], 'meta' => $kpis['margin']['meta']])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'amber', 'icon' => 'fa-percentage', 'label' => t_raw('vendor.analytics.kpi_food_cost'),
'value' => $kpis['foodCost']['value'] !== null ? number_format($kpis['foodCost']['value'], 1) . '%' : '—',
'spark' => $kpis['foodCost']['spark'], 'meta' => $kpis['foodCost']['meta']])
@endif
{{ t_raw('dashboard.sec.trends') }}
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_units_over_time'), 'sub' => t_raw('vendor.analytics.chart_units_over_time_sub'), 'cfg' => $trendChart, 'meta' => $trendMeta, 'accent' => 'green', 'opts' => ['id' => 'menuTrendChart', 'url' => route('vendor.chart-series', ['chart' => 'menuUnits']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_category_share'), 'sub' => t_raw('vendor.analytics.chart_units_by_category_sub'), 'cfg' => $catChart, 'meta' => $catMeta, 'icon' => 'fa-chart-pie', 'accent' => 'teal'])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_top_sellers'), 'sub' => t_raw('vendor.analytics.chart_top_sellers_caption'), 'cfg' => $topChart, 'meta' => $topMeta, 'icon' => 'fa-chart-bar', 'accent' => 'violet', 'opts' => ['id' => 'menuTopChart', 'url' => route('vendor.chart-series', ['chart' => 'menuTop']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@php /* The owner's second slot is the profit view; a manager, who never sees
money, gets the operational counterpart — what is failing to move. */
@endphp
@if ($showMoney)
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_margin_leaders'), 'sub' => t_raw('vendor.analytics.chart_margin_leaders_sub'), 'cfg' => $marginChart, 'meta' => $marginMeta, 'icon' => 'fa-chart-bar', 'accent' => 'green', 'opts' => ['id' => 'menuMarginChart', 'url' => route('vendor.chart-series', ['chart' => 'menuMargin']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@else
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_slow_movers'), 'sub' => t_raw('vendor.analytics.chart_slow_movers_sub'), 'cfg' => $slowChart, 'meta' => $slowMeta, 'icon' => 'fa-chart-bar', 'accent' => 'amber', 'opts' => ['id' => 'menuSlowChart', 'url' => route('vendor.chart-series', ['chart' => 'menuSlow']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@endif
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_units_by_channel'), 'sub' => t_raw('vendor.analytics.chart_units_by_channel_sub'), 'cfg' => $chanChart, 'meta' => $chanMeta, 'icon' => 'fa-chart-pie', 'accent' => 'blue'])
@if ($showMoney)
@partial('chart-card', ['heading' => t_raw('vendor.analytics.heading_menu_engineering'), 'sub' => t_raw('vendor.analytics.chart_menu_engineering_sub'), 'cfg' => $engChart, 'meta' => $engMeta, 'icon' => 'fa-braille', 'accent' => 'violet'])
{{ t_raw('vendor.analytics.hint_menu_engineering') }}
@endif
{{ t_raw('dashboard.sec.breakdown') }}
{{ t_raw('vendor.analytics.heading_all_dishes') }}
@if ($showMoney)
{{ t_raw('vendor.analytics.hint_cost_missing', [':n' => number_format($costed)]) }}
@endif
{{ t_raw('vendor.analytics.caption_all_dishes') }}
| {{ t_raw('vendor.analytics.col_dish') }} |
{{ t_raw('vendor.analytics.col_category') }} |
{{ t_raw('common.price') }} |
@if ($showMoney)
{{ t_raw('vendor.analytics.col_cost') }} |
{{ t_raw('vendor.analytics.col_food_cost_pct') }} |
@endif
{{ t_raw('common.units') }} |
{{ t_raw('vendor.analytics.col_share') }} |
@if ($showMoney)
{{ t_raw('common.revenue') }} |
{{ t_raw('vendor.analytics.col_margin') }} |
@endif
{{ t_raw('vendor.analytics.col_menu_class') }} |
{{ t_raw('vendor.analytics.col_last_sold') }} |
{{ t_raw('vendor.analytics.col_on_sale') }} |
{{ t_raw('common.actions') }} |
@if ($dishes)
@foreach ($dishes as $d)
@php $units = (int) $d['units']; $q = $d['quadrant'] ?? null; @endphp
{{ $d['name'] }}
|
{!! !empty($d['category_name']) ? e((string) $d['category_name']) : t('vendor.analytics.uncategorised') !!} |
{{ money($d['price']) }} |
@if ($showMoney)
@php /* A dish with no cost recorded reports nothing rather than a
zero — zero cost would flatter every margin figure beside it. */
@endphp
{!! $d['cost'] !== null ? money($d['cost']) : dash() !!} |
{!! $d['food_cost_pct'] !== null ? number_format((float) $d['food_cost_pct'], 1) . '%' : dash() !!} |
@endif
{{ number_format($units) }} |
{!! $totalUnits > 0 ? number_format(100 * $units / $totalUnits, 1) . '%' : dash() !!} |
@if ($showMoney)
{{ money($d['revenue']) }} |
{!! $d['margin_total'] !== null ? money($d['margin_total']) : dash() !!} |
@endif
@if ($q !== null && isset($quadrants[$q]))
{{ $quadrants[$q]['label'] }}
@else{!! dash() !!}@endif
|
{!! fmt_day($d['last_sold']) !!} |
{!! (int) $d['is_available'] === 1 ? t('common.yes') : t('common.no') !!} |
|
@endforeach
@else
@partial('table-empty', ['colspan' => $cols, 'icon' => 'fa-utensils', 'msg' => t_raw('vendor.analytics.empty_no_dishes')])
@endif
@partial('table-toolbar', ['pager' => $dishPager, 'base' => '/vendor/analytics/menu'])
@php /* /.qm-d2 */
@endphp
@endsection