import { CartBaseController } from './cart_base_controller' /* * Populates a country field where users can type to filter and select * from a predefined list. */ export default class extends CartBaseController { // All are required! static targets = [ 'id', 'iso', 'list', 'name' ] async connect () { const countries = await this.countries() countries.forEach(country => { const option = document.createElement('option') option.value = country.attributes.name option.dataset.id = country.id option.dataset.iso = country.attributes.iso option.dataset.statesRequired = country.attributes.states_required option.dataset.zipcodeRequired = country.attributes.zipcode_required this.listTarget.appendChild(option) }) const site = await this.site() // Only allow names on this list this.nameTarget.pattern = countries.map(x => x.attributes.name).join('|') this.nameTarget.addEventListener('input', event => this.nameTarget.setCustomValidity('')) this.nameTarget.addEventListener('invalid', event => this.nameTarget.setCustomValidity(site.i18n.countries.validation)) // When the input changes we update the actual value and also the // state list via an Event this.nameTarget.addEventListener('change', event => { const value = this.nameTarget.value.trim() if (value === '') return const options = Array.from(this.nameTarget.list.options) const option = options.find(x => x.value == value) // TODO: If no option is found, mark the field as invalid if (!option) return this.idTarget.value = option.dataset.id this.isoTarget.value = option.dataset.iso this.idTarget.dispatchEvent(new Event('change')) this.isoTarget.dispatchEvent(new Event('change')) this.dispatchChangedEvent(option.dataset) // XXX: Prevent mixing data delete this.nameTarget.dataset.selectedState delete this.nameTarget.dataset.selectedZipcode }) // The input is disabled at this point this.nameTarget.disabled = false // Load data if the input is autocompleted if (this.nameTarget.value.trim() !== '') this.nameTarget.dispatchEvent(new CustomEvent('change')) } /* * Sends a `cart:country:update` event so other controllers can * subscribe to changes. */ dispatchChangedEvent (data = {}) { const event = new CustomEvent('cart:country:update', { detail: { id: this.idTarget.value, iso: this.isoTarget.value, group: this.data.get('group'), selectedState: this.nameTarget.dataset.selectedState, selectedZipcode: this.nameTarget.dataset.selectedZipcode, data } }) window.dispatchEvent(event) } /* * Fetch the country list from storage or from API */ async countries () { const countries = JSON.parse(this.storageTemp.getItem('countries')) if (countries) return countries const response = await this.spree.countries.list() // TODO: Show error message if (!response.success()) return this.storageTemp.setItem('countries', JSON.stringify(response.success().data)) return response.success().data } }