@extends('layouts.dashboard') @section('content') @php use App\Models\Order; /** * Admin → Users → one account. A read-only drill-down whose lower panel adapts * to the user's role. Built entirely from shared dashboard components * (.qm-card / kpi-card / .qm-table / role_pill) — no bespoke markup. * * @var array $user the account row (password/PIN hashes already stripped by the controller) * @var array $panel role-scoped data assembled in UserController::show() * @var bool $pinSet whether this account carries a screen-lock PIN * @var array $activity the platform audit trail for what THIS account did * @var array $statusHistory what admins have done TO this account, and who did it * @var array $activityPager pager for the audit trail * @var array $historyPager pager for the account history * * Every table here is a page of its own set, not a fixed excerpt: each carries its own * pager key so resizing or paging one panel leaves the others exactly where they were. */ $role = (string) $user['role']; $status = (string) $user['status']; $statusPill = ['active' => 'qm-pill-green', 'pending' => 'qm-pill-amber', 'suspended' => 'qm-pill-red'][$status] ?? 'qm-pill-grey'; $payPill = ['paid' => 'qm-pill-green', 'unpaid' => 'qm-pill-grey', 'refunded' => 'qm-pill-red']; $pinSet = $pinSet ?? false; $activity = $activity ?? []; $statusHistory = $statusHistory ?? []; $activityPager = $activityPager ?? []; $historyPager = $historyPager ?? []; // The roles that belong to one restaurant, read from the roles table so a role created // on the Roles screen behaves like a shipped one on this page too. The driver is a staff // role now, so staffSlugs() already covers it (was staff + driver via teamSlugs). $staffRoles = \App\Models\Role::staffSlugs(); $isSelf = (int) $user['id'] === (int) \App\Support\Auth::id(); @endphp @php /* .qm-d2: the dashboard density standard (app.css §35) */ @endphp
{{ t_raw('admin.userdetail.back') }}
@php /* The account's identity wears the same hero the restaurant profile wears: brand-wash band (avatar, name, pills — support levers on the right) over the facts as one measured stat band. */ @endphp @php /* Same detail-header language as the restaurant page: divided fact rail closing on a solid call to action. Users carry no cover image. */ @endphp
{!! brandmark_html($user['avatar'] ?? null, (string) $user['name'], 'lg', 'qm-brandmark--round') !!}

{{ $user['name'] }}

{!! role_pill($role) !!} {{ status_label('user', $status) }}
@php /* Support levers. Suspend/activate gates the account; the other two are the recovery actions a support agent reaches for without touching the password: end every session the account holds, and clear a forgotten screen-lock PIN. */ @endphp
@php // Support impersonation. Offered only for accounts that can actually be // adopted: never another super admin, never yourself, never a suspended // account (Auth::impersonate() refuses all three server-side too). @endphp @if (!$isSelf && in_array($role, $staffRoles, true) && $pinSet)
@csrf
@endif @if (!$isSelf)
@csrf
@endif @if ($role !== 'super_admin' && !$isSelf)
@csrf
@endif
{{ t_raw('common.email') }}
{{ $user['email'] }}
{{ t_raw('common.phone') }}
{!! or_dash($user['phone'] ?? null) !!}
{{ t_raw('admin.userdetail.member_since') }}
{!! fmt_day($user['created_at']) !!}
{{ t_raw('admin.userdetail.last_updated') }}
{!! fmt_day($user['updated_at']) !!}
@php /* The one thing an admin comes here to DO closes the rail, exactly as "Open vendor dashboard" closes the restaurant header's. */ @endphp @if (!$isSelf && $role !== 'super_admin' && $status === 'active')
@csrf
@endif
@php // -------- Role-specific panel -------- $renderRestaurantCard = static function (?array $rest): string { if (!$rest) { return '

' . t('admin.userdetail.no_restaurant') . '

'; } $statusMap = ['approved' => 'qm-pill-green', 'pending' => 'qm-pill-amber', 'suspended' => 'qm-pill-red']; ob_start(); @endphp

