import { Controller } from '@hotwired/stimulus' import { csrfToken } from './csrf' // Drives the checkout page's left column: contact tabs, the same-as-billing // toggle, and — the bulk of it — autosaving the address form and the shipping // method with no submit buttons. // // Flow: any `change` in the address form is debounced ~400ms, then the whole // form is POSTed to saveUrl. The server persists leniently and returns // { errors, shippingOptionsHtml, summaryHtml }. We swap the shipping-options // block in place and hand the summary fragment to the drawer's bbk-cart // controller via the `bbk-cart:changed` window event (same mechanism the drawer // already uses). Shipping-method radios post to selectShippingUrl the same way. export default class extends Controller { static targets = [ 'guestTab', 'loginTab', 'guestPanel', 'loginPanel', 'sameAsBilling', 'shippingFields', 'form', 'shippingOptions', 'status', ] static values = { saveUrl: String, selectShippingUrl: String, statusSaving: String, statusSaved: String, statusError: String, } connect() { this.saveTimer = null this.saveController = null this.statusTimer = null if (this.hasSameAsBillingTarget) this.applySameAsBilling() } disconnect() { clearTimeout(this.saveTimer) clearTimeout(this.statusTimer) this.saveController?.abort() } // ── Contact tabs ──────────────────────────────────────────────────── showGuest() { this.guestPanelTarget.hidden = false this.loginPanelTarget.hidden = true this.guestTabTarget.setAttribute('aria-selected', 'true') this.loginTabTarget.setAttribute('aria-selected', 'false') } showLogin() { this.guestPanelTarget.hidden = true this.loginPanelTarget.hidden = false this.guestTabTarget.setAttribute('aria-selected', 'false') this.loginTabTarget.setAttribute('aria-selected', 'true') } // ── Same as billing ──────────────────────────────────────────────── toggleSameAsBilling() { this.applySameAsBilling() } applySameAsBilling() { const on = this.sameAsBillingTarget.checked // Checked: shipping *is* billing — copy every value across, then hide + // disable so the browser doesn't submit them; the server reuses billing. // Unchecked: reveal them pre-filled from billing wherever still empty. this.element.querySelectorAll('[name^="billing_"]').forEach((billingField) => { const shippingField = this.element.querySelector( `[name="${billingField.name.replace(/^billing_/, 'shipping_')}"]`, ) if (shippingField && (on || !shippingField.value)) { shippingField.value = billingField.value } }) this.shippingFieldsTarget.hidden = on this.shippingFieldsTarget.querySelectorAll('input, select, textarea').forEach((field) => { field.disabled = on }) } // ── Autosave ─────────────────────────────────────────────────────── scheduleSave(event) { // The shipping-method and payment radios live inside this controller's // element too, and this action is bound on .bbk-checkout-main to also // catch the contact email/consent that sit outside the