@extends('layouts.dashboard') @section('content') @php /** * Vendor CRM → Customers: everyone who has ordered from this restaurant, as a * searchable, segmented, sortable, paginated list. Each name links to that customer's * per-restaurant detail page. Built from the shared list components * (.qm-kpi-grid / .qm-order-filters / .qm-table / .qm-tbl-id / pagination) — no bespoke markup. * * Column order carries a judgement, so it is deliberate: how often someone orders and * what they spend decide who matters to the business, and how long they have been quiet * decides who needs attention. Ratings are the last column because a five-star review * from a one-time visitor should never outrank a regular who has never written one. * * @var array $customers the current page of customer rows * @var string $q active search term * @var string $sort active sort key (whitelisted in the controller) * @var string $segment active segment filter (blank = everyone) * @var array $counts per-segment customer counts + total spend * @var float|null $repeatRate share of customers who have ordered more than once * @var int $total total customers matching the search + segment * @var array $pagination paginate() metadata * @var array|null $restaurant */ $loyLabel = (string) ($restaurant['loyalty_points_label'] ?? 'points'); $sortOpts = [ 'spend' => t_raw('vendor.customers.sort_spend'), 'orders' => t_raw('vendor.customers.sort_orders'), 'recent' => t_raw('vendor.customers.sort_recent'), 'lapsed' => t_raw('vendor.customers.sort_lapsed'), 'name' => t_raw('vendor.customers.sort_name'), ]; $counts = $counts ?? ['all' => 0, 'new' => 0, 'active' => 0, 'at_risk' => 0, 'repeat' => 0, 'spend' => 0.0]; $segment = $segment ?? ''; $segOpts = [ '' => t_raw('vendor.customers.seg_all', [':n' => number_format((int) $counts['all'])]), 'active' => t_raw('vendor.customers.seg_active', [':n' => number_format((int) $counts['active'])]), 'at_risk' => t_raw('vendor.customers.seg_at_risk', [':n' => number_format((int) $counts['at_risk'])]), 'new' => t_raw('vendor.customers.seg_new', [':n' => number_format((int) $counts['new'])]), ]; $repeatRate = $repeatRate ?? null; $hasFilters = $q !== '' || $segment !== ''; // A manager runs the relationships, not the takings — same boundary as Kiosks and Orders. $showMoney = $showMoney ?? true; // Carry the active search / segment / sort onto the export link. $qs = http_build_query(array_filter([ 'segment' => $segment, 'sort' => $sort, 'q' => $q, ], static fn ($v) => (string) $v !== '')); @endphp @php /* .qm-d2: the dashboard density standard (app.css §35) */ @endphp
| {{ t_raw('common.customer') }} | {{ t_raw('common.orders') }} | @if ($showMoney){{ t_raw('admin.analytics_customers.col_spend') }} | @endif @if ($showMoney){{ t_raw('vendor.customers.col_balance') }} | @endif{{ t_raw('vendor.customers.col_recency') }} | {{ t_raw('vendor.analytics.col_loyalty_balance') }} | {{ t_raw('vendor.customers.col_reviews') }} |
|---|---|---|---|---|---|---|
|
{!! brandmark_html($c['avatar'] ?? null, (string) $c['name'], 'md', 'qm-brandmark--round') !!}
{{ $c['name'] }}
@if (!empty($c['email'])){{ $c['email'] }}@endif
@if (!empty($c['phone'])){{ $c['phone'] }}@endif
@if (empty($c['email']) && empty($c['phone'])){!! or_dash(null) !!}@endif
@if ($isAtRisk)
{{ t_raw('vendor.customers.pill_at_risk') }}
@elseif ($isNew)
{{ t_raw('vendor.customers.pill_new') }}
@endif
|
{{ number_format($oc) }} | @if ($showMoney){{ money($c['spend']) }} | @endif @if ($showMoney) @php $wn = $c['wallet_net'] !== null ? (float) $c['wallet_net'] : 0.0; @endphp@if ($wn > 0.005){{ money($wn) }} @elseif ($wn < -0.005){{ money(abs($wn)) }} @else{!! dash() !!}@endif | @endif @php /* Recency is the number an operator acts on, so it leads the cell and the calendar date follows it as the supporting detail. */ @endphp
@if ($days === null){!! dash() !!}
@else
{!! $days === 0 ? t('vendor.customers.recency_today') : t('vendor.customers.recency_days_ago', [':n' => number_format($days)]) !!}
{!! fmt_day($c['last_order']) !!}
@endif
|
{!! $c['points'] !== null ? number_format((int) $c['points']) . ' ' . e($loyLabel) : dash() !!} | @if ($rc > 0) {!! rating_stars_html((float) $c['review_avg']) !!} {{ t_raw('vendor.customers.review_count', [':count' => $rc]) }} @else {{ t_raw('vendor.customers.no_review') }} @endif |