{{ t_raw('admin.userdetail.restaurant') }}

{!! restaurant_logo_html($rest, 'md', 'qm-brandmark--round') !!}
{{ $rest['name'] }} @if (!empty($rest['city'])){{ $rest['city'] }}@endif
{{ status_label('restaurant', (string) $rest['status']) }} {{ t_raw('admin.userdetail.view_restaurant') }}
@php return (string) ob_get_clean(); }; @endphp @if ($role === 'vendor')
@partial('kpi-card', ['accent' => 'blue', 'icon' => 'fa-receipt', 'label' => t_raw('admin.userdetail.kpi_orders'), 'value' => number_format((int) ($panel['orders_c'] ?? 0))]) @partial('kpi-card', ['accent' => 'green', 'icon' => 'fa-money-bill-wave', 'label' => t_raw('admin.userdetail.kpi_revenue'), 'value' => money($panel['collected'] ?? 0)])
{!! $renderRestaurantCard($panel['restaurant'] ?? null) !!}
@php // Floor staff (driver excluded — its richer delivery panel is the `driver` branch below, // which isStaff() would otherwise shadow now that the rider is a staff role). @endphp @elseif (\App\Models\Role::worksVendorDashboard($role))
{{ t_raw('admin.userdetail.access_pin') }}
{!! !empty($panel['pin_set']) ? t('admin.userdetail.pin_set') : t('admin.userdetail.pin_unset') !!}
{!! $renderRestaurantCard($panel['restaurant'] ?? null) !!}
@elseif ($role === 'customer')
@partial('kpi-card', ['accent' => 'blue', 'icon' => 'fa-receipt', 'label' => t_raw('admin.userdetail.kpi_orders'), 'value' => number_format((int) ($panel['orders_c'] ?? 0))]) @partial('kpi-card', ['accent' => 'green', 'icon' => 'fa-wallet', 'label' => t_raw('admin.userdetail.kpi_spent'), 'value' => money($panel['spent'] ?? 0)]) @partial('kpi-card', ['accent' => 'amber', 'icon' => 'fa-star', 'label' => t_raw('admin.userdetail.kpi_reviews'), 'value' => number_format((int) ($panel['reviews_c'] ?? 0))])

{{ t_raw('admin.userdetail.recent_orders') }}

@if (!empty($panel['orders'])) @foreach ($panel['orders'] as $o) @endforeach @else @partial('table-empty', ['colspan' => 5, 'icon' => 'fa-receipt', 'msg' => t('admin.userdetail.no_orders')]) @endif
{{ t_raw('admin.dashboard.col_order') }}{{ t_raw('common.status') }}{{ t_raw('admin.orders.col_payment') }}{{ t_raw('admin.orders.col_total') }}{{ t_raw('admin.orders.col_placed') }}
{{ $o['order_number'] }} {{ Order::statusLabel((string) $o['status']) }} {{ t_raw('status.payment.' . $o['payment_status']) }} {{ money($o['total']) }} {!! fmt_datetime($o['placed_at']) !!}
@partial('table-toolbar', ['pager' => $panel['orders_pager'] ?? []])

{{ t_raw('admin.userdetail.recent_reviews') }}

