import { CartBaseController } from './cart_base_controller' /* * Populates a state field where users can type to filter and select * from a predefined list. It waits for an `cart:country:update` event * to become populated. */ export default class extends CartBaseController { // All are required! static targets = [ 'id', 'list', 'name' ] connect () { window.addEventListener('cart:country:update', async event => { if (this.data.get('group') !== event.detail.group) return this.idTarget.value = '' this.nameTarget.value = '' this.listTarget.innerHTML = '' const statesRequired = event.detail.data.statesRequired == 'true' this.nameTarget.disabled = !statesRequired this.nameTarget.required = statesRequired if (!statesRequired) return const states = await this.states(event.detail.iso) const site = window.site states.forEach(state => { let option = document.createElement('option') option.value = state.attributes.name option.dataset.id = state.id this.listTarget.appendChild(option) }) this.nameTarget.pattern = states.map(x => x.attributes.name).join('|') this.nameTarget.addEventListener('input', event => this.nameTarget.setCustomValidity('')) this.nameTarget.addEventListener('invalid', event => this.nameTarget.setCustomValidity(site.i18n.states.validation)) if (event.detail.selectedState) { this.nameTarget.value = event.detail.selectedState this.nameTarget.dispatchEvent(new Event('change')) } }) // When the input changes we update the actual value and also the // state list via an Event this.nameTarget.addEventListener('change', event => { const options = Array.from(this.listTarget.options) const option = options.find(x => x.value == this.nameTarget.value) // TODO: If no option is found, mark the field as invalid if (!option) return this.idTarget.value = option.dataset.id this.idTarget.dispatchEvent(new Event('change')) }) } /* * Fetch the state list from storage or from API using a country ISO * code */ async states (countryIso) { const stateId = `states:${countryIso}` let states = JSON.parse(this.storageTemp.getItem(stateId)) if (states) return states // There's no state query, but we can fetch the country and include // its states. const response = await this.spree.countries.show(countryIso, { include: 'states' }) // TODO: Show error message if (response.isFail()) { this.handleFailure(response) return {} } states = response.success().included // Order alphabetically by name states.sort((x, y) => x.attributes.name > y.attributes.name) this.storageTemp.setItem(stateId, JSON.stringify(states)) return states } }