270 lines
5.8 KiB
JavaScript
270 lines
5.8 KiB
JavaScript
import { Controller } from "stimulus";
|
|
import { Liquid } from "liquidjs";
|
|
|
|
/*
|
|
* Base controller, shared methods go here and other classes extend from
|
|
* this.
|
|
*/
|
|
export class CartBaseController extends Controller {
|
|
get spree() {
|
|
return window.spree;
|
|
}
|
|
|
|
/*
|
|
* Gets all products from storage
|
|
*
|
|
* @return [Array]
|
|
*/
|
|
get products() {
|
|
if (!this.cart) return [];
|
|
|
|
return this.cart.data.relationships.variants.data
|
|
.map((x) => JSON.parse(this.storage.getItem(`cart:item:${x.id}`)))
|
|
.filter((x) => x !== null);
|
|
}
|
|
|
|
/*
|
|
* The storage
|
|
*/
|
|
get storage() {
|
|
return window.localStorage;
|
|
}
|
|
|
|
/*
|
|
* Temporary storage
|
|
*/
|
|
get storageTemp() {
|
|
return window.sessionStorage;
|
|
}
|
|
|
|
get cart() {
|
|
return JSON.parse(this.storage.getItem("cart"));
|
|
}
|
|
|
|
set cart(response) {
|
|
this.storage.setItem("cart", JSON.stringify(response.success()));
|
|
}
|
|
|
|
get email() {
|
|
return this.storageTemp.getItem("email");
|
|
}
|
|
|
|
set email(email) {
|
|
this.storageTemp.setItem("email", email);
|
|
}
|
|
|
|
/*
|
|
* The orderToken
|
|
*
|
|
* @return [String]
|
|
*/
|
|
get token() {
|
|
return this.storage.getItem("token");
|
|
}
|
|
|
|
/*
|
|
* The bearerToken
|
|
*
|
|
* @return [String]
|
|
*/
|
|
get bearerToken() {
|
|
return this.storageTemp.getItem("bearerToken");
|
|
}
|
|
|
|
set bearerToken(token) {
|
|
this.storageTemp.setItem("bearerToken", token);
|
|
}
|
|
|
|
/*
|
|
* Liquid renderer
|
|
*
|
|
* @return Liquid
|
|
*/
|
|
get engine() {
|
|
if (!window.liquid) window.liquid = new Liquid();
|
|
|
|
return window.liquid;
|
|
}
|
|
|
|
/*
|
|
* Updates the item counter
|
|
*/
|
|
counterUpdate() {
|
|
const item_count = this.cart.data.attributes.item_count;
|
|
|
|
window.dispatchEvent(
|
|
new CustomEvent("cart:counter", { detail: { item_count } })
|
|
);
|
|
this.storage.setItem("cart:counter", item_count);
|
|
}
|
|
|
|
/*
|
|
* Removes the brackets from the name or returns the name
|
|
*
|
|
* @return [String]
|
|
*/
|
|
idFromInputName(input) {
|
|
const matches = input.name.match(/\[([^\]]+)\]$/);
|
|
|
|
return matches === null ? input.name : matches[1];
|
|
}
|
|
|
|
async handleFailure(response) {
|
|
const data = { type: "primary" };
|
|
let template = "alert";
|
|
let notify = true;
|
|
|
|
const site = window.site;
|
|
const fail = response.fail();
|
|
|
|
switch (fail.name) {
|
|
case "MisconfigurationError":
|
|
data.content = fail.message;
|
|
break;
|
|
case "NoResponseError":
|
|
data.content = site.i18n.alerts.no_response_error;
|
|
break;
|
|
case "SpreeError":
|
|
data.content = site.i18n.alerts.spree_error;
|
|
break;
|
|
case "BasicSpreeError":
|
|
// XXX: The order is missing, we need to start a new one
|
|
if (fail.serverResponse.status === 404) {
|
|
template = "recover_order";
|
|
data.content = site.i18n.alerts.recover_order;
|
|
} else {
|
|
data.content = response.fail().summary;
|
|
}
|
|
|
|
break;
|
|
case "ExpandedSpreeError":
|
|
const content = [];
|
|
// XXX: La API devuelve los mensajes de error tal cual en la
|
|
// llave `error` pero el cliente solo nos da acceso a `errors`.
|
|
for (const field of Object.keys(fail.errors)) {
|
|
if (!site.i18n.errors?.fields[field]) {
|
|
console.error("El campo no tiene traducción", field);
|
|
}
|
|
|
|
content.push(
|
|
`${site.i18n.errors?.fields[field]}: ${fail.errors[field].join(
|
|
", "
|
|
)}`
|
|
);
|
|
}
|
|
|
|
data.content = content.join(". ");
|
|
notify = false;
|
|
|
|
break;
|
|
default:
|
|
data.content = fail.message;
|
|
}
|
|
|
|
if (notify) console.error(fail.name, data.content);
|
|
window.dispatchEvent(
|
|
new CustomEvent("notification", { detail: { template, data } })
|
|
);
|
|
}
|
|
|
|
set formDisabled(state) {
|
|
if (!this.hasFormTarget) return;
|
|
|
|
this.formTarget.elements.forEach((x) => (x.disabled = !!state));
|
|
}
|
|
|
|
assignShippingAddress() {
|
|
if (!this.bearerToken) return;
|
|
|
|
const bearerToken = this.bearerToken;
|
|
const orderToken = this.token;
|
|
|
|
this.spree.sutty.assignOrderShippingAddress(
|
|
{ bearerToken },
|
|
{ orderToken }
|
|
);
|
|
}
|
|
|
|
notify(data = {}) {
|
|
window.dispatchEvent(
|
|
new CustomEvent("notification", { detail: { template: "alert", data } })
|
|
);
|
|
}
|
|
|
|
/*
|
|
* Visita una página con soporte para Turbolinks
|
|
*
|
|
* @param [String] URL
|
|
*/
|
|
visit(url) {
|
|
try {
|
|
Turbolinks.visit(url);
|
|
} catch {
|
|
window.location = url;
|
|
}
|
|
}
|
|
|
|
async firstAddress(bearerToken) {
|
|
if (!this._firstAddress) {
|
|
const addresses = await this.spree.account.addressesList({ bearerToken });
|
|
|
|
if (addresses.isFail()) {
|
|
this.handleFailure(addresses);
|
|
return;
|
|
}
|
|
|
|
// XXX: Asumimos que si se registró tiene una dirección que vamos
|
|
// a actualizar.
|
|
this._firstAddress = addresses.success().data[0];
|
|
}
|
|
|
|
return this._firstAddress;
|
|
}
|
|
|
|
async updateAddress(bearerToken, id, address) {
|
|
const updateAddress = await this.spree.account.updateAddress(
|
|
{ bearerToken },
|
|
id,
|
|
{ address }
|
|
);
|
|
|
|
if (updateAddress.isFail()) {
|
|
this.handleFailure(updateAddress);
|
|
return;
|
|
}
|
|
|
|
return updateAddress.success();
|
|
}
|
|
|
|
async shippingMethods(orderToken) {
|
|
const shippingMethods = await this.spree.checkout.shippingMethods(
|
|
{ orderToken },
|
|
{ include: "shipping_rates" }
|
|
);
|
|
|
|
if (shippingMethods.isFail()) {
|
|
this.handleFailure(shippingMethods);
|
|
return;
|
|
}
|
|
|
|
return shippingMethods.success();
|
|
}
|
|
|
|
fireCajon(state = "open", cajon = "cajon") {
|
|
window.dispatchEvent(
|
|
new CustomEvent("cajon", { detail: { cajon, state } })
|
|
);
|
|
}
|
|
|
|
formDataToObject(formData) {
|
|
const object = {};
|
|
|
|
for (const field of formData) {
|
|
if (field[0].startsWith("_ignore_")) continue;
|
|
|
|
object[field[0]] = field[1];
|
|
}
|
|
|
|
return object;
|
|
}
|
|
}
|