@extends('layouts.dashboard')
@section('content')
@php
/**
* Vendor → Staff analytics (bird's-eye view) for one reporting window. Shows, per
* staff member, the real work recorded in the order + reservation audit trails and
* the money they settled at the till: orders pushed through the kitchen, items
* prepared, reservations handled, tables seated, sales taken, tips and average
* check. Every number is computed in StaffController::activityMetrics().
*
* @var array $staff the current pager window of members, each with a ['stats'] block (owner first)
* @var array $pager paginate() metadata for the leaderboard
* @var array $totals staff roll-up: members/orders/items/reservations/seated/guests/sales/tips/avg_check
* @var array $roles role => ['label'] (context label; colour via role_pill_class())
* @var array $rangeLinks ['options' => [days => label], 'selected' => string]
* @var int $rangeDays the selected window, in days
* @var bool $showMoney false for a manager: takings stay with the owner
* @var array $workChart @var array $workMeta team activity per day
* @var array $moneyChart @var array $moneyMeta sales taken (or items prepared) per day
* @var array $ordersByMemberChart @var array $ordersByMemberMeta
* @var array $rankChart @var array $rankMeta sales (or items) per member
* @var array $hoursChart @var array $hoursMeta hour-of-day work pattern
* @var array $kpiSparks per-metric daily series for the KPI mini trends
* @var bool $hasActivity true when anyone logged work in the window
*/
$roleOf = static fn (string $r): array => $roles[$r] ?? ['label' => role_label($r)];
$kpiSparks = $kpiSparks ?? [];
$showMoney = $showMoney ?? true;
@endphp
@php /* .qm-d2: the dashboard density standard (app.css §35) */
@endphp
{{ t_raw('dashboard.sec.snapshot') }}
{{ t_raw('vendor.staff.subtitle_analytics') }}
@if (!$hasActivity)
{{ t_raw('vendor.staff.empty_title_no_activity') }}
{{ t_raw('vendor.staff.empty_text_in_window') }}
@else
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'teal', 'icon' => 'fa-users', 'label' => t_raw('vendor.staff.kpi_staff_members'), 'value' => number_format((int) $totals['members']), 'href' => route('vendor.staff'),
'meta' => '' . t('vendor.staff.meta_owner_staff') . ''])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'blue', 'icon' => 'fa-receipt', 'label' => t_raw('vendor.staff.kpi_orders_handled'), 'value' => number_format((int) $totals['orders']), 'href' => route('vendor.orders'), 'spark' => $kpiSparks['orders'] ?? [],
'meta' => '' . t('vendor.staff.meta_progressed_in_window', [':days' => (int) $rangeDays]) . ''])
@if ($showMoney)
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'green', 'icon' => 'fa-cash-register', 'label' => t_raw('vendor.staff.kpi_sales_taken'), 'value' => money($totals['sales']), 'spark' => $kpiSparks['sales'] ?? [],
'meta' => '' . t('vendor.staff.meta_settled_at_till') . ''])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'pink', 'icon' => 'fa-hand-holding-usd', 'label' => t_raw('vendor.staff.kpi_tips'), 'value' => money($totals['tips']),
'meta' => '' . t('vendor.staff.meta_tips_on_settled') . ''])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'slate', 'icon' => 'fa-balance-scale', 'label' => t_raw('vendor.staff.kpi_avg_check'),
'value' => (int) $totals['orders_paid'] > 0 ? money($totals['avg_check']) : '—',
'meta' => '' . t('vendor.staff.meta_across_n_bills', [':n' => number_format((int) $totals['orders_paid'])]) . ''])
@endif
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'amber', 'icon' => 'fa-utensils', 'label' => t_raw('vendor.staff.kpi_items_prepared'), 'value' => number_format((int) $totals['items']), 'href' => route('vendor.kitchen'), 'spark' => $kpiSparks['items'] ?? [],
'meta' => '' . t('vendor.staff.meta_through_kitchen') . ''])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'violet', 'icon' => 'fa-calendar-check', 'label' => t_raw('vendor.staff.kpi_reservations'), 'value' => number_format((int) $totals['reservations']), 'href' => route('vendor.reservations'), 'spark' => $kpiSparks['reservations'] ?? [],
'meta' => '' . t('vendor.staff.meta_bookings_managed') . ''])
@partial('kpi-card', ['variant' => 'panel', 'accent' => 'orange', 'icon' => 'fa-chair', 'label' => t_raw('vendor.staff.kpi_guests_seated'), 'value' => number_format((int) $totals['guests']), 'href' => route('vendor.reservations'), 'spark' => $kpiSparks['guests'] ?? [],
'meta' => '' . t('vendor.staff.meta_covers_seated') . ''])
@php /* Trends: what the team did day by day, beside the money (or, for a manager, the volume)
it produced. Each card's caption and its accessible summary are the same sentence, so the
two can never drift apart. */
@endphp
@partial('chart-card', ['heading' => t_raw('vendor.staff.chart_team_activity'), 'sub' => t_raw('vendor.staff.sub_team_activity'),
'cfg' => $workChart, 'meta' => $workMeta, 'accent' => 'blue', 'icon' => 'fa-chart-line'])
@partial('chart-card', [
'heading' => $showMoney ? t_raw('vendor.staff.chart_sales_taken') : t_raw('vendor.staff.kpi_items_prepared'),
'sub' => t_raw('vendor.staff.sub_sales_taken'),
'cfg' => $moneyChart, 'meta' => $moneyMeta, 'accent' => $showMoney ? 'green' : 'amber',
'icon' => $showMoney ? 'fa-cash-register' : 'fa-utensils'])
@php /* Breakdown: who carried the load, who took the money, and when the floor is busiest. */
@endphp
@partial('chart-card', ['heading' => t_raw('vendor.staff.chart_orders_by_member'), 'sub' => t_raw('vendor.staff.sub_orders_by_member'),
'cfg' => $ordersByMemberChart, 'meta' => $ordersByMemberMeta, 'accent' => 'blue', 'icon' => 'fa-chart-bar'])
@partial('chart-card', [
'heading' => $showMoney ? t_raw('vendor.staff.chart_sales_by_member') : t_raw('vendor.staff.chart_items_by_member'),
'sub' => t_raw('vendor.staff.sub_rank_by_member'),
'cfg' => $rankChart, 'meta' => $rankMeta, 'accent' => $showMoney ? 'green' : 'amber', 'icon' => 'fa-chart-bar'])
@partial('chart-card', ['heading' => t_raw('vendor.staff.chart_hours_pattern'), 'sub' => t_raw('vendor.staff.sub_hours_pattern'),
'cfg' => $hoursChart, 'meta' => $hoursMeta, 'accent' => 'violet', 'icon' => 'fa-clock'])
{{ t_raw('vendor.staff.heading_leaderboard') }}
{{ t_raw('vendor.staff.leaderboard_sub_window', [':days' => (int) $rangeDays]) }}
@php /* Last active renders a relative phrase ("3 days ago"), which Date.parse() cannot
read, so that cell carries the raw timestamp in data-sort-value instead. */
@endphp
{{ t_raw('vendor.staff.caption_leaderboard') }}
| {{ t_raw('vendor.staff.col_member') }} |
{{ t_raw('common.orders') }} |
@if ($showMoney)
{{ t_raw('vendor.staff.kpi_sales_taken') }} |
{{ t_raw('vendor.staff.kpi_tips') }} |
{{ t_raw('vendor.staff.kpi_avg_check') }} |
@endif
{{ t_raw('vendor.staff.col_items_prepd') }} |
{{ t_raw('vendor.staff.kpi_reservations') }} |
{{ t_raw('vendor.staff.col_tables_seated') }} |
{{ t_raw('vendor.staff.col_guests') }} |
{{ t_raw('vendor.staff.col_last_active') }} |
@foreach ($staff as $mem)
@php $s = $mem['stats']; $r = $roleOf((string) $mem['role']); @endphp
|
{!! brandmark_html($mem['avatar'] ?? null, (string) $mem['name'], 'md', 'qm-brandmark--round') !!}
{{ $mem['name'] }}
{{ $r['label'] }}
|
{!! (int) $s['orders_touched'] > 0 ? number_format((int) $s['orders_touched']) : dash() !!} |
@if ($showMoney)
{!! (float) $s['sales'] != 0.0 ? money($s['sales']) : dash() !!} |
{!! (float) $s['tips'] != 0.0 ? money($s['tips']) : dash() !!} |
{!! (int) $s['orders_paid'] > 0 ? money($s['avg_check']) : dash() !!} |
@endif
{!! (int) $s['items'] > 0 ? number_format((int) $s['items']) : dash() !!} |
{!! (int) $s['reservations'] > 0 ? number_format((int) $s['reservations']) : dash() !!} |
{!! (int) $s['seated'] > 0 ? number_format((int) $s['seated']) : dash() !!} |
{!! (int) $s['guests'] > 0 ? number_format((int) $s['guests']) : dash() !!} |
{!! $s['last_at'] ? e(time_ago((string) $s['last_at'])) : dash() !!} |
@endforeach
@partial('table-toolbar', ['pager' => $pager, 'base' => '/vendor/staff/analytics'])
@endif
@php /* /.qm-d2 */
@endphp
@endsection