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

125 lines
3.7 KiB
JavaScript
Raw Permalink 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 country field where users can type to filter and select
* from a predefined list.
*/
export default class extends CartBaseController {
// All are required!
2021-11-22 17:51:50 +00:00
static targets = ["id", "iso", "list", "name"];
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
async connect() {
const countries = await this.countries();
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
countries.forEach((country) => {
const option = document.createElement("option");
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
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;
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
this.input_event = this._input_event.bind(this);
this.invalid_event = this._invalid_event.bind(this);
this.change_event = this._change_event.bind(this);
2021-06-01 21:33:49 +00:00
// Only allow names on this list
2021-11-22 17:51:50 +00:00
this.nameTarget.pattern = countries.map((x) => x.attributes.name).join("|");
this.nameTarget.addEventListener("input", this.input_event);
this.nameTarget.addEventListener("invalid", this.invalid_event);
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
this.nameTarget.addEventListener("change", this.change_event);
2021-06-01 21:33:49 +00:00
// 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"));
}
2021-06-01 21:33:49 +00:00
disconnect() {
this.nameTarget.removeEventListener("input", this.input_event);
this.nameTarget.removeEventListener("invalid", this.invalid_event);
this.nameTarget.removeEventListener("change", this.change_event);
}
2021-06-01 21:33:49 +00:00
_input_event(event) {
this.nameTarget.setCustomValidity("");
}
2021-06-01 21:33:49 +00:00
_invalid_event(event) {
const site = window.site;
this.nameTarget.setCustomValidity(site.i18n.countries.validation);
}
2021-06-01 21:33:49 +00:00
_change_event(event) {
const value = this.nameTarget.value.trim();
2021-06-01 21:33:49 +00:00
if (value === "") return;
2021-06-01 21:33:49 +00:00
const options = Array.from(this.nameTarget.list.options);
const option = options.find((x) => x.value == value);
2021-06-01 21:33:49 +00:00
// 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;
2021-06-01 21:33:49 +00:00
}
/*
* Sends a `cart:country:update` event so other controllers can
* subscribe to changes.
*/
2021-11-22 17:51:50 +00:00
dispatchChangedEvent(data = {}) {
const event = new CustomEvent("cart:country:update", {
2021-06-01 21:33:49 +00:00
detail: {
id: this.idTarget.value,
iso: this.isoTarget.value,
2021-11-22 17:51:50 +00:00
group: this.data.get("group"),
2021-06-01 21:33:49 +00:00
selectedState: this.nameTarget.dataset.selectedState,
selectedZipcode: this.nameTarget.dataset.selectedZipcode,
2021-11-22 17:51:50 +00:00
data,
},
});
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
window.dispatchEvent(event);
2021-06-01 21:33:49 +00:00
}
/*
* Fetch the country list from storage or from API
*/
2021-11-22 17:51:50 +00:00
async countries() {
const countries = JSON.parse(this.storageTemp.getItem("countries"));
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
if (countries) return countries;
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
const response = await this.spree.countries.list();
2021-06-01 21:33:49 +00:00
// TODO: Show error message
2021-11-22 17:51:50 +00:00
if (!response.success()) return;
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
this.storageTemp.setItem(
"countries",
JSON.stringify(response.success().data)
);
2021-06-01 21:33:49 +00:00
2021-11-22 17:51:50 +00:00
return response.success().data;
2021-06-01 21:33:49 +00:00
}
}