sutty-base-jekyll-theme/_packs/controllers/state_controller.js

92 lines
2.8 KiB
JavaScript
Raw Normal View History

2021-06-01 21:33:49 +00:00
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 = await this.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
}
}