2021-11-22 17:51:50 +00:00
|
|
|
import { CartBaseController } from "./cart_base_controller";
|
2021-06-01 21:33:49 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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!
|
2021-11-22 17:51:50 +00:00
|
|
|
static targets = ["id", "list", "name"];
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-22 17:51:50 +00:00
|
|
|
connect() {
|
2021-11-25 21:40:44 +00:00
|
|
|
this.cart_country_update_event = this._cart_country_update_event.bind(this);
|
|
|
|
this.change_event = this._change_event.bind(this);
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
window.addEventListener(
|
|
|
|
"cart:country:update",
|
|
|
|
this.cart_country_update_event
|
|
|
|
);
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
// When the input changes we update the actual value and also the
|
|
|
|
// state list via an Event
|
|
|
|
this.nameTarget.addEventListener("change", this.change_event);
|
|
|
|
}
|
|
|
|
|
|
|
|
disconnect() {
|
|
|
|
window.removeEventListener(
|
|
|
|
"cart:country:update",
|
|
|
|
this.cart_country_update_event
|
|
|
|
);
|
|
|
|
this.nameTarget.removeEventListener("change", this.change_event);
|
|
|
|
}
|
|
|
|
|
|
|
|
async _cart_country_update_event(event) {
|
|
|
|
if (this.data.get("group") !== event.detail.group) return;
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
this.idTarget.value = "";
|
|
|
|
this.nameTarget.value = "";
|
|
|
|
this.listTarget.innerHTML = "";
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
const statesRequired = event.detail.data.statesRequired == "true";
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
this.nameTarget.disabled = !statesRequired;
|
|
|
|
this.nameTarget.required = statesRequired;
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
if (!statesRequired) return;
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
const states = await this.states(event.detail.iso);
|
|
|
|
const site = window.site;
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
states.forEach((state) => {
|
|
|
|
let option = document.createElement("option");
|
|
|
|
option.value = state.attributes.name;
|
|
|
|
option.dataset.id = state.id;
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
this.listTarget.appendChild(option);
|
2021-11-22 17:51:50 +00:00
|
|
|
});
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
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"));
|
|
|
|
}
|
|
|
|
}
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
_change_event(event) {
|
|
|
|
const options = Array.from(this.listTarget.options);
|
|
|
|
const option = options.find((x) => x.value == this.nameTarget.value);
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-25 21:40:44 +00:00
|
|
|
// 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"));
|
2021-06-01 21:33:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fetch the state list from storage or from API using a country ISO
|
|
|
|
* code
|
|
|
|
*/
|
2021-11-22 17:51:50 +00:00
|
|
|
async states(countryIso) {
|
|
|
|
const stateId = `states:${countryIso}`;
|
|
|
|
let states = JSON.parse(this.storageTemp.getItem(stateId));
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-22 17:51:50 +00:00
|
|
|
if (states) return states;
|
2021-06-01 21:33:49 +00:00
|
|
|
|
|
|
|
// There's no state query, but we can fetch the country and include
|
|
|
|
// its states.
|
2021-11-22 17:51:50 +00:00
|
|
|
const response = await this.spree.countries.show(countryIso, {
|
|
|
|
include: "states",
|
|
|
|
});
|
2021-06-01 21:33:49 +00:00
|
|
|
|
|
|
|
// TODO: Show error message
|
|
|
|
if (response.isFail()) {
|
2021-11-22 17:51:50 +00:00
|
|
|
this.handleFailure(response);
|
|
|
|
return {};
|
2021-06-01 21:33:49 +00:00
|
|
|
}
|
|
|
|
|
2021-11-22 17:51:50 +00:00
|
|
|
states = response.success().included;
|
2021-06-01 21:33:49 +00:00
|
|
|
|
|
|
|
// Order alphabetically by name
|
2021-11-22 17:51:50 +00:00
|
|
|
states.sort((x, y) => x.attributes.name > y.attributes.name);
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-22 17:51:50 +00:00
|
|
|
this.storageTemp.setItem(stateId, JSON.stringify(states));
|
2021-06-01 21:33:49 +00:00
|
|
|
|
2021-11-22 17:51:50 +00:00
|
|
|
return states;
|
2021-06-01 21:33:49 +00:00
|
|
|
}
|
|
|
|
}
|