{{-- Edit Booking — docs/wireframes-v12/edit-booking.html. ## Shape v12's layout, top to bottom: 1. a top bar: the status pill and the `code · customer · unit` meta line on the left, a View button on the right; 2. a card carrying the three-tab strip (Basic Details / Documents / History) with no bottom margin, so the panel below reads as attached; 3. one `.tab-content-panel` per tab. The tabs are real links to the panels they reveal, not buttons with an inline `onclick` the way v12 writes them: nrems-tabs.js upgrades them in place, and with no Javascript at all all three panels render one under the other — every field, every document and the whole history still on the page, which is the right way for this screen to fail. Avoiding the inline handler is a step toward the planned strict CSP, not arrival at it. **The form wraps the Basic panel only.** The Documents panel carries delete forms of its own, and a form inside a form is invalid HTML that browsers resolve by silently dropping the inner one — which would have made every document's Delete button submit the booking instead. ## The twin rule (recipe §9) This file and bookings/create.blade.php are twins. Every field is written out in both, and neither includes a shared form partial. **A field added, removed or renamed here must be mirrored in create.blade.php in the same commit.** The one thing they share is bookings/partials/co-owner-block.blade.php, whose header says why a repeater row is the exception; the documents and history panels are reads rather than fields and are shared with the show screen for the same reason. ### What this screen has that its twin does not * it PUTs to `bookings.update` and therefore carries a `_method` field; * the tab strip and its two extra panels; * Booking Information is ordered date / inquiry / entity type, which is this wireframe's order (the twin's is the other one's); * its footer depends on the booking's status (CR-8 §3.1) — see the note there; * every control is prefilled, the unit select can draw a unit that is `booked` because THIS booking holds it, and the Co-Owner Details section renders one block per stored co-owner. ## Deliberate differences from the wireframe * The wireframe has a **stray duplicated Occupation block** at lines 275-288, outside the co-owner block it belongs to and with a mismatched ``. It is a wireframe bug and is not reproduced. * Its trailing script is broken in the same way new-booking.html's is (lines 402-414: an unbalanced `);` and a dangling function body). * The "WhatsApp Number" label on line 212 is the inquiry form's wording leaking in; this field is `customers.mobile_number` and every other screen calls it Mobile Number, so it is Mobile Number here. * Occupation is a select and an Assigned Sales Person row is rendered on both twins — decisions D5 and D6, argued in create.blade.php's header. ## No lang file (CR-8 §0.1) Every string on this screen is written here, on the client's instruction. --}} @extends('layouts.app') @section('title', 'Edit Booking') @section('breadcrumbs') @endsection @section('content') @php $occupations = \App\Enums\Occupation::options(); // The "Through its …" map, keyed by booking type ID for the client and // built from the name-keyed constant. See create.blade.php's twin block. $throughMap = []; foreach ($bookingTypes as $typeId => $typeName) { if (isset(\App\Models\Booking::THROUGH_MAP[$typeName])) { $throughMap[$typeId] = [ 'title' => \App\Models\Booking::THROUGH_MAP[$typeName], 'placeholder' => \App\Models\Booking::THROUGH_PLACEHOLDERS[$typeName] ?? '', ]; } } $selectedType = old('booking_type_id', $booking->booking_type_id); $through = $throughMap[$selectedType] ?? null; // Old input wins over the stored rows, so a rejected submit comes back // with exactly what the user had typed — including a co-owner they had // just added and one they had just removed. A blade loop and not a JS // restore pass (CR-8 §5). $coOwnerRows = is_array(old('co_owners')) ? old('co_owners') : $coOwners->map(static fn (\App\Models\Customer $row): array => [ 'id' => $row->getKey(), 'name' => $row->name, 'occupation' => $row->occupation?->value, 'mobile_number' => $row->mobile_number, 'alternate_mobile' => $row->alternate_mobile, 'email' => $row->email, 'address' => $row->address, ])->values()->all(); @endphp
@include('bookings.partials.status-badge', ['status' => $booking->status]) {{ $booking->code }}  ·  {{ $customer->name ?? '—' }}  ·  {{ $booking->unit?->unit_number ?? '—' }}
@can('bookings.view') View @endcan
{{-- The module's client config, in three JSON data-attributes plus two scalars. `data-include-unit` is what keeps this booking's own unit in the cascade's answer when the project is re-chosen and turns out to be the same one — without it, a confirmed booking's unit (which is `booked`, because this booking holds it) would vanish from the select. --}}
{{-- ===== 1. Booking Information ===== --}}
Booking Information
{{-- Written out rather than because the control needs the wireframe's helper line under it, and the select component has no hint prop — 's own docblock invites this use. --}}
{{-- ===== 2. Booking Details (the main customer) ===== --}}
Booking Details
{{-- THREE cells, not two — Common Name, the "Through its …" panel, Occupation — matching the twin and the wireframe's own `form-row form-row-3` (new-booking.html:145; edit-booking.html draws the same three, in a row its own stray markup mislabels). --}}
{{-- The one "Through its …" block. Server-rendered into the right state; retitled and shown/hidden by the module when the entity type changes. --}}
{{-- ===== 3. Co-Owner Details ===== --}}
Co-Owner Details
@foreach ($coOwnerRows as $index => $row) @include('bookings.partials.co-owner-block', [ 'index' => $index, 'row' => is_array($row) ? $row : [], 'position' => $loop->iteration, 'occupations' => $occupations, ]) @endforeach
Click "Add More Co-Owner" to add additional co-owners.
{{-- ===== 4. Contact Person ===== --}}
Contact Person
{{-- ===== 5. Unit Selection ===== --}}
Unit Selection
{{-- The options carry this booking's own unit even when the availability rule would drop it — see BookingUnitOptions::forProject() on why a select cannot show a value it has no option for. --}}
{{-- ===== 6. Remarks ===== --}}
Remarks
{{-- ONE submit, and it carries no `name` (CR-9 §4, decision D11). The footer used to depend on the state: a draft got Save as Draft and Confirm Booking, a confirmed booking got Save Changes alone, and BookingRequest checked the posted `action` against those two sets. The user removed the draft — "all booking always confirmed booking" — so there is one state left, one button, and nothing for the server to tell apart. An update leaves the lifecycle exactly where it was (BookingService::targetStatus()), which is what "Update Booking" has always meant: demoting a confirmed booking would silently free its own unit and un-confirm its inquiry, and there is no button for that. A cancelled booking never reaches this screen at all — the controller 404s first. --}}
@include('bookings.partials.documents', ['booking' => $booking])
Booking History
@include('bookings.partials.history', ['history' => $history])
{{-- The conditional, cascade and repeater rules are excluded from the client rule set. See BookingRequest::clientRuleExclusions(); create.blade.php carries the same note. --}} {{-- The Booking Entity Type confirmation (CR-15.2 §7 item G1). At the END of the content section and outside every `.card`, for the clipping reason its own header records — and AFTER above, which is what puts its script behind the generated `.validate()` call on the scripts stack. The guard's ordering note explains why that matters. --}} @include('bookings.partials.booking-type-modal', ['booking' => $booking]) {{-- The Documents tab's delete confirmation (CR-15.3 item H2), for the same placement reason as the dialog above it. --}} @include('customer-documents.partials.delete-modal') @endsection @push('scripts') {{-- The tab strip. Progressive enhancement: every panel is rendered visible and this module hides the inactive ones on load, so the screen degrades to three sections one under the other rather than to two hidden ones. It does nothing at all on a page without [data-nrems-tabs]. --}} {{-- The booking form client (CR-8 §5). ES5, no build step, no dependency, and it does nothing at all on a page without #nrems_booking_form_module. --}} @endpush