@extends('layouts.public') @section('content') @php /** @var array $items @var array $restaurant @var array $totals @var array $zones @var array|null $user * @var bool $tipsEnabled @var bool $schedulingEnabled */ // Dine-in: offered only when the cart is bound to a scanned table AND the restaurant // allows QR ordering. When present it is the first option and pre-selected, so delivery // is NOT checked by default. Resolved here rather than beside the radios because the // step rail below names step 2 after the same choice. $dineIn = $dineIn ?? false; $tableLabel = (string) ($tableLabel ?? ''); /* --------------------------------------------------------------------------- Three-step checkout. The fieldsets below are the ones this page has always had; they are only GROUPED into three panes. The form still posts ONCE, to the same action, so there is no new route and no per-step save that can half-succeed. Nothing is hidden server-side: every pane renders, and only checkout.js — once it has run — collapses them to one at a time. That is what makes the page work with JavaScript disabled: three panes stacked, one submit, order completes. Step names reuse the headings the sections already carry, so the rail and the fieldset it points at are never worded differently. --------------------------------------------------------------------------- */ $coSteps = [ 1 => t('checkout.contact'), 2 => $dineIn ? t('checkout.order_type') : t('checkout.delivery_method'), 3 => t('checkout.payment_method'), ]; // Which pane a rejected submit re-opens. CheckoutController::checkoutFail puts the field // the server refused into the same flashed-input bag old() reads, so this needs no new // mechanism and expires with the rest of that input. An error naming no field (the // restaurant is closed, the cart went stale) opens the first pane, where the flash // banner above the form is already in view. $coErrorPane = [ 'customer_name' => 1, 'customer_phone' => 1, 'customer_email' => 1, 'service_mode' => 2, 'delivery_address' => 2, 'zone_id' => 2, 'scheduled_at' => 2, 'payment_method' => 3, 'tip' => 3, 'coupon' => 3, 'loyalty_reward_id' => 3, 'notes' => 3, ][(string) \App\Support\Session::old('_error_field', '')] ?? 1; /* Choices a rejected submit must not make the customer enter twice. old() already restores every text field on this page; these are the radios and selects it cannot reach. Each falls back to exactly the default it had before, so a first visit — where the flashed bag is empty — renders identically to how it always did. */ $coOld = static fn (string $k): string => (string) \App\Support\Session::old($k, ''); $coOldPay = $coOld('payment_method'); $coOldReward = $coOld('loyalty_reward_id'); $coMode = $coOld('service_mode') !== '' ? $coOld('service_mode') : ($dineIn ? 'dine_in' : 'delivery'); $coLater = $coOld('when') === 'later'; // The first enabled payment method stays pre-selected until the customer has actually // chosen one; after a rejected submit their choice wins. $coPayChecked = static fn (string $value, bool $isFirst): string => ($coOldPay !== '' ? $coOldPay === $value : $isFirst) ? ' checked' : ''; @endphp