@extends('layouts.dashboard') @section('content') @php use App\Models\Reservation; /** * Admin → Reservations → one booking. The operator's read-only view of a single reservation: * who it is for, when and where, the table and occasion, the guest's requests and the internal * staff note, plus the booking's status history. Built from the shared dashboard components * (.qm-od-topbar / .qm-card / .qm-ops-head / .qm-tbl-id / .qm-table / row g-3) — the same * language as the restaurant detail page, no new styles. Management (edit / status changes) * stays in the vendor panel; the only write offered here is the admin cancel already on the list. * * @var array $reservation the booking row (+ rest_*, cuisine_*, label_*, table_label, customer_*) * @var array $history status-history rows, newest first, each with its actor */ $r = $reservation; $status = (string) $r['status']; $srcKey = (string) ($r['source'] ?? 'staff'); $isCancellable = in_array($status, ['pending', 'confirmed', 'seated', 'waitlisted'], true); @endphp @php /* .qm-d2: the dashboard density standard (app.css §35) */ @endphp
@php /* Only Back lives in the page chrome. Everything you can DO to this booking moved into the header band with it, the way the restaurant page arranges them. */ @endphp
{{ t_raw('admin.reservationdetail.back') }}
@php /* Same header the restaurant and user detail pages wear: the venue's cover leads, the guest's mark straddles its lower edge, standing rides the cover, and the booking's facts sit below as one divided rail. */ @endphp
@php $resFlag = function_exists('cuisine_flag') ? cuisine_flag((string) ($r['cuisine_slug'] ?? '')) : null; @endphp @if ($resFlag){{ (string) ($r['cuisine_name'] ?? '') }}@endif
{{ Reservation::statusLabel($status) }} {{ Reservation::sourceLabel($srcKey) }} @if (!empty($r['label_name'])){{ $r['label_name'] }}@endif
{!! brandmark_html($r['avatar'] ?? null, (string) ($r['guest_name'] ?? t_raw('admin.reservations.fallback_guest_name')), 'lg', 'qm-brandmark--round') !!}

{{ $r['guest_name'] }}

@php /* The venue carries its own mark here, as it does in the list this page opens from - a cover photograph does not name a restaurant, and the reader arrives having just seen that mark in the row they clicked. Its flag is left off: the cover above already flies one. */ @endphp

{!! restaurant_logo_html(['logo' => $r['rest_logo'] ?? '', 'name' => $r['rest_name'] ?? '', 'cuisine_slug' => $r['cuisine_slug'] ?? ''], 'sm', 'qm-brandmark--round') !!} {{ trim((string) ($r['rest_name'] ?? '') . ' · ' . (string) ($r['cuisine_name'] ?? ''), ' ·') }}

@if (($r['rest_status'] ?? '') === 'approved' && !empty($r['rest_slug'])) {{ t_raw('admin.restaurants.aria_view_public') }} @endif @if ($isCancellable)
@csrf
@endif
@php /* Every fact the old grid carried, in one rail: the booking itself first, then - past the heavier rule - who it is for. The optional two (deposit, customer account) hold their cells and show a dash, so the rail keeps one shape whatever a given booking happens to have. */ @endphp
{{ t_raw('admin.reservations.col_when') }}
{!! fmt_datetime($r['reserved_at']) !!} {{ t_raw('admin.reservationdetail.duration', [':n' => (int) $r['duration_minutes']]) }}
{{ t_raw('admin.reservations.col_party') }}
{{ (int) $r['party_size'] }}
{{ t_raw('admin.reservations.col_table') }}
{!! or_dash($r['table_label'] ?? null) !!}
{{ t_raw('admin.reservationdetail.deposit') }}
{!! !empty($r['deposit_amount']) ? money($r['deposit_amount']) : dash() !!}
{{ t_raw('common.phone') }}
{!! or_dash($r['guest_phone'] ?? null) !!}
{{ t_raw('common.email') }}
{!! or_dash($r['guest_email'] ?? null) !!}
{{ t_raw('admin.reservationdetail.customer_account') }}
@if (!empty($r['customer_account_id'])) {{ (string) ($r['customer_account_name'] ?? '') }} @else{!! dash() !!}@endif
@php /* The rail closes on the click-through an operator actually wants from a booking: the venue it was made at. */ @endphp
@if (!empty($r['special_requests']) || !empty($r['staff_notes']))

{{ t_raw('admin.reservationdetail.sec_notes') }}

@if (!empty($r['special_requests']))
{{ t_raw('admin.reservationdetail.special_requests') }}
{{ $r['special_requests'] }}
@endif @if (!empty($r['staff_notes']))
{{ t_raw('admin.reservationdetail.staff_notes') }}
{{ $r['staff_notes'] }}
@endif
@endif

{{ t_raw('admin.reservationdetail.sec_history') }}

@php /* The booking's own audit trail — status transitions and lifecycle events, newest first. */ @endphp
@if ($history) @foreach ($history as $h) @endforeach @else @partial('table-empty', ['colspan' => 4, 'icon' => 'fa-history', 'msg' => t('admin.reservationdetail.no_history')]) @endif
{{ t_raw('admin.reservationdetail.col_change') }}{{ t_raw('admin.restaurantdetail.col_by') }}{{ t_raw('common.description') }}{{ t_raw('common.when') }}
@if (!empty($h['from_status']) && !empty($h['to_status']) && (string) $h['from_status'] !== (string) $h['to_status']) {{ Reservation::statusLabel((string) $h['from_status']) }} {{ Reservation::statusLabel((string) $h['to_status']) }} @else {{ activity_label((string) $h['action']) }} @endif @if (!empty($h['actor_name']))
{!! brandmark_html($h['actor_avatar'] ?? null, (string) $h['actor_name'], 'sm', 'qm-brandmark--round') !!}
{{ $h['actor_name'] }}
@else{{ t_raw('admin.reservationdetail.by_system') }}@endif
{!! or_dash(history_detail($h['detail'] ?? null) ?: null) !!}
{{ time_ago($h['created_at']) }}
@php /* /.qm-d2 */ @endphp @endsection