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

98 lines
2.9 KiB
JavaScript
Raw Normal View History

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() {
window.addEventListener("cart:country:update", async (event) => {
if (this.data.get("group") !== event.detail.group) return;
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
this.idTarget.value = "";
this.nameTarget.value = "";
this.listTarget.innerHTML = "";
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
const statesRequired = event.detail.data.statesRequired == "true";
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
this.nameTarget.disabled = !statesRequired;
this.nameTarget.required = statesRequired;
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
if (!statesRequired) return;
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
const states = await this.states(event.detail.iso);
const site = window.site;
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +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-22 17:51:50 +00:00
this.listTarget.appendChild(option);
});
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +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)
);
2021-06-01 21:33:49 +00:00
if (event.detail.selectedState) {
2021-11-22 17:51:50 +00:00
this.nameTarget.value = event.detail.selectedState;
this.nameTarget.dispatchEvent(new Event("change"));
2021-06-01 21:33:49 +00:00
}
2021-11-22 17:51:50 +00:00
});
2021-06-01 21:33:49 +00:00
// When the input changes we update the actual value and also the
// state list via an Event
2021-11-22 17:51:50 +00:00
this.nameTarget.addEventListener("change", (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
// TODO: If no option is found, mark the field as invalid
2021-11-22 17:51:50 +00:00
if (!option) return;
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
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
}
}