@extends('layouts.dashboard')
@section('content')
@php
/**
* Vendor → Upsell rules: what this restaurant offers once a given dish is in the
* basket. One row is one pairing — a target dish, the dish to recommend beside it,
* and an optional discount to sweeten it (UpsellController::index()).
*
* Rules are optional. With none written the engine still recommends: it falls back
* to the cheapest available dish outside the categories the basket already draws
* on. That is why this page never reads as "off" when it is empty.
*
* @var array $rows the current pager window of rule rows, each carrying
* target_name / rec_name / rec_price from the join
* @var array $pager paginate() metadata
* @var array $dishes this restaurant's dishes, for both selects
* @var int $active active rules
* @var int $covered distinct dishes that have at least one active rule
* @var int $sellable dishes a customer can actually order right now
* @var float|null $coverage % of sellable dishes covered (null = nothing sellable)
* @var int $withOffer active rules that carry a discount
* @var bool $engineOn the platform-wide switch
*/
@endphp
@php /* .qm-d2: the dashboard density standard (app.css §35) */
@endphp
@php // Page primary action → top-bar subheader slot, exactly as Coupons does, leaving the
// table card header for the title. ob_start captures the button HTML for the layout slot.
ob_start();
@endphp
@php \App\Support\View::slot('subhead', ob_get_clean());
@endphp
@php /* No reporting-period control on this page: a rule has no history to window. Nothing on
an order records that a recommendation was what sold it, so every figure below is read from
the rules and the menu — a measured number or none at all. */
@endphp
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'blue', 'icon' => 'fa-lightbulb', 'label' => t_raw('vendor.upsell.kpi_active'),
'value' => number_format((int) $active),
'meta' => '' . t('vendor.upsell.kpi_active_meta', [':n' => number_format((int) $pager['total'])]) . ''])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'green', 'icon' => 'fa-hamburger', 'label' => t_raw('vendor.upsell.kpi_covered'),
'value' => number_format((int) $covered), 'href' => route('vendor.menu'),
'meta' => '' . t('vendor.upsell.kpi_covered_meta', [':n' => number_format((int) $sellable)]) . ''])
@php /* Coverage only exists when there is something to cover; with no sellable dish the
figure does not exist and is shown as such rather than as a zero. */
@endphp
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'amber', 'icon' => 'fa-percentage', 'label' => t_raw('vendor.upsell.kpi_coverage'),
'value' => $coverage !== null ? number_format($coverage, 1) . '%' : '—',
'meta' => '' . ($coverage !== null
? t('vendor.upsell.kpi_coverage_meta')
: t('vendor.upsell.kpi_coverage_meta_none')) . ''])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'rose', 'icon' => 'fa-tags', 'label' => t_raw('vendor.upsell.kpi_offers'),
'value' => number_format((int) $withOffer),
'meta' => '' . t('vendor.upsell.kpi_offers_meta') . ''])
@php /* What customers are actually being shown. The vendor cannot change the platform
switch, so it is reported rather than offered — a page full of rules that nothing reads
should say so on the page. */
@endphp
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'slate', 'icon' => 'fa-lightbulb', 'label' => t_raw('vendor.upsell.kpi_engine'),
'value' => $engineOn ? t_raw('vendor.upsell.state_on') : t_raw('vendor.upsell.state_off'),
'meta' => '' . (!$engineOn
? t('vendor.upsell.kpi_engine_meta_off')
: ($active > 0 ? t('vendor.upsell.kpi_engine_meta_rules') : t('vendor.upsell.kpi_engine_meta_auto'))) . ''])
{{ t_raw('vendor.upsell.table_heading') }}
@php /* The offer column mixes a percentage with a money amount, which are not one scale, so
that
carries no data-sort — the same call Coupons makes on its discount column. */
@endphp
{!! $r['rec_name'] !== null ? e((string) $r['rec_name']) : t('vendor.upsell.dish_removed') !!}
@php /* A rule pointing at a dish that is off the menu is not an error to
fix in the database — the engine simply skips it — but the vendor should
be able to see why a pairing they wrote never appears. */
@endphp
@if ($r['rec_name'] !== null && (int) $r['rec_available'] !== 1){{ t_raw('vendor.upsell.rec_unavailable') }}@endif
@partial('table-toolbar', ['pager' => $pager, 'base' => '/vendor/upsell'])
@php /* ====================================================== RULE MODAL (same shape as the
Coupons modal — one form, add and edit share it, the id decides which). The populate script
at the foot of this file is this page's own: app.js's shared bindModal() is registered for a
fixed list of modal names and adding to that list is an edit to a file this page does not own. */
@endphp