@extends('layouts.dashboard') @section('content') @php /** * Operation Analytics → Reservations: the front-of-house report. No-shows as a * rate rather than a count, how far ahead guests commit, how long a table stays * occupied, where the bookings come from and when the covers land. * * @var array $kpis @var array $paceChart @var array $paceMeta @var array $statusChart @var array $statusMeta * @var array $sourceChart @var array $sourceMeta @var array $partyChart @var array $partyMeta * @var array $turnChart @var array $turnMeta @var array $heatChart @var array $heatMeta * @var array $rows @var array $pager @var int $rangeDays @var array $rangeLinks @var bool $showMoney */ // The booking pills reuse the same status colours the Reservations desk uses, so a // row reads identically whichever page the manager is standing on. $statusTone = [ 'pending' => 'amber', 'confirmed' => 'blue', 'seated' => 'green', 'completed' => 'green', 'cancelled' => 'grey', 'no_show' => 'red', 'waitlisted' => 'amber', ]; $cols = 9 + ($showMoney ? 1 : 0); @endphp @php /* .qm-d2: the dashboard density standard (app.css §35) */ @endphp

{{ t_raw('dashboard.sec.snapshot') }}

{{ t_raw('vendor.analytics.subtitle_reservations') }}

@foreach ($rangeLinks['options'] as $val => $text) @php $on = ((string) $val === $rangeLinks['selected']); @endphp {{ $text }} @endforeach
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'blue', 'icon' => 'fa-calendar-check', 'label' => t_raw('nav.reservations'), 'value' => number_format($kpis['bookings']['value']), 'spark' => $kpis['bookings']['spark'], 'meta' => $kpis['bookings']['meta']]) @php /* Reported as a RATE: ten no-shows out of twelve bookings and ten out of four hundred are the same count and completely different problems. */ @endphp @partial('kpi-card', ['variant' => 'panel', 'accent' => 'rose', 'icon' => 'fa-user-slash', 'label' => t_raw('vendor.analytics.kpi_no_show_rate'), 'value' => $kpis['noShow']['value'] !== null ? number_format($kpis['noShow']['value'], 1) . '%' : '—', 'spark' => $kpis['noShow']['spark'], 'meta' => $kpis['noShow']['meta']]) @partial('kpi-card', ['variant' => 'panel', 'accent' => 'green', 'icon' => 'fa-chair', 'label' => t_raw('vendor.analytics.kpi_seated_rate'), 'value' => $kpis['seated']['value'] !== null ? number_format($kpis['seated']['value'], 1) . '%' : '—', 'spark' => $kpis['seated']['spark'], 'meta' => $kpis['seated']['meta']]) @partial('kpi-card', ['variant' => 'panel', 'accent' => 'violet', 'icon' => 'fa-hourglass-start', 'label' => t_raw('vendor.analytics.kpi_lead_time'), 'value' => $kpis['lead']['value'] ?? '—', 'spark' => $kpis['lead']['spark'], 'meta' => $kpis['lead']['meta']]) @partial('kpi-card', ['variant' => 'panel', 'accent' => 'teal', 'icon' => 'fa-stopwatch', 'label' => t_raw('vendor.analytics.kpi_turn_time'), 'value' => $kpis['turn']['value'] ?? '—', 'spark' => $kpis['turn']['spark'], 'meta' => $kpis['turn']['meta']]) @partial('kpi-card', ['variant' => 'panel', 'accent' => 'amber', 'icon' => 'fa-user-friends', 'label' => t_raw('vendor.analytics.kpi_covers'), 'value' => number_format($kpis['covers']['value']), 'spark' => $kpis['covers']['spark'], 'meta' => $kpis['covers']['meta']])

{{ t_raw('dashboard.sec.trends') }}

