{{-- The conclusion dialog of CR-10 §6.3 — one instance per page, re-targeted at whichever activity task's ✓ was pressed. Modelled on inquiries/partials/modals.blade.php's #notInterestedModal, line for line: wrapping an , a per-form error bag, a hidden field naming the row so a rejected submit can come back to it, and every string the script can put on screen handed in from Blade as data. Included by the three screens that offer the ✓ — the dashboard, the inquiry show page and the follow-up page — at the END of their content section rather than inside a card. A Bootstrap dialog is `position: fixed`, but its containing block is whatever ancestor establishes one, so nesting it inside a `.card` (which the wireframe gives `overflow: hidden`) is a way to have it clipped on some browsers and not others. ## It also renders the document tasks' forms The `nrems_task_forms` stack at the foot of this file is where every document task's POST form lands — partials/task-action.blade.php pushes one per row rather than writing it in place, because the follow-up page draws its timeline inside a form of its own and a nested
is dropped by the parser. That partial's header has the full reasoning. The two live in one file on purpose: a screen that renders the ✓ needs the dialog AND the stack, so pairing them here means there is one include to remember rather than two, and no screen can end up with a button whose form was never emitted. The stack must therefore be rendered AFTER the markup that pushes onto it — which is what "include this at the end of the content section" buys, and the only ordering rule this partial has. ## One instance, re-targeted The reason modals.blade.php gives: a 10-row page would otherwise carry ten hidden forms and ten CSRF tokens. `form.action` is rewritten by nrems-pending-tasks.js from the button's own `data-task` payload, which was built with route() server-side — so no url is ever constructed from an id in Javascript. ## The error bag, and what reopens the dialog CompleteFollowUpRequest::ERROR_BAG is `complete_task`, and InquiryActionController re-bags the recorder's race exception into it too, so this is the only bag either half of the endpoint writes to. Two things read it: * the textarea below, through `$errors->getBag(...)` — written out inside rather than as because the field components resolve their error from the DEFAULT bag and take no prop to point them elsewhere. Same reasoning, same markup, as the three CR-6 dialogs. * the reopen decision: a `conclusion` message means the user's text was rejected and the dialog goes back up with it. A `task` message does NOT reopen it — that is "somebody already finished this", which the card's alert says and which no amount of retyping fixes. Old input is not scoped to a bag, so `old('conclusion')` repopulates whatever the user typed regardless of which page they were on. ## Escaping Every string in the JSON payload is a lang string. `data-reopen-task` is old input and is emitted through `{{ }}`; the script strips it to digits before using it as an id anyway. Both reads of old input go through `$oldScalar()` below rather than through `old()` directly, because old input is posted input and posted input can be an array. Its docblock has the failure that closes. --}} @php $completeErrors = $errors->getBag(\App\Http\Requests\Inquiries\CompleteFollowUpRequest::ERROR_BAG); /** * Old input, forced to a string. * * `old()` hands back WHATEVER was flashed, and what was flashed is whatever * was posted: `conclusion[]=x` is an array, and an array reaching `{{ }}` * is `htmlspecialchars(): Argument #1 must be of type string, array given` * — a 500 on the page the redirect lands on, and again on the next render * because the input is re-flashed with the errors. The `string` rule * rejects the array, which is what makes this the *rejected* path and so * exactly the path that repopulates the form. * * An array is dropped rather than serialised: there is no honest scalar to * show for it, and the user typed one either way. * * The same shape is in inquiries/partials/modals.blade.php (CR-6's three * dialogs read `old('reason')`, `old('location')` and the rest raw). It is * NOT fixed here — that file is outside this CR — but it is the same defect * and a future CR should sweep it. */ $oldScalar = static fn (string $key): string => is_scalar($value = old($key, '')) ? (string) $value : ''; // Reopen only for a rejected CONCLUSION. See the header. $reopenTask = $completeErrors->has('conclusion') ? $oldScalar('reopen_task') : ''; $oldConclusion = $oldScalar('conclusion'); @endphp
{{-- `:novalidate="false"` — the browser's own bubble is wanted here, and this is the case 's docblock says the flag exists for. The form has ONE field with ONE unconditional rule, no jsvalidation is bound to it (nothing points the component at this selector), and without the flag the `required` on the textarea below is decorative: an empty conclusion would cost a round-trip to be told what the field already knows. --}} {{-- Which task this dialog is pointed at. The label is written by the script with textContent — never innerHTML — from the button's payload, because there is one dialog and many rows. --}}

{{ __('inquiries.modals.complete_for') }}

@if ($completeErrors->has('conclusion'))
{{ $completeErrors->first('conclusion') }}
@endif
{{-- The document tasks' own POST forms, hoisted out of the rows that own them. See the header, and partials/task-action.blade.php. Empty on a page whose pending tasks are all activity ones, and on a page with no ✓ at all. --}} @stack('nrems_task_forms') @push('scripts') {{-- The Pending Tasks client (CR-10 §6.3). ES5, no build step, and it does nothing at all on a page without #nrems_pending_tasks_module — the same shape as the other nrems-*.js modules. @once because all three screens push it and one of them (the follow-up page) already pushes another. --}} @once @endonce @endpush