@extends('layouts.dashboard') @section('content') @php /** * Vendor → Staff analytics → one member, for the selected reporting window. * Role-aware metrics plus an activity trend, an hour-of-day work pattern, the * money this member settled at the till and a recent-activity log — all drawn * from the real audit trails and payment ledger (StaffController::memberAnalytics()). * * @var array $member id, name, role, email, status * @var array $stats the member's metric block for the window (may be all-zero) * @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 $trendChart @var array $trendMeta actions per day * @var array $hoursChart @var array $hoursMeta hour-of-day work pattern * @var array $salesChart @var array $salesMeta money settled per day * @var array $kpiSparks per-metric daily series for the KPI mini trends * @var array $recent merged recent actions [{kind,ref,status,detail?,at}] */ $role = (string) $member['role']; $status = (string) $member['status']; $rmeta = $roles[$role] ?? ['label' => role_label($role)]; $g = static fn (string $k): int => (int) ($stats[$k] ?? 0); $m = static fn (string $k): float => (float) ($stats[$k] ?? 0); $lastAt = $stats['last_at'] ?? null; $kpiSparks = $kpiSparks ?? []; $showMoney = $showMoney ?? true; // KPI cards chosen by what this member's role can actually DO, so each page leads with the // work they own — and a role composed on the admin Roles screen lands on the right set // without a branch being written for it. A role that runs the whole floor (it can read the // order list) gets the general set; a narrow one gets the cards for its speciality. // Each tuple: [label, value, accent, FA5 glyph, sparkKey, "View all" href|''] for the // shared kpi-card 'panel' variant. sparkKey selects this member's daily series from // $kpiSparks (built in StaffController::memberAnalytics from the audit trails). $rolePerms = \App\Models\Role::permissionsFor($role); $holds = static fn (string $perm): bool => in_array($perm, $rolePerms, true); $isWide = $holds('orders.view'); $ordersUrl = route('vendor.orders'); $kitchenUrl = route('vendor.kitchen'); $resvUrl = route('vendor.reservations'); if ($role === 'driver') { // A rider's work is the last leg, not the kitchen: the order-confirmation and // preparation counters a manager is judged on are always zero for them, so the // card set follows the run itself — picked up, delivered, and the bills they // collected on the doorstep. $kpis = [ [t_raw('vendor.staff.kpi_marked_ready'), $g('ready'), 'blue', 'fa-box', 'ready', $ordersUrl], [t_raw('vendor.staff.kpi_delivered'), $g('delivered'), 'green', 'fa-check-circle', 'delivered', $ordersUrl], [t_raw('vendor.staff.kpi_orders_handled'), $g('orders_touched'), 'violet', 'fa-receipt', 'total_actions', $ordersUrl], [t_raw('vendor.staff.kpi_actions_logged'), $g('total_actions'), 'slate', 'fa-chart-line', 'total_actions', ''], ]; } elseif (!$isWide && $holds('kitchen.advance')) { $kpis = [ [t_raw('vendor.staff.kpi_orders_prepared'), $g('prepared'), 'blue', 'fa-receipt', 'prepared', $kitchenUrl], [t_raw('vendor.staff.kpi_items_prepared'), $g('items'), 'amber', 'fa-utensils', 'items', $kitchenUrl], [t_raw('vendor.staff.kpi_marked_ready'), $g('ready'), 'green', 'fa-box', 'ready', $ordersUrl], [t_raw('vendor.staff.kpi_actions_logged'), $g('total_actions'), 'slate', 'fa-chart-line', 'total_actions', ''], ]; } elseif (!$isWide && $holds('reservations.manage')) { $kpis = [ [t_raw('vendor.staff.kpi_reservations'), $g('reservations'), 'violet', 'fa-calendar-check', 'reservations', $resvUrl], [t_raw('vendor.staff.col_tables_seated'), $g('seated'), 'teal', 'fa-chair', 'seated', $resvUrl], [t_raw('vendor.staff.kpi_guests_seated'), $g('guests'), 'green', 'fa-users', 'guests', $resvUrl], [t_raw('vendor.staff.kpi_completed'), $g('completed'), 'blue', 'fa-check-circle', 'completed', $resvUrl], ]; } else { // the owner, and anyone who runs the floor end to end $kpis = [ [t_raw('vendor.staff.kpi_orders_confirmed'), $g('confirmed'), 'blue', 'fa-check-circle', 'confirmed', $ordersUrl], [t_raw('vendor.staff.kpi_orders_prepared'), $g('prepared'), 'amber', 'fa-utensils', 'prepared', $kitchenUrl], [t_raw('vendor.staff.kpi_cancellations'), $g('cancelled'), 'rose', 'fa-ban', 'cancelled', $ordersUrl], [t_raw('vendor.staff.kpi_actions_logged'), $g('total_actions'), 'slate', 'fa-chart-line', 'total_actions', ''], ]; } // Recent-activity presentation: order status -> verb/icon; reservations use their detail line. $orderVerb = [ 'pending' => [t_raw('vendor.staff.verb_logged_new_order'), 'fa-receipt'], 'confirmed' => [t_raw('vendor.staff.verb_accepted_order'), 'fa-check'], 'preparing' => [t_raw('vendor.staff.verb_started_preparing'), 'fa-fire'], 'out_for_delivery' => [t_raw('vendor.staff.kpi_marked_ready'), 'fa-box'], 'delivered' => [t_raw('vendor.staff.verb_completed_order'), 'fa-check-circle'], 'cancelled' => [t_raw('vendor.staff.verb_cancelled_order'), 'fa-times-circle'], ]; // A member who logged no workflow actions may still have settled bills (a cashier // on the till all shift), so the empty state has to consider both. $hasWork = $g('total_actions') > 0 || $g('orders_paid') > 0; @endphp @php /* .qm-d2: the dashboard density standard (app.css §35) */ @endphp
{{ t_raw('vendor.staff.no_activity_in_window') }}
{{ t_raw('vendor.staff.empty_no_recent_actions') }}