@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_booking_pace'), 'sub' => t_raw('vendor.analytics.chart_booking_pace_sub'), 'cfg' => $paceChart, 'meta' => $paceMeta, 'accent' => 'blue', 'opts' => ['id' => 'resvPaceChart', 'url' => route('vendor.chart-series', ['chart' => 'resvPace']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_booking_status'), 'sub' => t_raw('vendor.analytics.chart_booking_status_sub'), 'cfg' => $statusChart, 'meta' => $statusMeta, 'icon' => 'fa-chart-pie', 'accent' => 'rose'])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_booking_channels'), 'sub' => t_raw('vendor.analytics.chart_booking_channels_sub'), 'cfg' => $sourceChart, 'meta' => $sourceMeta, 'icon' => 'fa-chart-pie', 'accent' => 'violet'])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_party_sizes'), 'sub' => t_raw('vendor.analytics.chart_party_sizes_sub'), 'cfg' => $partyChart, 'meta' => $partyMeta, 'icon' => 'fa-chart-bar', 'accent' => 'amber', 'opts' => ['id' => 'resvPartyChart', 'url' => route('vendor.chart-series', ['chart' => 'resvParty']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_turn_time'), 'sub' => t_raw('vendor.analytics.chart_turn_time_sub'), 'cfg' => $turnChart, 'meta' => $turnMeta, 'icon' => 'fa-stopwatch', 'accent' => 'teal', 'opts' => ['id' => 'resvTurnChart', 'url' => route('vendor.chart-series', ['chart' => 'resvTurn']), 'selected' => $rangeLinks['selected'], 'options' => $rangeLinks['options'], 'control' => 'compact']])
@partial('chart-card', ['heading' => t_raw('vendor.analytics.chart_seating_clock'), 'sub' => t_raw('vendor.analytics.chart_seating_clock_sub'), 'cfg' => $heatChart, 'meta' => $heatMeta, 'icon' => 'fa-th', 'accent' => 'teal'])

{{ t_raw('dashboard.sec.breakdown') }}

{{ t_raw('vendor.analytics.heading_bookings') }}

{{ t_raw('vendor.analytics.hint_bookings') }}

@if ($showMoney)@endif @if ($rows) @foreach ($rows as $r) @php $st = (string) $r['status']; @endphp @php /* Lead and turn time exist only once the guest actually sat down and left; an unfinished booking reports nothing, never a zero. */ @endphp @if ($showMoney) @endif @endforeach @else @partial('table-empty', ['colspan' => $cols, 'icon' => 'fa-calendar-check', 'msg' => t_raw('vendor.analytics.empty_no_bookings')]) @endif
{{ t_raw('vendor.analytics.caption_bookings') }}
{{ t_raw('vendor.analytics.col_guest') }} {{ t_raw('vendor.analytics.kpi_covers') }} {{ t_raw('vendor.analytics.col_booked_on') }} {{ t_raw('vendor.analytics.col_sitting') }} {{ t_raw('vendor.analytics.col_lead_time') }} {{ t_raw('vendor.analytics.col_seated') }} {{ t_raw('vendor.analytics.col_turn_time') }} {{ t_raw('common.status') }} {{ t_raw('vendor.analytics.col_channel') }}{{ t_raw('vendor.analytics.col_deposit') }}
{!! brandmark_html($r['avatar'] ?? null, (string) $r['guest_name'], 'md', 'qm-brandmark--round') !!}
{{ (string) $r['guest_name'] }} {!! or_dash($r['guest_phone']) !!}
{{ number_format((int) $r['party_size']) }} {!! fmt_day($r['created_at']) !!} {!! fmt_datetime($r['reserved_at']) !!}{!! or_dash($r['lead_label']) !!} {!! $r['seated_at'] !== null ? fmt_clock($r['seated_at']) : dash() !!} {!! or_dash($r['turn_label']) !!} {{ status_label('reservation', $st) }} {{ status_label('reservation_source', (string) $r['source']) }}{!! $r['deposit_amount'] !== null ? money($r['deposit_amount']) : dash() !!}
@partial('table-toolbar', ['pager' => $pager, 'base' => '/vendor/analytics/reservations'])
@php /* /.qm-d2 */ @endphp @endsection