{{-- Users listing — docs/wireframes-v12/user-management.html, content region for content region. v12's order, top to bottom: a `.grid-4` stat strip, then the action bar, then ONE card carrying the `.filter-bar` and the `.data-table` — the filters are the card's own header strip, not a card of their own. **Note the stat strip is ABOVE the action bar here**, where the brokers listing puts its button first. That is v12's own difference between the two pages (user-management.html:75-102 against broker-management.html:75-109), not a drift, and pixel fidelity is what the client asked for. The action bar is also the wireframe's exact shape and not the brokers page's: an EMPTY left `
` and the button on the right (lines 99-102). There is no "All Users" heading and no sub-line on this page, so none is invented — the empty div is kept because `.d-flex.justify-between` is what pushes the button to the right edge. DataTables drives the table. Its own search box stays out of the dom string because the wireframe's `.search-input` in the filter bar is the one the user sees; the script below feeds the plugin from it. The column list exists only in UsersDataTable::getColumns(). ## Deliberate differences from the wireframe * **The fourth stat card is Deleted, not Locked** (decision D9). Nothing in this application locks an account — no attempt counter, no lockout window, no unlock screen — and the client chose two statuses (D1), so the red `fa-user-lock` slot is spent on a number the database can answer. It keeps the wireframe's red icon chip and its glyph. * **The Status filter offers two options, not three.** Same reason. * **There is no Department filter and no Department column**, and no User ID column either (client instruction, CR-13.1 B3 + B5). v12 draws all three. Both columns went from UsersDataTable and the select went from the filter bar below, so the bar is Search, Role, Status — three controls where the wireframe has four. `department` and `code` are still on the form, the profile page and the model; this page simply stopped listing and filtering on them. * **The Role filter lists the REAL spatie roles** (decision D3) where v12 hardcodes seven fictional ones: a filter offering a role nobody holds returns an empty table, and one missing a role somebody created cannot find them at all. * **Two extra row actions** — a status toggle (D1) and a Delete (D7) — which v12's action group does not draw. See users/partials/actions. * **No trend lines under the stat cards**, which is not a difference at all: v12 draws none on this page. It is written down because the projects and brokers listings had to drop mocked ones, and the next reader should know this page never had any. --}} @extends('layouts.app') @section('title', __('users.title')) @section('breadcrumbs') @endsection @section('content') @php /* * Both keys are defaulted here as well as skipped in the controller on * an ajax draw. Either alone would be enough today; together they mean * the page cannot break on the difference between two ways of asking * for it — the 500 CR-7 shipped and then closed twice over. */ $stats = $stats ?? ['total' => 0, 'active' => 0, 'inactive' => 0, 'deleted' => 0]; $roleNames = $roleNames ?? []; @endphp {{-- The stat strip. v12 tints the icon chip per tile; the values carry no colour class on this page, so none is added. --}}
@foreach ([ 'total' => ['icon' => 'fa-users', 'tone' => 'blue'], 'active' => ['icon' => 'fa-user-check', 'tone' => 'green'], 'inactive' => ['icon' => 'fa-user-clock', 'tone' => 'yellow'], 'deleted' => ['icon' => 'fa-user-lock', 'tone' => 'red'], ] as $key => $tile)
{{ $stats[$key] ?? 0 }}
{{ __('users.stats.'.$key) }}
@endforeach
{{-- v12's own action bar: an empty left cell and the primary action on the right. The empty
is load-bearing — it is what `justify-between` pushes the button away from. --}}
@can('users.create') {{ __('users.add_button') }} @endcan
{{-- The filter bar IS the card's header strip in v12. It is a
here only so Enter does not reload the page; `.filter-bar` is the flex row, so the form element carries it directly. v12 labels none of these controls — a placeholder and an option list are all it draws. The visually-hidden labels are ours and are not a visual change: a select whose only name is its first option is unusable with a screen reader. --}}
{{-- `table-wrapper` is v12's own scroll box. `table-responsive` rides along because it is Bootstrap's name for the same thing and the one the shared component and its test both use; this screen does not go through that component (v12's card has no card-body around the table) but the two names stay together so a later reader does not read the difference as meaningful. --}}
{!! $dataTable->table(['class' => 'data-table']) !!}
{{-- The shared row-delete confirmation (CR-16 item J8). At the END of the content section and outside every `.card`, for the clipping reason the partial's own header records. It also pushes the toaster and the shared delete client, which is why the row buttons need nothing of their own. --}} @include('partials.ajax-delete-modal') @endsection @push('styles') @endpush @push('scripts') {{-- Order is load bearing: jQuery (plugins.bundle.js, already in the layout) → core library → the Bootstrap 5 integration that patches its renderers → yajra's init, which calls $(…).DataTable(…) and would throw without the two above. --}} {!! $dataTable->scripts() !!} @endpush