{{-- The three Booking Action modals of docs/wireframes-v12/inquiry.html — #tentativeModal (~line 414), #meetingModal (~456) and #notInterestedModal (~488). ## One instance of each, re-targeted per row The wireframe draws them once at the foot of the page and points them at whichever row's dropdown was used, and so does this: each form's `action` is rewritten by nrems-inquiry-actions.js from the row's own `data-inquiry` payload before the dialog opens. Rendering three dialogs per row would have been 30 hidden forms on a 10-row page and 30 CSRF tokens with them. The wireframe's own dialogs are hand-rolled fixed-position divs; these are , which is Bootstrap 5's markup with the wireframe's look applied to `.modal-content` from the app-additions tail of nrems-wireframe.css. That is the component's documented reason for existing (v12 draws no modal its own stylesheet actually renders), and it buys the focus trap, the Escape key and the backdrop click that the wireframe's inline `onclick` handlers were approximating. ## Per-form error bags (recipe §9) The three FormRequests declare `$errorBag` — `hold`, `meeting` and `not_interested` — so a rejected hold puts its messages in a bag of its own and cannot light up the Not Interested modal's Reason field. Two things read those bags: * the fields below, through `$errors->getBag(...)`. The controls are written out inside rather than as etc., because the field components resolve their own error from the *default* bag and there is no prop to point them at another one — and 's own docblock invites exactly this use ("whenever a form needs a control this library does not ship... and you still want the label, asterisk and error to look and behave like every other field"). The markup they emit is the components' own, class for class. * the reopen decision, below: `$errors->hasBag(...)` tells the page which dialog to put back on screen after a failed submit, and the hidden `data-reopen` field tells it which row that was. ## Old input Flashed old input is NOT scoped to an error bag, so `old()` repopulates the right control whichever form failed. The unit select is the exception and is left to the script: its options are fetched from the cascade when the dialog opens, so there is nothing server-rendered for `old()` to select — the script re-applies the old value once the options exist, from `data-old-unit` below. --}} @php $holdErrors = $errors->getBag('hold'); $meetingErrors = $errors->getBag('meeting'); $closingErrors = $errors->getBag('not_interested'); // Which dialog a failed submit should put back on screen, and which row it // belonged to. `reopen_inquiry` is a hidden field every one of the three // forms posts, so the answer survives the redirect in old input. $reopen = match (true) { $holdErrors->isNotEmpty() => 'tentative', $meetingErrors->isNotEmpty() => 'meeting', $closingErrors->isNotEmpty() => 'notinterested', default => null, }; @endphp {{-- The whole block is a write surface, so it renders only for a user who may write. The Booking Action column is gated per row on the same ability, so a view-only user has no way to reach these and no markup for them either. The gate is the bare permission rather than a policy check, because there is no one inquiry these dialogs belong to — they are re-targeted per row, and the per-row gate is the one in partials/booking-action.blade.php. InquiryPolicy@update is `$user->can('inquiries.edit')` and nothing else, so the two agree by construction; a Super Admin passes here through the same Gate::before hook that carries them through the policy. --}} @can('inquiries.edit')
{{-- ===== TENTATIVE BOOKING ===== --}} {{-- Options are fetched from the cascade endpoint when the dialog opens, scoped to the row's project with the row's own hold ignored (CR-6 §3). The placeholder is the only option the server renders. --}} {{ __('inquiries.hints.units_available') }} @if ($holdErrors->has('tentative_unit_id'))
{{ $holdErrors->first('tentative_unit_id') }}
@endif
{{ __('inquiries.hints.hold_until') }} @if ($holdErrors->has('hold_until'))
{{ $holdErrors->first('hold_until') }}
@endif
{{-- ===== PERSONAL MEETING ===== --}}
@if ($meetingErrors->has('date'))
{{ $meetingErrors->first('date') }}
@endif
@if ($meetingErrors->has('time'))
{{ $meetingErrors->first('time') }}
@endif
@if ($meetingErrors->has('location'))
{{ $meetingErrors->first('location') }}
@endif
{{-- ===== NOT INTERESTED / CLOSED ===== --}} @if ($closingErrors->has('reason'))
{{ $closingErrors->first('reason') }}
@endif
{{-- v12 paints this one `background:var(--danger)` over a `.btn-primary`; `.btn-danger` is the wireframe's own class for exactly that fill (style.css:441) and is used instead of an inline style. --}}
@endcan