@extends('layouts.dashboard') @section('content') @php /** * Vendor → Menu → Structure. * * How the menu is DIVIDED and WHEN parts of it are offered. Both were on the dish list, in a * col-4/col-8 row that locked a 26-row section list and a 3-row schedule table to the same * 1,590px height and pushed the dishes two screens down the page. They are one job, they are * touched about once a month, and they both want a full-width table — so they live here. * * @var array $categories sections (id, name, sort_order, schedule_id, station_id) * @var array $catCounts dishes per section id * @var array $schedules day-part windows * @var array $scheduleCounts dishes attached per schedule id * @var array $stations kitchen stations (id, name, sort_order, is_active) * @var array $stationCounts dishes reaching each station once inheritance is resolved * @var int $unassignedDishes dishes reaching no station at all * @var string $menuName what this restaurant calls its menu * @var int $dishCount total dishes, for the tab badge * @var int $draftCount imports awaiting review, for the tab badge * @var bool $canImport whether either import route is configured */ use App\Services\MenuSchedule; $categories = $categories ?? []; $allCategories = $allCategories ?? $categories; $pager = $pager ?? []; $catCounts = $catCounts ?? []; $schedules = $schedules ?? []; $scheduleCounts = $scheduleCounts ?? []; $stations = $stations ?? []; $stationCounts = $stationCounts ?? []; $unassignedDishes = (int) ($unassignedDishes ?? 0); $menuName = (string) ($menuName ?? ''); $dishCount = (int) ($dishCount ?? 0); $draftCount = (int) ($draftCount ?? 0); $canImport = !empty($canImport); // Schedule id -> name, so a section can show which window it is attached to by name. $schedName = []; foreach ($schedules as $s) { $schedName[(int) $s['id']] = (string) $s['name']; } // Station id -> name, for the same reason on the station column. $statName = []; foreach ($stations as $s) { $statName[(int) $s['id']] = (string) $s['name']; } @endphp @php /* Vertical tabs, the same .qm-settings grid the settings pages use: a 232px sticky nav beside its panel. Serving times were below twenty-seven sections and effectively unfindable; now they are one click, and neither table pushes the other down. */ @endphp
{{ t_raw('vendor.menu.sections_sub') }}
| {{ t_raw('vendor.menu.reorder_label') }} | {{ t_raw('common.name') }} | {{ t_raw('vendor.menu.col_dishes') }} | {{ t_raw('vendor.menu.availability_label') }} | @if ($stations){{ t_raw('vendor.menu.station_label') }} | @endif{{ t_raw('common.actions') }} |
|---|---|---|---|---|---|
| {{ $c['name'] }} | @php /* Amber at zero: an empty section is not an error, but it is the thing on this page most worth noticing. */ @endphp{{ number_format($n) }} | @php /* No .qm-cell-body here: that utility is white-space:pre-line, for genuinely multi-line content, and the newlines in this block would render as a real line break that drops the text below its row. */ @endphp@if ($sid > 0 && isset($schedName[$sid])) {{ $schedName[$sid] }}@else{{ t_raw('vendor.menu.always_available_option') }}@endif | @php /* Amber when nothing cooks it: an unmapped section still reaches the board, but it reaches the UNASSIGNED screen rather than a cook's own. */ @endphp @if ($stations)@if ($stid > 0 && isset($statName[$stid])) {{ $statName[$stid] }}@else{{ t_raw('vendor.menu.station_unassigned_option') }}@endif | @endif@php /* The shared component, as the saved-menus table uses. This cell was hand-rolled — the fourth different action treatment in one feature, which is exactly what the partial exists to prevent. */ @endphp @partial('row-actions', ['actions' => [ ['label' => t_raw('common.edit'), 'icon' => 'fa-pen', 'primary' => true, 'attrs' => ['data-cat-edit' => '1', 'data-id' => (string) (int) $c['id'], 'data-name' => (string) $c['name'], 'data-sort' => (string) (int) $c['sort_order'], 'data-sched' => $sid > 0 ? (string) $sid : '', 'data-station' => $stid > 0 ? (string) $stid : '', 'data-bs-toggle' => 'modal', 'data-bs-target' => '#catModal']], ['label' => t_raw('common.delete'), 'icon' => 'fa-trash-alt', 'danger' => true, 'form' => ['action' => '/vendor/menu/category/delete', 'fields' => ['id' => (int) $c['id']], 'confirm' => t_raw('vendor.menu.confirm_delete_category')]], ]]) |
{{ t_raw('vendor.menu.schedules_sub') }}
| {{ t_raw('common.name') }} | {{ t_raw('common.when') }} | {{ t_raw('vendor.menu.col_products') }} | {{ t_raw('common.status') }} | {{ t_raw('common.actions') }} |
|---|---|---|---|---|
| {{ $s['name'] }} | {{ MenuSchedule::describe($s) }} | @php /* The COUNT pill stays neutral. It was bound to is_active, so a schedule with nothing attached rendered "0" in green — success colouring on the one number that means the schedule is doing nothing. */ @endphp{{ (int) ($scheduleCounts[(int) $s['id']] ?? 0) }} | {!! (int) $s['is_active'] === 1 ? t('vendor.menu.schedule_status_active') : t('vendor.menu.schedule_status_off') !!} | @partial('row-actions', ['actions' => [ ['label' => t_raw('common.edit'), 'icon' => 'fa-pen', 'primary' => true, 'attrs' => ['data-sched-edit' => '1', 'data-id' => (string) (int) $s['id'], 'data-name' => (string) $s['name'], 'data-mask' => (string) (int) $s['days_mask'], 'data-start' => substr((string) $s['start_time'], 0, 5), 'data-end' => substr((string) $s['end_time'], 0, 5), 'data-active' => (string) (int) $s['is_active'], 'data-bs-toggle' => 'modal', 'data-bs-target' => '#schedModal']], ['label' => t_raw('common.delete'), 'icon' => 'fa-trash-alt', 'danger' => true, 'form' => ['action' => '/vendor/menu/schedules/delete', 'fields' => ['id' => (int) $s['id']], 'confirm' => t_raw('vendor.menu.confirm_delete_schedule')]], ]]) |
{{ t_raw('vendor.menu.stations_sub') }}
@if ($unassignedDishes > 0) {{ t_raw('vendor.menu.stations_unassigned_count', [':n' => number_format($unassignedDishes)]) }} @else {{ t_raw('vendor.menu.stations_all_mapped') }} @endif
@endif| {{ t_raw('common.name') }} | {{ t_raw('vendor.menu.col_dishes') }} | {{ t_raw('common.sort_order') }} | {{ t_raw('common.status') }} | {{ t_raw('common.actions') }} |
|---|---|---|---|---|
| {{ $st['name'] }} | {{ number_format($sn) }} | {{ (int) $st['sort_order'] }} | {!! (int) $st['is_active'] === 1 ? t('vendor.menu.schedule_status_active') : t('vendor.menu.schedule_status_off') !!} | @partial('row-actions', ['actions' => [ ['label' => t_raw('common.edit'), 'icon' => 'fa-pen', 'primary' => true, 'attrs' => ['data-station-edit' => '1', 'data-id' => (string) (int) $st['id'], 'data-name' => (string) $st['name'], 'data-sort' => (string) (int) $st['sort_order'], 'data-active' => (string) (int) $st['is_active'], 'data-bs-toggle' => 'modal', 'data-bs-target' => '#stationModal']], ['label' => t_raw('common.delete'), 'icon' => 'fa-trash-alt', 'danger' => true, 'form' => ['action' => '/vendor/menu/stations/delete', 'fields' => ['id' => (int) $st['id']], 'confirm' => t_raw('vendor.menu.confirm_delete_station')]], ]]) |