{{-- Row actions for the Inquiries DataTable — docs/wireframes-v12/inquiry.html (~line 130):
v12 shows view + edit. Delete is added here for the reason projects/partials/actions.blade.php gives for the same addition: the module has a delete permission and no other screen exposes it. It wears the same `.btn-icon` with the wireframe's own `.text-danger` utility. Rendered by InquiriesDataTable through rawColumns(['actions']), which means this output is injected into the page unescaped. **Nothing user-controlled may reach it unescaped**: the only dynamic values here are route urls built from the model key, and the inquiry code, which appears solely inside Js::from() — that emits it as a JSON string literal with < > & " escaped to \u sequences, which is what stops `');alert(1)//` breaking out of the confirm() string (the stored XSS commit 3492ec1 fixed on the projects listing). yajra hands the row's model in as $model. Every control is gated on its own ability rather than on one blanket check, so a user with `inquiries.view` alone gets the eye and nothing else. Delete is a plain button that opens the shared confirmation dialog and, on Confirm, sends the DELETE by ajax (CR-16 item J2) — never a link, because a GET that destroys data would be triggered by any crawler or prefetch. ## The lock (CR-6.2 items K1/K2) Edit and Delete are withheld entirely on a BOOKING-CONFIRMED inquiry, for every viewer including a Super Admin. The client's sentence is that once an inquiry is booking-confirmed *"no one can edit, delete that inquiry"*, and "no one" is why the predicate is a STATE comparison and not a policy arm: Gate::before hands a Super Admin every ability, so a policy returning false would have locked everybody except the one account that sentence most needs to cover. InquiryPolicy is untouched. Both halves are required — the existing ability AND the lock — so a viewer who may not edit still sees nothing, and one who may sees nothing on a booked row. The server refuses the same two routes on the same predicate (InquiryController::lockedReason()), so this is a screen telling the truth about what the server will do rather than the enforcement itself. And it lifts by itself: cancelling the booking reverts the status (CR-9) and the two controls come back. --}} @php /** @var \App\Models\Inquiry $model */ // CR-6.2 item K1: a status comparison on a model this row already holds, // so it costs nothing per row. Never hasLiveBooking() here — that is a // query per row, and a WIDER set than the client named. $locked = $model->isLockedByBooking(); @endphp
@can('view', $model) @endcan @if (! $locked) @can('update', $model) @endcan @can('delete', $model) {{-- CR-16 item J2: a plain button, not a form with a confirm(). `data-url` is the destroy route rendered by route() — the client's own instruction — and `data-confirm` is the SAME lang sentence the confirm() showed, which the shared dialog writes with textContent. nrems-ajax-delete.js sends the DELETE and redraws this table in place, so the page and the filters survive the delete. --}} @endcan @endif