@if (!empty($panel['reviews'])) @foreach ($panel['reviews'] as $rv) @endforeach @else @partial('table-empty', ['colspan' => 4, 'icon' => 'fa-star', 'msg' => t('admin.userdetail.no_reviews')]) @endif
{{ t_raw('admin.userdetail.col_restaurant') }}{{ t_raw('common.rating') }}{{ t_raw('common.status') }}{{ t_raw('admin.reviews.col_posted') }}
{{ $rv['restaurant_name'] ?? t_raw('admin.reviews.deleted_restaurant') }} {!! rating_stars_html((float) (int) $rv['rating']) !!} {{ status_label('review', (string) $rv['status']) }} {!! fmt_day($rv['created_at']) !!}
@partial('table-toolbar', ['pager' => $panel['reviews_pager'] ?? []])
@elseif ($role === 'driver')
@partial('kpi-card', ['accent' => 'blue', 'icon' => 'fa-motorcycle', 'label' => t_raw('admin.userdetail.kpi_assigned'), 'value' => number_format((int) ($panel['assigned'] ?? 0))]) @partial('kpi-card', ['accent' => 'green', 'icon' => 'fa-check-circle', 'label' => t_raw('admin.userdetail.kpi_delivered'), 'value' => number_format((int) ($panel['delivered'] ?? 0))])
{{ t_raw('admin.userdetail.access_pin') }}
{!! !empty($panel['pin_set']) ? t('admin.userdetail.pin_set') : t('admin.userdetail.pin_unset') !!}
{!! $renderRestaurantCard($panel['restaurant'] ?? null) !!}

{{ t_raw('admin.userdetail.recent_deliveries') }}

@if (!empty($panel['orders'])) @foreach ($panel['orders'] as $o) @endforeach @else @partial('table-empty', ['colspan' => 5, 'icon' => 'fa-motorcycle', 'msg' => t('admin.userdetail.no_orders')]) @endif
{{ t_raw('admin.dashboard.col_order') }}{{ t_raw('admin.userdetail.col_restaurant') }}{{ t_raw('common.status') }}{{ t_raw('admin.orders.col_total') }}{{ t_raw('admin.orders.col_placed') }}
{{ $o['order_number'] }} {!! or_dash($o['restaurant_name'] ?? null) !!} {{ Order::statusLabel((string) $o['status']) }} {{ money($o['total']) }} {!! fmt_datetime($o['placed_at']) !!}
@partial('table-toolbar', ['pager' => $panel['orders_pager'] ?? []])
@endif @php /* Two halves of the same question a support agent opens a record to answer: what this account has been doing, and what has been done to it. */ @endphp

{{ t_raw('admin.userdetail.sec_activity') }}

{{ t_raw('common.view_all') }}
@if ($activity) @foreach ($activity as $a) @endforeach @else @partial('table-empty', ['colspan' => 4, 'icon' => 'fa-clipboard-list', 'msg' => t('admin.userdetail.no_activity')]) @endif
{{ t_raw('admin.restaurantdetail.col_action') }}{{ t_raw('common.description') }}{{ t_raw('admin.userdetail.col_ip') }}{{ t_raw('common.when') }}
{{ activity_label((string) $a['action']) }}
{!! or_dash($a['detail'] ?? null) !!}
{!! or_dash($a['ip'] ?? null) !!} {{ time_ago($a['created_at']) }}
@partial('table-toolbar', ['pager' => $activityPager])

{{ t_raw('admin.userdetail.sec_account_history') }}

@if ($statusHistory) @foreach ($statusHistory as $h) @endforeach @else @partial('table-empty', ['colspan' => 5, 'icon' => 'fa-user-shield', 'msg' => t('admin.userdetail.no_account_history')]) @endif
{{ t_raw('admin.restaurantdetail.col_action') }}{{ t_raw('admin.userdetail.col_change') }}{{ t_raw('admin.restaurantdetail.col_by') }}{{ t_raw('common.description') }}{{ t_raw('common.when') }}
{{ activity_label((string) $h['action']) }} @php // Only a genuine status transition has a before and after to show. @endphp @if (!empty($h['new_status'])) {!! or_dash($h['old_status'] ?? null) !!} → {{ (string) $h['new_status'] }} @else{!! dash() !!}@endif @if (!empty($h['changed_by_name']))
{!! brandmark_html($h['changed_by_avatar'] ?? null, (string) $h['changed_by_name'], 'sm', 'qm-brandmark--round') !!}
{{ $h['changed_by_name'] }}
@else{!! dash() !!}@endif
{!! or_dash($h['detail'] ?? null) !!}
{{ time_ago($h['created_at']) }}
@partial('table-toolbar', ['pager' => $historyPager])
@php /* /.qm-d2 */ @endphp @endsection