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 } }