prettificar
This commit is contained in:
parent
ef29848cfa
commit
ccdf831dac
25 changed files with 1290 additions and 911 deletions
|
@ -1,13 +1,13 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
import { Liquid } from 'liquidjs'
|
import { Liquid } from "liquidjs";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Base controller, shared methods go here and other classes extend from
|
* Base controller, shared methods go here and other classes extend from
|
||||||
* this.
|
* this.
|
||||||
*/
|
*/
|
||||||
export class CartBaseController extends Controller {
|
export class CartBaseController extends Controller {
|
||||||
get spree () {
|
get spree() {
|
||||||
return window.spree
|
return window.spree;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -15,40 +15,42 @@ export class CartBaseController extends Controller {
|
||||||
*
|
*
|
||||||
* @return [Array]
|
* @return [Array]
|
||||||
*/
|
*/
|
||||||
get products () {
|
get products() {
|
||||||
if (!this.cart) return []
|
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)
|
return this.cart.data.relationships.variants.data
|
||||||
|
.map((x) => JSON.parse(this.storage.getItem(`cart:item:${x.id}`)))
|
||||||
|
.filter((x) => x !== null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The storage
|
* The storage
|
||||||
*/
|
*/
|
||||||
get storage () {
|
get storage() {
|
||||||
return window.localStorage
|
return window.localStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Temporary storage
|
* Temporary storage
|
||||||
*/
|
*/
|
||||||
get storageTemp () {
|
get storageTemp() {
|
||||||
return window.sessionStorage
|
return window.sessionStorage;
|
||||||
}
|
}
|
||||||
|
|
||||||
get cart () {
|
get cart() {
|
||||||
return JSON.parse(this.storage.getItem('cart'))
|
return JSON.parse(this.storage.getItem("cart"));
|
||||||
}
|
}
|
||||||
|
|
||||||
set cart (response) {
|
set cart(response) {
|
||||||
this.storage.setItem('cart', JSON.stringify(response.success()))
|
this.storage.setItem("cart", JSON.stringify(response.success()));
|
||||||
}
|
}
|
||||||
|
|
||||||
get email () {
|
get email() {
|
||||||
return this.storageTemp.getItem('email')
|
return this.storageTemp.getItem("email");
|
||||||
}
|
}
|
||||||
|
|
||||||
set email (email) {
|
set email(email) {
|
||||||
this.storageTemp.setItem('email', email)
|
this.storageTemp.setItem("email", email);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -56,8 +58,8 @@ export class CartBaseController extends Controller {
|
||||||
*
|
*
|
||||||
* @return [String]
|
* @return [String]
|
||||||
*/
|
*/
|
||||||
get token () {
|
get token() {
|
||||||
return this.storage.getItem('token')
|
return this.storage.getItem("token");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -65,12 +67,12 @@ export class CartBaseController extends Controller {
|
||||||
*
|
*
|
||||||
* @return [String]
|
* @return [String]
|
||||||
*/
|
*/
|
||||||
get bearerToken () {
|
get bearerToken() {
|
||||||
return this.storageTemp.getItem('bearerToken')
|
return this.storageTemp.getItem("bearerToken");
|
||||||
}
|
}
|
||||||
|
|
||||||
set bearerToken (token) {
|
set bearerToken(token) {
|
||||||
this.storageTemp.setItem('bearerToken', token)
|
this.storageTemp.setItem("bearerToken", token);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -78,20 +80,22 @@ export class CartBaseController extends Controller {
|
||||||
*
|
*
|
||||||
* @return Liquid
|
* @return Liquid
|
||||||
*/
|
*/
|
||||||
get engine () {
|
get engine() {
|
||||||
if (!window.liquid) window.liquid = new Liquid()
|
if (!window.liquid) window.liquid = new Liquid();
|
||||||
|
|
||||||
return window.liquid
|
return window.liquid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Updates the item counter
|
* Updates the item counter
|
||||||
*/
|
*/
|
||||||
counterUpdate () {
|
counterUpdate() {
|
||||||
const item_count = this.cart.data.attributes.item_count
|
const item_count = this.cart.data.attributes.item_count;
|
||||||
|
|
||||||
window.dispatchEvent(new CustomEvent('cart:counter', { detail: { item_count }}))
|
window.dispatchEvent(
|
||||||
this.storage.setItem('cart:counter', item_count)
|
new CustomEvent("cart:counter", { detail: { item_count } })
|
||||||
|
);
|
||||||
|
this.storage.setItem("cart:counter", item_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -99,81 +103,92 @@ export class CartBaseController extends Controller {
|
||||||
*
|
*
|
||||||
* @return [String]
|
* @return [String]
|
||||||
*/
|
*/
|
||||||
idFromInputName (input) {
|
idFromInputName(input) {
|
||||||
const matches = input.name.match(/\[([^\]]+)\]$/)
|
const matches = input.name.match(/\[([^\]]+)\]$/);
|
||||||
|
|
||||||
return (matches === null) ? input.name : matches[1]
|
return matches === null ? input.name : matches[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleFailure (response) {
|
async handleFailure(response) {
|
||||||
const data = { type: 'primary' }
|
const data = { type: "primary" };
|
||||||
let template = 'alert'
|
let template = "alert";
|
||||||
let notify = true
|
let notify = true;
|
||||||
|
|
||||||
const site = window.site
|
const site = window.site;
|
||||||
const fail = response.fail()
|
const fail = response.fail();
|
||||||
|
|
||||||
switch (fail.name) {
|
switch (fail.name) {
|
||||||
case 'MisconfigurationError':
|
case "MisconfigurationError":
|
||||||
data.content = fail.message
|
data.content = fail.message;
|
||||||
break
|
break;
|
||||||
case 'NoResponseError':
|
case "NoResponseError":
|
||||||
data.content = site.i18n.alerts.no_response_error
|
data.content = site.i18n.alerts.no_response_error;
|
||||||
break
|
break;
|
||||||
case 'SpreeError':
|
case "SpreeError":
|
||||||
data.content = site.i18n.alerts.spree_error
|
data.content = site.i18n.alerts.spree_error;
|
||||||
break
|
break;
|
||||||
case 'BasicSpreeError':
|
case "BasicSpreeError":
|
||||||
// XXX: The order is missing, we need to start a new one
|
// XXX: The order is missing, we need to start a new one
|
||||||
if (fail.serverResponse.status === 404) {
|
if (fail.serverResponse.status === 404) {
|
||||||
template = 'recover_order'
|
template = "recover_order";
|
||||||
data.content = site.i18n.alerts.recover_order
|
data.content = site.i18n.alerts.recover_order;
|
||||||
} else {
|
} else {
|
||||||
data.content = response.fail().summary
|
data.content = response.fail().summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break;
|
||||||
case 'ExpandedSpreeError':
|
case "ExpandedSpreeError":
|
||||||
const content = []
|
const content = [];
|
||||||
// XXX: La API devuelve los mensajes de error tal cual en la
|
// XXX: La API devuelve los mensajes de error tal cual en la
|
||||||
// llave `error` pero el cliente solo nos da acceso a `errors`.
|
// llave `error` pero el cliente solo nos da acceso a `errors`.
|
||||||
for (const field of Object.keys(fail.errors)) {
|
for (const field of Object.keys(fail.errors)) {
|
||||||
if (!site.i18n.errors?.fields[field]) {
|
if (!site.i18n.errors?.fields[field]) {
|
||||||
console.error('El campo no tiene traducción', field)
|
console.error("El campo no tiene traducción", field);
|
||||||
}
|
}
|
||||||
|
|
||||||
content.push(`${site.i18n.errors?.fields[field]}: ${fail.errors[field].join(', ')}`)
|
content.push(
|
||||||
|
`${site.i18n.errors?.fields[field]}: ${fail.errors[field].join(
|
||||||
|
", "
|
||||||
|
)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
data.content = content.join('. ')
|
data.content = content.join(". ");
|
||||||
notify = false
|
notify = false;
|
||||||
|
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
data.content = fail.message
|
data.content = fail.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notify) console.error(fail.name, data.content)
|
if (notify) console.error(fail.name, data.content);
|
||||||
window.dispatchEvent(new CustomEvent('notification', { detail: { template, data } }))
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("notification", { detail: { template, data } })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
set formDisabled (state) {
|
set formDisabled(state) {
|
||||||
if (!this.hasFormTarget) return
|
if (!this.hasFormTarget) return;
|
||||||
|
|
||||||
this.formTarget.elements.forEach(x => x.disabled = !!state)
|
this.formTarget.elements.forEach((x) => (x.disabled = !!state));
|
||||||
}
|
}
|
||||||
|
|
||||||
assignShippingAddress () {
|
assignShippingAddress() {
|
||||||
if (!this.bearerToken) return
|
if (!this.bearerToken) return;
|
||||||
|
|
||||||
const bearerToken = this.bearerToken
|
const bearerToken = this.bearerToken;
|
||||||
const orderToken = this.token
|
const orderToken = this.token;
|
||||||
|
|
||||||
this.spree.sutty.assignOrderShippingAddress({ bearerToken }, { orderToken })
|
this.spree.sutty.assignOrderShippingAddress(
|
||||||
|
{ bearerToken },
|
||||||
|
{ orderToken }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
notify (data = {}) {
|
notify(data = {}) {
|
||||||
window.dispatchEvent(new CustomEvent('notification', { detail: { template: 'alert', data } }))
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("notification", { detail: { template: "alert", data } })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -181,66 +196,75 @@ export class CartBaseController extends Controller {
|
||||||
*
|
*
|
||||||
* @param [String] URL
|
* @param [String] URL
|
||||||
*/
|
*/
|
||||||
visit (url) {
|
visit(url) {
|
||||||
try {
|
try {
|
||||||
Turbolinks.visit(url)
|
Turbolinks.visit(url);
|
||||||
} catch {
|
} catch {
|
||||||
window.location = url
|
window.location = url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async firstAddress (bearerToken) {
|
async firstAddress(bearerToken) {
|
||||||
if (!this._firstAddress) {
|
if (!this._firstAddress) {
|
||||||
const addresses = await this.spree.account.addressesList({ bearerToken })
|
const addresses = await this.spree.account.addressesList({ bearerToken });
|
||||||
|
|
||||||
if (addresses.isFail()) {
|
if (addresses.isFail()) {
|
||||||
this.handleFailure(addresses)
|
this.handleFailure(addresses);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX: Asumimos que si se registró tiene una dirección que vamos
|
// XXX: Asumimos que si se registró tiene una dirección que vamos
|
||||||
// a actualizar.
|
// a actualizar.
|
||||||
this._firstAddress = addresses.success().data[0]
|
this._firstAddress = addresses.success().data[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._firstAddress
|
return this._firstAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateAddress(bearerToken, id, address) {
|
async updateAddress(bearerToken, id, address) {
|
||||||
const updateAddress = await this.spree.account.updateAddress({ bearerToken }, id, { address })
|
const updateAddress = await this.spree.account.updateAddress(
|
||||||
|
{ bearerToken },
|
||||||
|
id,
|
||||||
|
{ address }
|
||||||
|
);
|
||||||
|
|
||||||
if (updateAddress.isFail()) {
|
if (updateAddress.isFail()) {
|
||||||
this.handleFailure(updateAddress)
|
this.handleFailure(updateAddress);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return updateAddress.success()
|
return updateAddress.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
async shippingMethods(orderToken) {
|
async shippingMethods(orderToken) {
|
||||||
const shippingMethods = await this.spree.checkout.shippingMethods({ orderToken }, { include: 'shipping_rates' })
|
const shippingMethods = await this.spree.checkout.shippingMethods(
|
||||||
|
{ orderToken },
|
||||||
|
{ include: "shipping_rates" }
|
||||||
|
);
|
||||||
|
|
||||||
if (shippingMethods.isFail()) {
|
if (shippingMethods.isFail()) {
|
||||||
this.handleFailure(shippingMethods)
|
this.handleFailure(shippingMethods);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return shippingMethods.success()
|
return shippingMethods.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
fireCajon (state = 'open', cajon = 'cajon') {
|
fireCajon(state = "open", cajon = "cajon") {
|
||||||
window.dispatchEvent(new CustomEvent('cajon', { detail: { cajon, state }}))
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("cajon", { detail: { cajon, state } })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
formDataToObject (formData) {
|
formDataToObject(formData) {
|
||||||
const object = {}
|
const object = {};
|
||||||
|
|
||||||
for (const field of formData) {
|
for (const field of formData) {
|
||||||
if (field[0].startsWith('_ignore_')) continue
|
if (field[0].startsWith("_ignore_")) continue;
|
||||||
|
|
||||||
object[field[0]] = field[1]
|
object[field[0]] = field[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
return object
|
return object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +1,47 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
static targets = [ 'order' ]
|
static targets = ["order"];
|
||||||
|
|
||||||
async connect () {
|
async connect() {
|
||||||
if (this.clear) {
|
if (this.clear) {
|
||||||
this.storage.clear()
|
this.storage.clear();
|
||||||
window.dispatchEvent(new CustomEvent('cart:counter', { detail: { item_count: 0 }}))
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("cart:counter", { detail: { item_count: 0 } })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.template) return
|
if (!this.template) return;
|
||||||
|
|
||||||
if (this.storage.cart) {
|
if (this.storage.cart) {
|
||||||
const order = this.cart.data.attributes
|
const order = this.cart.data.attributes;
|
||||||
const products = this.products
|
const products = this.products;
|
||||||
const site = window.site
|
const site = window.site;
|
||||||
const shipping_address = JSON.parse(this.storage.getItem('shipping_address'))
|
const shipping_address = JSON.parse(
|
||||||
|
this.storage.getItem("shipping_address")
|
||||||
|
);
|
||||||
|
|
||||||
const data = { order, products, site, shipping_address }
|
const data = { order, products, site, shipping_address };
|
||||||
|
|
||||||
this.storage.setItem('confirmation', JSON.stringify(data))
|
this.storage.setItem("confirmation", JSON.stringify(data));
|
||||||
} else {
|
} else {
|
||||||
data = JSON.parse(this.storage.getItem('confirmation'))
|
data = JSON.parse(this.storage.getItem("confirmation"));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.render(data)
|
this.render(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
render (data = {}) {
|
render(data = {}) {
|
||||||
this.engine.parseAndRender(this.template, data).then(html => this.orderTarget.innerHTML = html)
|
this.engine
|
||||||
|
.parseAndRender(this.template, data)
|
||||||
|
.then((html) => (this.orderTarget.innerHTML = html));
|
||||||
}
|
}
|
||||||
|
|
||||||
get clear () {
|
get clear() {
|
||||||
return this.element.dataset.clear
|
return this.element.dataset.clear;
|
||||||
}
|
}
|
||||||
|
|
||||||
get template () {
|
get template() {
|
||||||
return window.templates[this.element.dataset.template]
|
return window.templates[this.element.dataset.template];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
static targets = [ 'form', 'username' ]
|
static targets = ["form", "username"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
if (!this.hasUsernameTarget) return
|
if (!this.hasUsernameTarget) return;
|
||||||
if (!this.hasFormTarget) return
|
if (!this.hasFormTarget) return;
|
||||||
|
|
||||||
this.formTarget.addEventListener('focusout', event => {
|
this.formTarget.addEventListener("focusout", (event) => {
|
||||||
if (!this.formTarget.checkValidity()) {
|
if (!this.formTarget.checkValidity()) {
|
||||||
this.formTarget.classList.add('was-validated')
|
this.formTarget.classList.add("was-validated");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.formTarget.classList.remove('was-validated')
|
this.formTarget.classList.remove("was-validated");
|
||||||
|
|
||||||
const username = this.usernameTarget.value.trim()
|
const username = this.usernameTarget.value.trim();
|
||||||
if (username.length === 0) return
|
if (username.length === 0) return;
|
||||||
|
|
||||||
this.email = username
|
this.email = username;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Manages the cart and its contents.
|
* Manages the cart and its contents.
|
||||||
|
@ -17,10 +17,10 @@ import { CartBaseController } from './cart_base_controller'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
static targets = [ 'quantity', 'subtotal', 'addedQuantity' ]
|
static targets = ["quantity", "subtotal", "addedQuantity"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
if (!this.hasQuantityTarget) return
|
if (!this.hasQuantityTarget) return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When the quantity selector changes, we update the order to have
|
* When the quantity selector changes, we update the order to have
|
||||||
|
@ -28,47 +28,51 @@ export default class extends CartBaseController {
|
||||||
*
|
*
|
||||||
* TODO: Go back to previous amount if there's not enough.
|
* TODO: Go back to previous amount if there's not enough.
|
||||||
*/
|
*/
|
||||||
this.quantityTarget.addEventListener('change', async (event) => {
|
this.quantityTarget.addEventListener("change", async (event) => {
|
||||||
const quantity = event.target.value
|
const quantity = event.target.value;
|
||||||
|
|
||||||
if (quantity < 1) return;
|
if (quantity < 1) return;
|
||||||
|
|
||||||
const orderToken = await this.tokenGetOrCreate()
|
const orderToken = await this.tokenGetOrCreate();
|
||||||
const product = this.product
|
const product = this.product;
|
||||||
|
|
||||||
if (!product) return
|
if (!product) return;
|
||||||
|
|
||||||
event.target.disabled = true
|
event.target.disabled = true;
|
||||||
|
|
||||||
const response = await this.spree.cart.setQuantity({ orderToken }, {
|
const response = await this.spree.cart.setQuantity(
|
||||||
|
{ orderToken },
|
||||||
|
{
|
||||||
line_item_id: product.line_item.id,
|
line_item_id: product.line_item.id,
|
||||||
quantity,
|
quantity,
|
||||||
include: 'line_items'
|
include: "line_items",
|
||||||
})
|
}
|
||||||
|
);
|
||||||
|
|
||||||
event.target.disabled = false
|
event.target.disabled = false;
|
||||||
event.target.focus()
|
event.target.focus();
|
||||||
|
|
||||||
// If we're failing here it could be due to a missing order, so we
|
// If we're failing here it could be due to a missing order, so we
|
||||||
// ask the user to decide what they want to do about it
|
// ask the user to decide what they want to do about it
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cart = response
|
this.cart = response;
|
||||||
this.subtotalUpdate()
|
this.subtotalUpdate();
|
||||||
this.counterUpdate()
|
this.counterUpdate();
|
||||||
await this.itemStore()
|
await this.itemStore();
|
||||||
|
|
||||||
if (!this.hasSubtotalTarget) return
|
if (!this.hasSubtotalTarget) return;
|
||||||
|
|
||||||
this.subtotalTarget.innerText = product.line_item.attributes.discounted_amount
|
this.subtotalTarget.innerText =
|
||||||
})
|
product.line_item.attributes.discounted_amount;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
subtotalUpdate () {
|
subtotalUpdate() {
|
||||||
window.dispatchEvent(new Event('cart:subtotal:update'))
|
window.dispatchEvent(new Event("cart:subtotal:update"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -76,20 +80,20 @@ export default class extends CartBaseController {
|
||||||
*
|
*
|
||||||
* @return [String]
|
* @return [String]
|
||||||
*/
|
*/
|
||||||
async cartCreate () {
|
async cartCreate() {
|
||||||
const response = await this.spree.cart.create()
|
const response = await this.spree.cart.create();
|
||||||
|
|
||||||
// If we fail here it's probably a server error, so we inform the
|
// If we fail here it's probably a server error, so we inform the
|
||||||
// user.
|
// user.
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cart = response
|
this.cart = response;
|
||||||
this.storage.setItem('token', response.success().data.attributes.token)
|
this.storage.setItem("token", response.success().data.attributes.token);
|
||||||
|
|
||||||
return this.token
|
return this.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -97,10 +101,10 @@ export default class extends CartBaseController {
|
||||||
*
|
*
|
||||||
* @return [String]
|
* @return [String]
|
||||||
*/
|
*/
|
||||||
async tokenGetOrCreate () {
|
async tokenGetOrCreate() {
|
||||||
let token = this.storage.getItem('token')
|
let token = this.storage.getItem("token");
|
||||||
|
|
||||||
return token || await this.cartCreate()
|
return token || (await this.cartCreate());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -108,18 +112,23 @@ export default class extends CartBaseController {
|
||||||
*
|
*
|
||||||
* @return [String]
|
* @return [String]
|
||||||
*/
|
*/
|
||||||
get variantId () {
|
get variantId() {
|
||||||
return this.data.get('variantId')
|
return this.data.get("variantId");
|
||||||
}
|
}
|
||||||
|
|
||||||
get product () {
|
get product() {
|
||||||
const product = JSON.parse(this.storage.getItem(this.storageId))
|
const product = JSON.parse(this.storage.getItem(this.storageId));
|
||||||
|
|
||||||
if (!product) {
|
if (!product) {
|
||||||
console.error("El producto es nulo!", this.storageId, this.storage.length, this.cart)
|
console.error(
|
||||||
|
"El producto es nulo!",
|
||||||
|
this.storageId,
|
||||||
|
this.storage.length,
|
||||||
|
this.cart
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return product
|
return product;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -128,14 +137,18 @@ export default class extends CartBaseController {
|
||||||
*
|
*
|
||||||
* @return [Object]
|
* @return [Object]
|
||||||
*/
|
*/
|
||||||
findLineItem () {
|
findLineItem() {
|
||||||
const line_item = this.cart.included.find(x => (x.type === 'line_item' && x.relationships.variant.data.id == this.variantId))
|
const line_item = this.cart.included.find(
|
||||||
|
(x) =>
|
||||||
|
x.type === "line_item" &&
|
||||||
|
x.relationships.variant.data.id == this.variantId
|
||||||
|
);
|
||||||
|
|
||||||
return (line_item || {})
|
return line_item || {};
|
||||||
}
|
}
|
||||||
|
|
||||||
get storageId () {
|
get storageId() {
|
||||||
return `cart:item:${this.variantId}`
|
return `cart:item:${this.variantId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -143,17 +156,20 @@ export default class extends CartBaseController {
|
||||||
*
|
*
|
||||||
* @see {./order_controller.js}
|
* @see {./order_controller.js}
|
||||||
*/
|
*/
|
||||||
itemStore () {
|
itemStore() {
|
||||||
this.storage.setItem(this.storageId, JSON.stringify({
|
this.storage.setItem(
|
||||||
|
this.storageId,
|
||||||
|
JSON.stringify({
|
||||||
variant_id: this.variantId,
|
variant_id: this.variantId,
|
||||||
line_item: this.findLineItem(),
|
line_item: this.findLineItem(),
|
||||||
image: this.data.get('image'),
|
image: this.data.get("image"),
|
||||||
title: this.data.get('title'),
|
title: this.data.get("title"),
|
||||||
url: this.data.get('url'),
|
url: this.data.get("url"),
|
||||||
stock: this.data.get('stock'),
|
stock: this.data.get("stock"),
|
||||||
in_stock: this.data.get('inStock'),
|
in_stock: this.data.get("inStock"),
|
||||||
extra: this.data.get('extra') ? this.data.get('extra').split('|') : []
|
extra: this.data.get("extra") ? this.data.get("extra").split("|") : [],
|
||||||
}))
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -164,26 +180,31 @@ export default class extends CartBaseController {
|
||||||
* The item needs a variant ID to be added.
|
* The item needs a variant ID to be added.
|
||||||
*/
|
*/
|
||||||
async add(event, quantity = 1, floating_alert = true) {
|
async add(event, quantity = 1, floating_alert = true) {
|
||||||
const addedQuantity = this.addedQuantity()
|
const addedQuantity = this.addedQuantity();
|
||||||
if (addedQuantity > 1) quantity = addedQuantity
|
if (addedQuantity > 1) quantity = addedQuantity;
|
||||||
|
|
||||||
const orderToken = await this.tokenGetOrCreate()
|
const orderToken = await this.tokenGetOrCreate();
|
||||||
const response = await this.spree.cart.addItem({ orderToken }, { variant_id: this.variantId, quantity, include: 'line_items' })
|
const response = await this.spree.cart.addItem(
|
||||||
|
{ orderToken },
|
||||||
|
{ variant_id: this.variantId, quantity, include: "line_items" }
|
||||||
|
);
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cart = response
|
this.cart = response;
|
||||||
this.itemStore()
|
this.itemStore();
|
||||||
this.counterUpdate()
|
this.counterUpdate();
|
||||||
this.fireCajon()
|
this.fireCajon();
|
||||||
|
|
||||||
if (floating_alert) {
|
if (floating_alert) {
|
||||||
const site = window.site
|
const site = window.site;
|
||||||
const content = site.cart.added
|
const content = site.cart.added;
|
||||||
window.dispatchEvent(new CustomEvent('floating:alert', { detail: { content }}))
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("floating:alert", { detail: { content } })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,92 +212,98 @@ export default class extends CartBaseController {
|
||||||
* Remove the element from the cart. It contacts the API and if the
|
* Remove the element from the cart. It contacts the API and if the
|
||||||
* item is removed, it removes itself from the page and the storage.
|
* item is removed, it removes itself from the page and the storage.
|
||||||
*/
|
*/
|
||||||
async remove () {
|
async remove() {
|
||||||
const product = this.product
|
const product = this.product;
|
||||||
|
|
||||||
if (!product) return
|
if (!product) return;
|
||||||
if (!product.line_item) return
|
if (!product.line_item) return;
|
||||||
|
|
||||||
const orderToken = this.token
|
const orderToken = this.token;
|
||||||
const response = await this.spree.cart.removeItem({ orderToken }, product.line_item.id, { include: 'line_items' })
|
const response = await this.spree.cart.removeItem(
|
||||||
|
{ orderToken },
|
||||||
|
product.line_item.id,
|
||||||
|
{ include: "line_items" }
|
||||||
|
);
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cart = response
|
this.cart = response;
|
||||||
this.storage.removeItem(this.storageId)
|
this.storage.removeItem(this.storageId);
|
||||||
this.element.remove()
|
this.element.remove();
|
||||||
this.subtotalUpdate()
|
this.subtotalUpdate();
|
||||||
this.counterUpdate()
|
this.counterUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shows variants
|
* Shows variants
|
||||||
*/
|
*/
|
||||||
async variants () {
|
async variants() {
|
||||||
const template = 'variants'
|
const template = "variants";
|
||||||
const data = {
|
const data = {
|
||||||
product: {
|
product: {
|
||||||
variant_id: this.data.get('variantId'),
|
variant_id: this.data.get("variantId"),
|
||||||
digital_variant_id: this.data.get('digitalVariantId'),
|
digital_variant_id: this.data.get("digitalVariantId"),
|
||||||
image: this.data.get('image'),
|
image: this.data.get("image"),
|
||||||
title: this.data.get('title'),
|
title: this.data.get("title"),
|
||||||
price: this.data.get('price'),
|
price: this.data.get("price"),
|
||||||
digital_price: this.data.get('digitalPrice'),
|
digital_price: this.data.get("digitalPrice"),
|
||||||
in_stock: this.data.get('inStock'),
|
in_stock: this.data.get("inStock"),
|
||||||
extra: this.data.get('extra').split('|')
|
extra: this.data.get("extra").split("|"),
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
window.dispatchEvent(new CustomEvent('notification', { detail: { template, data } }))
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("notification", { detail: { template, data } })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Recovers the order if something failed
|
* Recovers the order if something failed
|
||||||
*/
|
*/
|
||||||
async recover () {
|
async recover() {
|
||||||
console.error('Recuperando pedido', this.token)
|
console.error("Recuperando pedido", this.token);
|
||||||
|
|
||||||
// Removes the failing token
|
// Removes the failing token
|
||||||
this.storage.removeItem('token')
|
this.storage.removeItem("token");
|
||||||
|
|
||||||
// Get a new token and cart
|
// Get a new token and cart
|
||||||
await this.tokenGetOrCreate()
|
await this.tokenGetOrCreate();
|
||||||
|
|
||||||
// Stores the previous cart
|
// Stores the previous cart
|
||||||
const cart = this.cart
|
const cart = this.cart;
|
||||||
|
|
||||||
if (!cart) return
|
if (!cart) return;
|
||||||
|
|
||||||
// Add previous items and their quantities to the new cart by
|
// Add previous items and their quantities to the new cart by
|
||||||
// mimicking user's actions
|
// mimicking user's actions
|
||||||
//
|
//
|
||||||
// XXX: We don't use forEach because it's not async
|
// XXX: We don't use forEach because it's not async
|
||||||
for (const variant of cart.data.relationships.variants.data) {
|
for (const variant of cart.data.relationships.variants.data) {
|
||||||
this.data.set('variantId', variant.id)
|
this.data.set("variantId", variant.id);
|
||||||
|
|
||||||
const product = this.product
|
const product = this.product;
|
||||||
|
|
||||||
if (!product) continue
|
if (!product) continue;
|
||||||
|
|
||||||
this.data.set('image', product.image)
|
this.data.set("image", product.image);
|
||||||
this.data.set('title', product.title)
|
this.data.set("title", product.title);
|
||||||
this.data.set('extra', product.extra.join('|'))
|
this.data.set("extra", product.extra.join("|"));
|
||||||
|
|
||||||
await this.add(null, product.line_item.attributes.quantity, false)
|
await this.add(null, product.line_item.attributes.quantity, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Si le compradore aumenta la cantidad antes de agregar
|
* Si le compradore aumenta la cantidad antes de agregar
|
||||||
*/
|
*/
|
||||||
addedQuantity () {
|
addedQuantity() {
|
||||||
if (!this.hasAddedQuantityTarget) return 0
|
if (!this.hasAddedQuantityTarget) return 0;
|
||||||
|
|
||||||
const addedQuantity = parseInt(this.addedQuantityTarget.value)
|
const addedQuantity = parseInt(this.addedQuantityTarget.value);
|
||||||
|
|
||||||
return (isNaN(addedQuantity) ? 0 : addedQuantity)
|
return isNaN(addedQuantity) ? 0 : addedQuantity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,28 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
static targets = [ 'counter' ]
|
static targets = ["counter"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
if (!this.hasCounterTarget) {
|
if (!this.hasCounterTarget) {
|
||||||
console.error("Missing counter target")
|
console.error("Missing counter target");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('cart:counter', event => this.counter = event.detail.item_count)
|
window.addEventListener(
|
||||||
window.addEventListener('storage', event => {
|
"cart:counter",
|
||||||
if (event.key == 'cart:counter') this.counter = event.newValue
|
(event) => (this.counter = event.detail.item_count)
|
||||||
})
|
);
|
||||||
|
window.addEventListener("storage", (event) => {
|
||||||
|
if (event.key == "cart:counter") this.counter = event.newValue;
|
||||||
|
});
|
||||||
|
|
||||||
if (!this.cart) return
|
if (!this.cart) return;
|
||||||
|
|
||||||
this.counter = this.cart.data.attributes.item_count
|
this.counter = this.cart.data.attributes.item_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
set counter (quantity) {
|
set counter(quantity) {
|
||||||
this.counterTarget.innerText = quantity
|
this.counterTarget.innerText = quantity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +1,73 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Retrieves shipping methods
|
* Retrieves shipping methods
|
||||||
*/
|
*/
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
static targets = [ 'couponCodeInvalid', 'preDiscount', 'total' ]
|
static targets = ["couponCodeInvalid", "preDiscount", "total"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
this.couponCode.addEventListener('input', event => {
|
this.couponCode.addEventListener("input", (event) => {
|
||||||
this.couponCode.parentElement.classList.remove('was-validated')
|
this.couponCode.parentElement.classList.remove("was-validated");
|
||||||
this.couponCode.setCustomValidity('')
|
this.couponCode.setCustomValidity("");
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get couponCode () {
|
get couponCode() {
|
||||||
if (!this._couponCode) this._couponCode = this.element.elements.coupon_code
|
if (!this._couponCode) this._couponCode = this.element.elements.coupon_code;
|
||||||
|
|
||||||
return this._couponCode
|
return this._couponCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
get couponCodeInvalid () {
|
get couponCodeInvalid() {
|
||||||
return this.hasCouponCodeInvalidTarget ? this.couponCodeInvalidTarget : document.querySelector('#coupon-code-invalid')
|
return this.hasCouponCodeInvalidTarget
|
||||||
|
? this.couponCodeInvalidTarget
|
||||||
|
: document.querySelector("#coupon-code-invalid");
|
||||||
}
|
}
|
||||||
|
|
||||||
get preDiscount () {
|
get preDiscount() {
|
||||||
return this.hasPreDiscountTarget ? this.preDiscountTarget : document.querySelector('#pre-discount')
|
return this.hasPreDiscountTarget
|
||||||
|
? this.preDiscountTarget
|
||||||
|
: document.querySelector("#pre-discount");
|
||||||
}
|
}
|
||||||
|
|
||||||
get total () {
|
get total() {
|
||||||
return this.hasTotalTarget ? this.totalTarget : document.querySelector('#total')
|
return this.hasTotalTarget
|
||||||
|
? this.totalTarget
|
||||||
|
: document.querySelector("#total");
|
||||||
}
|
}
|
||||||
|
|
||||||
set total (total) {
|
set total(total) {
|
||||||
this.total.innerHTML = total
|
this.total.innerHTML = total;
|
||||||
}
|
}
|
||||||
|
|
||||||
async apply (event = undefined) {
|
async apply(event = undefined) {
|
||||||
event?.preventDefault()
|
event?.preventDefault();
|
||||||
event?.stopPropagation()
|
event?.stopPropagation();
|
||||||
|
|
||||||
const orderToken = this.token
|
const orderToken = this.token;
|
||||||
const coupon_code = this.couponCode.value
|
const coupon_code = this.couponCode.value;
|
||||||
const include = 'line_items'
|
const include = "line_items";
|
||||||
|
|
||||||
const response = await window.spree.cart.applyCouponCode({ orderToken }, { coupon_code, include })
|
const response = await window.spree.cart.applyCouponCode(
|
||||||
|
{ orderToken },
|
||||||
|
{ coupon_code, include }
|
||||||
|
);
|
||||||
|
|
||||||
this.element.elements.forEach(x => x.disabled = true)
|
this.element.elements.forEach((x) => (x.disabled = true));
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.couponCodeInvalid.innerHTML = response.fail().summary
|
this.couponCodeInvalid.innerHTML = response.fail().summary;
|
||||||
this.couponCode.setCustomValidity(response.fail().summary)
|
this.couponCode.setCustomValidity(response.fail().summary);
|
||||||
this.couponCode.parentElement.classList.add('was-validated')
|
this.couponCode.parentElement.classList.add("was-validated");
|
||||||
|
|
||||||
this.element.elements.forEach(x => x.disabled = false)
|
this.element.elements.forEach((x) => (x.disabled = false));
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cart = response
|
this.cart = response;
|
||||||
this.total = response.success().data.attributes.total
|
this.total = response.success().data.attributes.total;
|
||||||
this.preDiscount.classList.remove('d-none')
|
this.preDiscount.classList.remove("d-none");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,88 +1,92 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Retrieves payment methods and redirect to external checkouts
|
* Retrieves payment methods and redirect to external checkouts
|
||||||
*/
|
*/
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
static targets = [ 'form', 'submit', 'specialInstructions' ]
|
static targets = ["form", "submit", "specialInstructions"];
|
||||||
|
|
||||||
async connect () {
|
async connect() {
|
||||||
const orderToken = this.token
|
const orderToken = this.token;
|
||||||
const response = await this.spree.checkout.paymentMethods({ orderToken })
|
const response = await this.spree.checkout.paymentMethods({ orderToken });
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const payment_methods = response.success().data
|
const payment_methods = response.success().data;
|
||||||
const site = window.site
|
const site = window.site;
|
||||||
const cart = this.cart
|
const cart = this.cart;
|
||||||
const next = { url: this.data.get('nextUrl') }
|
const next = { url: this.data.get("nextUrl") };
|
||||||
const back = { url: this.data.get('backUrl') }
|
const back = { url: this.data.get("backUrl") };
|
||||||
|
|
||||||
this.render({ payment_methods, site, cart, next, back })
|
this.render({ payment_methods, site, cart, next, back });
|
||||||
}
|
}
|
||||||
|
|
||||||
async render (data = {}) {
|
async render(data = {}) {
|
||||||
const template = window.templates[this.data.get('template')]
|
const template = window.templates[this.data.get("template")];
|
||||||
|
|
||||||
this.element.innerHTML = await this.engine.parseAndRender(template, data)
|
this.element.innerHTML = await this.engine.parseAndRender(template, data);
|
||||||
|
|
||||||
if (!this.hasSubmitTarget) return
|
if (!this.hasSubmitTarget) return;
|
||||||
this.formTarget.elements.forEach(p => p.addEventListener('change', e => this.submitTarget.disabled = false))
|
this.formTarget.elements.forEach((p) =>
|
||||||
|
p.addEventListener("change", (e) => (this.submitTarget.disabled = false))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async pay (event) {
|
async pay(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
|
|
||||||
this.formDisabled = true
|
this.formDisabled = true;
|
||||||
|
|
||||||
const payment_method_id = this.formTarget.elements.payment_method_id.value
|
const payment_method_id = this.formTarget.elements.payment_method_id.value;
|
||||||
const orderToken = this.token
|
const orderToken = this.token;
|
||||||
const special_instructions = this.specialInstructionsTarget.value.trim()
|
const special_instructions = this.specialInstructionsTarget.value.trim();
|
||||||
|
|
||||||
// XXX: Currently SpreeClient expects us to send payment source
|
// XXX: Currently SpreeClient expects us to send payment source
|
||||||
// attributes as if it were a credit card.
|
// attributes as if it were a credit card.
|
||||||
let response = await this.spree.checkout.orderUpdate({ orderToken },
|
let response = await this.spree.checkout.orderUpdate(
|
||||||
|
{ orderToken },
|
||||||
{
|
{
|
||||||
order: {
|
order: {
|
||||||
special_instructions,
|
special_instructions,
|
||||||
payments_attributes: [{ payment_method_id }] },
|
payments_attributes: [{ payment_method_id }],
|
||||||
payment_source: {
|
payment_source: {
|
||||||
[payment_method_id]: {
|
[payment_method_id]: {
|
||||||
name: 'Pepitx',
|
name: "Pepitx",
|
||||||
month: 12,
|
month: 12,
|
||||||
year: 2020
|
year: 2020,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
this.formDisabled = false
|
this.formDisabled = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cart = response
|
this.cart = response;
|
||||||
|
|
||||||
response = await this.spree.checkout.complete({ orderToken })
|
response = await this.spree.checkout.complete({ orderToken });
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
this.formDisabled = false
|
this.formDisabled = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cart = response
|
this.cart = response;
|
||||||
|
|
||||||
const checkoutUrls = await this.spree.sutty.getCheckoutURL({ orderToken })
|
const checkoutUrls = await this.spree.sutty.getCheckoutURL({ orderToken });
|
||||||
let redirectUrl = this.data.get('nextUrl')
|
let redirectUrl = this.data.get("nextUrl");
|
||||||
|
|
||||||
if (checkoutUrls.data.length > 0) redirectUrl = checkoutUrls.data[0]
|
if (checkoutUrls.data.length > 0) redirectUrl = checkoutUrls.data[0];
|
||||||
|
|
||||||
window.location = redirectUrl
|
window.location = redirectUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replaces checkout.js.
|
* Replaces checkout.js.
|
||||||
|
@ -9,15 +9,22 @@ import { CartBaseController } from './cart_base_controller'
|
||||||
* discarded.
|
* discarded.
|
||||||
*/
|
*/
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
async connect () {
|
async connect() {
|
||||||
if (this.params.PayerID === undefined) return
|
if (this.params.PayerID === undefined) return;
|
||||||
|
|
||||||
this.site = window.site
|
this.site = window.site;
|
||||||
this.element.innerHTML = this.site.i18n.cart.layouts.paypal.confirming
|
this.element.innerHTML = this.site.i18n.cart.layouts.paypal.confirming;
|
||||||
|
|
||||||
fetch(this.executeURL)
|
fetch(this.executeURL)
|
||||||
.then(r => this.element.innerHTML = this.site.i18n.cart.layouts.paypal[(r.ok ? 'confirmed' : 'failure')])
|
.then(
|
||||||
.catch(e => this.element.innerHTML = this.site.i18n.cart.layouts.paypal.failure)
|
(r) =>
|
||||||
|
(this.element.innerHTML =
|
||||||
|
this.site.i18n.cart.layouts.paypal[r.ok ? "confirmed" : "failure"])
|
||||||
|
)
|
||||||
|
.catch(
|
||||||
|
(e) =>
|
||||||
|
(this.element.innerHTML = this.site.i18n.cart.layouts.paypal.failure)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -25,18 +32,29 @@ export default class extends CartBaseController {
|
||||||
*
|
*
|
||||||
* @return [Object]
|
* @return [Object]
|
||||||
*/
|
*/
|
||||||
get params () {
|
get params() {
|
||||||
if (this._params) return this._params
|
if (this._params) return this._params;
|
||||||
|
|
||||||
this._params = Object.fromEntries(decodeURIComponent(window.location.search.replace('?', '')).split('&').map(x => x.split('=')))
|
this._params = Object.fromEntries(
|
||||||
|
decodeURIComponent(window.location.search.replace("?", ""))
|
||||||
|
.split("&")
|
||||||
|
.map((x) => x.split("="))
|
||||||
|
);
|
||||||
|
|
||||||
return this._params
|
return this._params;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* URL to contact the store and execute the payment.
|
* URL to contact the store and execute the payment.
|
||||||
*/
|
*/
|
||||||
get executeURL () {
|
get executeURL() {
|
||||||
return [ window.spree.host, 'paypal', 'execute', this.params.orderId, this.params.paymentId, this.params.PayerID ].join('/')
|
return [
|
||||||
|
window.spree.host,
|
||||||
|
"paypal",
|
||||||
|
"execute",
|
||||||
|
this.params.orderId,
|
||||||
|
this.params.paymentId,
|
||||||
|
this.params.PayerID,
|
||||||
|
].join("/");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,110 +1,127 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
static targets = [ 'methods', 'rates', 'form' ]
|
static targets = ["methods", "rates", "form"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
this.formTarget.addEventListener('formdata', event => this.processShippingAddress(event.formData))
|
this.formTarget.addEventListener("formdata", (event) =>
|
||||||
|
this.processShippingAddress(event.formData)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async rates (event) {
|
async rates(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
|
|
||||||
if (!this.formTarget.checkValidity()) {
|
if (!this.formTarget.checkValidity()) {
|
||||||
this.adressTarget.classList.add('was-validated')
|
this.adressTarget.classList.add("was-validated");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.formTarget.classList.remove('was-validated')
|
this.formTarget.classList.remove("was-validated");
|
||||||
|
|
||||||
// FormDataEvent es muy reciente
|
// FormDataEvent es muy reciente
|
||||||
if (window.FormDataEvent) {
|
if (window.FormDataEvent) {
|
||||||
// Esto lanza el evento formdata en el formulario
|
// Esto lanza el evento formdata en el formulario
|
||||||
new FormData(event.target)
|
new FormData(event.target);
|
||||||
} else {
|
} else {
|
||||||
// Fallback
|
// Fallback
|
||||||
this.processShippingAddress(new FormData(event.target))
|
this.processShippingAddress(new FormData(event.target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
payment (event) {
|
payment(event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
|
|
||||||
// FormDataEvent es muy reciente
|
// FormDataEvent es muy reciente
|
||||||
if (window.FormDataEvent) {
|
if (window.FormDataEvent) {
|
||||||
// Esto lanza el evento formdata en el formulario
|
// Esto lanza el evento formdata en el formulario
|
||||||
new FormData(event.target)
|
new FormData(event.target);
|
||||||
} else {
|
} else {
|
||||||
this.processShippingRate(new FormData(event.target))
|
this.processShippingRate(new FormData(event.target));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async processShippingAddress (formData) {
|
async processShippingAddress(formData) {
|
||||||
this.formDisabled = true
|
this.formDisabled = true;
|
||||||
|
|
||||||
const email = this.email
|
const email = this.email;
|
||||||
const orderToken = this.token
|
const orderToken = this.token;
|
||||||
|
|
||||||
const ship_address_attributes = this.formDataToObject(formData)
|
const ship_address_attributes = this.formDataToObject(formData);
|
||||||
const bill_address_attributes = ship_address_attributes
|
const bill_address_attributes = ship_address_attributes;
|
||||||
|
|
||||||
const response = await this.spree.checkout.orderUpdate({ orderToken }, { order: { email, ship_address_attributes, bill_address_attributes }})
|
const response = await this.spree.checkout.orderUpdate(
|
||||||
|
{ orderToken },
|
||||||
|
{ order: { email, ship_address_attributes, bill_address_attributes } }
|
||||||
|
);
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
this.formDisabled = false
|
this.formDisabled = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const shippingMethods = await this.shippingMethods(orderToken)
|
const shippingMethods = await this.shippingMethods(orderToken);
|
||||||
|
|
||||||
if (!shippingMethods) {
|
if (!shippingMethods) {
|
||||||
this.formDisabled = false
|
this.formDisabled = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const shipping_rates = shippingMethods.included.filter(x => x.type == 'shipping_rate')
|
const shipping_rates = shippingMethods.included.filter(
|
||||||
|
(x) => x.type == "shipping_rate"
|
||||||
|
);
|
||||||
// XXX: No hay varios paquetes
|
// XXX: No hay varios paquetes
|
||||||
const shipping_method = shippingMethods.data[0]
|
const shipping_method = shippingMethods.data[0];
|
||||||
const site = window.site
|
const site = window.site;
|
||||||
|
|
||||||
await this.render({ shipping_method, shipping_rates, site })
|
await this.render({ shipping_method, shipping_rates, site });
|
||||||
|
|
||||||
const nextStep = document.querySelector(`#${this.element.dataset.scrollTo}`)
|
const nextStep = document.querySelector(
|
||||||
if (nextStep) nextStep.scrollIntoView()
|
`#${this.element.dataset.scrollTo}`
|
||||||
|
);
|
||||||
|
if (nextStep) nextStep.scrollIntoView();
|
||||||
}
|
}
|
||||||
|
|
||||||
async processShippingRate (formData) {
|
async processShippingRate(formData) {
|
||||||
const rate = this.formDataToObject(formData)
|
const rate = this.formDataToObject(formData);
|
||||||
const orderToken = this.token
|
const orderToken = this.token;
|
||||||
|
|
||||||
// XXX: Deshabilitar el formulario después del evento FormData, de
|
// XXX: Deshabilitar el formulario después del evento FormData, de
|
||||||
// lo contrario el objeto queda vacío.
|
// lo contrario el objeto queda vacío.
|
||||||
this.ratesTarget.elements.forEach(x => x.disabled = true)
|
this.ratesTarget.elements.forEach((x) => (x.disabled = true));
|
||||||
|
|
||||||
const response = await window.spree.checkout.orderUpdate({ orderToken }, { order: { shipments_attributes: [{ ...rate }] } })
|
const response = await window.spree.checkout.orderUpdate(
|
||||||
|
{ orderToken },
|
||||||
|
{ order: { shipments_attributes: [{ ...rate }] } }
|
||||||
|
);
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.cart = response
|
this.cart = response;
|
||||||
|
|
||||||
// Continue to next step
|
// Continue to next step
|
||||||
try {
|
try {
|
||||||
Turbolinks.visit(this.data.get('next'))
|
Turbolinks.visit(this.data.get("next"));
|
||||||
} catch {
|
} catch {
|
||||||
window.location = this.data.get('next')
|
window.location = this.data.get("next");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async render (data = {}) {
|
async render(data = {}) {
|
||||||
const template = window.templates[this.data.get('template')]
|
const template = window.templates[this.data.get("template")];
|
||||||
|
|
||||||
this.methodsTarget.innerHTML = await this.engine.parseAndRender(template, data)
|
this.methodsTarget.innerHTML = await this.engine.parseAndRender(
|
||||||
this.ratesTarget.addEventListener('formdata', event => this.processShippingRate(event.formData))
|
template,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
this.ratesTarget.addEventListener("formdata", (event) =>
|
||||||
|
this.processShippingRate(event.formData)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,42 +1,42 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sólo permite enviar el formulario de contacto después de unos
|
* Sólo permite enviar el formulario de contacto después de unos
|
||||||
* segundos, para evitar el spam.
|
* segundos, para evitar el spam.
|
||||||
*/
|
*/
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = [ 'submit' ]
|
static targets = ["submit"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
if (!this.hasSubmitTarget) return
|
if (!this.hasSubmitTarget) return;
|
||||||
|
|
||||||
this.submitTarget.disabled = true
|
this.submitTarget.disabled = true;
|
||||||
|
|
||||||
this._value = this.submitTarget.value
|
this._value = this.submitTarget.value;
|
||||||
|
|
||||||
// Esperar un minuto desde que se carga la página hasta que se
|
// Esperar un minuto desde que se carga la página hasta que se
|
||||||
// permite enviar.
|
// permite enviar.
|
||||||
this._interval = setInterval(() => {
|
this._interval = setInterval(() => {
|
||||||
const delay = this.delay
|
const delay = this.delay;
|
||||||
|
|
||||||
if (this.delay == 0) {
|
if (this.delay == 0) {
|
||||||
clearInterval(this._interval)
|
clearInterval(this._interval);
|
||||||
this.submitTarget.disabled = false
|
this.submitTarget.disabled = false;
|
||||||
this.submitTarget.value = this._value
|
this.submitTarget.value = this._value;
|
||||||
} else {
|
} else {
|
||||||
this.delay = delay - 1
|
this.delay = delay - 1;
|
||||||
}
|
}
|
||||||
}, 1000)
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
get delay () {
|
get delay() {
|
||||||
const delay = parseInt(this.element.dataset.delay)
|
const delay = parseInt(this.element.dataset.delay);
|
||||||
|
|
||||||
return isNaN(delay) ? 0 : delay
|
return isNaN(delay) ? 0 : delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
set delay (value) {
|
set delay(value) {
|
||||||
this.element.dataset.delay = value
|
this.element.dataset.delay = value;
|
||||||
this.submitTarget.value = `${this._value} (${value})`
|
this.submitTarget.value = `${this._value} (${value})`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populates a country field where users can type to filter and select
|
* Populates a country field where users can type to filter and select
|
||||||
|
@ -6,96 +6,104 @@ import { CartBaseController } from './cart_base_controller'
|
||||||
*/
|
*/
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
// All are required!
|
// All are required!
|
||||||
static targets = [ 'id', 'iso', 'list', 'name' ]
|
static targets = ["id", "iso", "list", "name"];
|
||||||
|
|
||||||
async connect () {
|
async connect() {
|
||||||
const countries = await this.countries()
|
const countries = await this.countries();
|
||||||
|
|
||||||
countries.forEach(country => {
|
countries.forEach((country) => {
|
||||||
const option = document.createElement('option')
|
const option = document.createElement("option");
|
||||||
|
|
||||||
option.value = country.attributes.name
|
option.value = country.attributes.name;
|
||||||
option.dataset.id = country.id
|
option.dataset.id = country.id;
|
||||||
option.dataset.iso = country.attributes.iso
|
option.dataset.iso = country.attributes.iso;
|
||||||
option.dataset.statesRequired = country.attributes.states_required
|
option.dataset.statesRequired = country.attributes.states_required;
|
||||||
option.dataset.zipcodeRequired = country.attributes.zipcode_required
|
option.dataset.zipcodeRequired = country.attributes.zipcode_required;
|
||||||
|
|
||||||
this.listTarget.appendChild(option)
|
this.listTarget.appendChild(option);
|
||||||
})
|
});
|
||||||
|
|
||||||
const site = window.site
|
const site = window.site;
|
||||||
|
|
||||||
// Only allow names on this list
|
// Only allow names on this list
|
||||||
this.nameTarget.pattern = countries.map(x => x.attributes.name).join('|')
|
this.nameTarget.pattern = countries.map((x) => x.attributes.name).join("|");
|
||||||
this.nameTarget.addEventListener('input', event => this.nameTarget.setCustomValidity(''))
|
this.nameTarget.addEventListener("input", (event) =>
|
||||||
this.nameTarget.addEventListener('invalid', event => this.nameTarget.setCustomValidity(site.i18n.countries.validation))
|
this.nameTarget.setCustomValidity("")
|
||||||
|
);
|
||||||
|
this.nameTarget.addEventListener("invalid", (event) =>
|
||||||
|
this.nameTarget.setCustomValidity(site.i18n.countries.validation)
|
||||||
|
);
|
||||||
|
|
||||||
// When the input changes we update the actual value and also the
|
// When the input changes we update the actual value and also the
|
||||||
// state list via an Event
|
// state list via an Event
|
||||||
this.nameTarget.addEventListener('change', event => {
|
this.nameTarget.addEventListener("change", (event) => {
|
||||||
const value = this.nameTarget.value.trim()
|
const value = this.nameTarget.value.trim();
|
||||||
|
|
||||||
if (value === '') return
|
if (value === "") return;
|
||||||
|
|
||||||
const options = Array.from(this.nameTarget.list.options)
|
const options = Array.from(this.nameTarget.list.options);
|
||||||
const option = options.find(x => x.value == value)
|
const option = options.find((x) => x.value == value);
|
||||||
|
|
||||||
// TODO: If no option is found, mark the field as invalid
|
// TODO: If no option is found, mark the field as invalid
|
||||||
if (!option) return
|
if (!option) return;
|
||||||
|
|
||||||
this.idTarget.value = option.dataset.id
|
this.idTarget.value = option.dataset.id;
|
||||||
this.isoTarget.value = option.dataset.iso
|
this.isoTarget.value = option.dataset.iso;
|
||||||
|
|
||||||
this.idTarget.dispatchEvent(new Event('change'))
|
this.idTarget.dispatchEvent(new Event("change"));
|
||||||
this.isoTarget.dispatchEvent(new Event('change'))
|
this.isoTarget.dispatchEvent(new Event("change"));
|
||||||
|
|
||||||
this.dispatchChangedEvent(option.dataset)
|
this.dispatchChangedEvent(option.dataset);
|
||||||
|
|
||||||
// XXX: Prevent mixing data
|
// XXX: Prevent mixing data
|
||||||
delete this.nameTarget.dataset.selectedState
|
delete this.nameTarget.dataset.selectedState;
|
||||||
delete this.nameTarget.dataset.selectedZipcode
|
delete this.nameTarget.dataset.selectedZipcode;
|
||||||
})
|
});
|
||||||
|
|
||||||
// The input is disabled at this point
|
// The input is disabled at this point
|
||||||
this.nameTarget.disabled = false
|
this.nameTarget.disabled = false;
|
||||||
// Load data if the input is autocompleted
|
// Load data if the input is autocompleted
|
||||||
if (this.nameTarget.value.trim() !== '') this.nameTarget.dispatchEvent(new CustomEvent('change'))
|
if (this.nameTarget.value.trim() !== "")
|
||||||
|
this.nameTarget.dispatchEvent(new CustomEvent("change"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sends a `cart:country:update` event so other controllers can
|
* Sends a `cart:country:update` event so other controllers can
|
||||||
* subscribe to changes.
|
* subscribe to changes.
|
||||||
*/
|
*/
|
||||||
dispatchChangedEvent (data = {}) {
|
dispatchChangedEvent(data = {}) {
|
||||||
const event = new CustomEvent('cart:country:update', {
|
const event = new CustomEvent("cart:country:update", {
|
||||||
detail: {
|
detail: {
|
||||||
id: this.idTarget.value,
|
id: this.idTarget.value,
|
||||||
iso: this.isoTarget.value,
|
iso: this.isoTarget.value,
|
||||||
group: this.data.get('group'),
|
group: this.data.get("group"),
|
||||||
selectedState: this.nameTarget.dataset.selectedState,
|
selectedState: this.nameTarget.dataset.selectedState,
|
||||||
selectedZipcode: this.nameTarget.dataset.selectedZipcode,
|
selectedZipcode: this.nameTarget.dataset.selectedZipcode,
|
||||||
data
|
data,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
window.dispatchEvent(event)
|
window.dispatchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch the country list from storage or from API
|
* Fetch the country list from storage or from API
|
||||||
*/
|
*/
|
||||||
async countries () {
|
async countries() {
|
||||||
const countries = JSON.parse(this.storageTemp.getItem('countries'))
|
const countries = JSON.parse(this.storageTemp.getItem("countries"));
|
||||||
|
|
||||||
if (countries) return countries
|
if (countries) return countries;
|
||||||
|
|
||||||
const response = await this.spree.countries.list()
|
const response = await this.spree.countries.list();
|
||||||
|
|
||||||
// TODO: Show error message
|
// TODO: Show error message
|
||||||
if (!response.success()) return
|
if (!response.success()) return;
|
||||||
|
|
||||||
this.storageTemp.setItem('countries', JSON.stringify(response.success().data))
|
this.storageTemp.setItem(
|
||||||
|
"countries",
|
||||||
|
JSON.stringify(response.success().data)
|
||||||
|
);
|
||||||
|
|
||||||
return response.success().data
|
return response.success().data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = [ 'content' ]
|
static targets = ["content"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
window.addEventListener('toast', event => {
|
window.addEventListener("toast", (event) => {
|
||||||
this.contentTarget.innerText = event.detail.content
|
this.contentTarget.innerText = event.detail.content;
|
||||||
this.element.classList.toggle('hide')
|
this.element.classList.toggle("hide");
|
||||||
this.element.classList.toggle('show')
|
this.element.classList.toggle("show");
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.element.classList.toggle('hide')
|
this.element.classList.toggle("hide");
|
||||||
this.element.classList.toggle('show')
|
this.element.classList.toggle("show");
|
||||||
}, 3000)
|
}, 3000);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,31 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = [ 'item' ]
|
static targets = ["item"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
window.addEventListener('scroll:section', event => this.update(event.detail.id))
|
window.addEventListener("scroll:section", (event) =>
|
||||||
|
this.update(event.detail.id)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get items () {
|
get items() {
|
||||||
if (!this._items) {
|
if (!this._items) {
|
||||||
this._items = {}
|
this._items = {};
|
||||||
|
|
||||||
for (const item of this.itemTargets) {
|
for (const item of this.itemTargets) {
|
||||||
this._items[item.href.split('#')[1]] = item
|
this._items[item.href.split("#")[1]] = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._items
|
return this._items;
|
||||||
}
|
}
|
||||||
|
|
||||||
update (id) {
|
update(id) {
|
||||||
for (const item of Object.values(this.items)) {
|
for (const item of Object.values(this.items)) {
|
||||||
item.classList.remove('active')
|
item.classList.remove("active");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.items[id]) this.items[id].classList.add('active')
|
if (this.items[id]) this.items[id].classList.add("active");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,47 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
import { Liquid } from 'liquidjs'
|
import { Liquid } from "liquidjs";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Waits for notifications and shows them by fetching and rendering
|
* Waits for notifications and shows them by fetching and rendering
|
||||||
* a template.
|
* a template.
|
||||||
*/
|
*/
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
connect () {
|
connect() {
|
||||||
window.addEventListener('notification', async event => await this.render(event.detail.template, event.detail.data))
|
window.addEventListener(
|
||||||
|
"notification",
|
||||||
|
async (event) =>
|
||||||
|
await this.render(event.detail.template, event.detail.data)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Renders and replaces notification contents and then shows it. Does
|
* Renders and replaces notification contents and then shows it. Does
|
||||||
* nothing if the template isn't found.
|
* nothing if the template isn't found.
|
||||||
*/
|
*/
|
||||||
async render (name, data = {}) {
|
async render(name, data = {}) {
|
||||||
data.site = window.site
|
data.site = window.site;
|
||||||
|
|
||||||
const template = window.templates.alert
|
const template = window.templates.alert;
|
||||||
const html = await this.engine.parseAndRender(template, data)
|
const html = await this.engine.parseAndRender(template, data);
|
||||||
|
|
||||||
this.element.innerHTML = html
|
this.element.innerHTML = html;
|
||||||
this.show()
|
this.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shows the notification
|
* Shows the notification
|
||||||
*/
|
*/
|
||||||
show () {
|
show() {
|
||||||
this.element.classList.add('show')
|
this.element.classList.add("show");
|
||||||
this.element.classList.remove('hide')
|
this.element.classList.remove("hide");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hides the notification
|
* Hides the notification
|
||||||
*/
|
*/
|
||||||
hide () {
|
hide() {
|
||||||
this.element.classList.add('hide')
|
this.element.classList.add("hide");
|
||||||
this.element.classList.remove('show')
|
this.element.classList.remove("show");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -45,9 +49,9 @@ export default class extends Controller {
|
||||||
*
|
*
|
||||||
* @return Liquid
|
* @return Liquid
|
||||||
*/
|
*/
|
||||||
get engine () {
|
get engine() {
|
||||||
if (!window.liquid) window.liquid = new Liquid()
|
if (!window.liquid) window.liquid = new Liquid();
|
||||||
|
|
||||||
return window.liquid
|
return window.liquid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Renders the order table. All products are stored on localStorage, so
|
* Renders the order table. All products are stored on localStorage, so
|
||||||
|
@ -6,46 +6,48 @@ import { CartBaseController } from './cart_base_controller'
|
||||||
* Liquid.
|
* Liquid.
|
||||||
*/
|
*/
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
static targets = [ 'cart', 'subtotal', 'itemCount' ]
|
static targets = ["cart", "subtotal", "itemCount"];
|
||||||
|
|
||||||
async connect () {
|
async connect() {
|
||||||
const products = this.products
|
const products = this.products;
|
||||||
const site = window.site
|
const site = window.site;
|
||||||
|
|
||||||
this.render({ products, site })
|
this.render({ products, site });
|
||||||
this.subtotalUpdate()
|
this.subtotalUpdate();
|
||||||
this.itemCountUpdate()
|
this.itemCountUpdate();
|
||||||
this.subscribe()
|
this.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subscribe to change on the storage to update the cart.
|
* Subscribe to change on the storage to update the cart.
|
||||||
*/
|
*/
|
||||||
subscribe () {
|
subscribe() {
|
||||||
window.addEventListener('storage', async event => {
|
window.addEventListener("storage", async (event) => {
|
||||||
if (!event.key?.startsWith('cart:item:')) return
|
if (!event.key?.startsWith("cart:item:")) return;
|
||||||
|
|
||||||
const products = this.products
|
const products = this.products;
|
||||||
const site = window.site
|
const site = window.site;
|
||||||
|
|
||||||
this.render({ products, site })
|
this.render({ products, site });
|
||||||
this.subtotalUpdate()
|
this.subtotalUpdate();
|
||||||
this.itemCountUpdate()
|
this.itemCountUpdate();
|
||||||
})
|
});
|
||||||
|
|
||||||
window.addEventListener('cart:subtotal:update', event => {
|
window.addEventListener("cart:subtotal:update", (event) => {
|
||||||
this.itemCountUpdate()
|
this.itemCountUpdate();
|
||||||
this.subtotalUpdate()
|
this.subtotalUpdate();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Download the item template and render the order
|
* Download the item template and render the order
|
||||||
*/
|
*/
|
||||||
render (data = {}) {
|
render(data = {}) {
|
||||||
const template = window.templates[this.data.get('itemTemplate')]
|
const template = window.templates[this.data.get("itemTemplate")];
|
||||||
|
|
||||||
this.engine.parseAndRender(template, data).then(html => this.cartTarget.innerHTML = html)
|
this.engine
|
||||||
|
.parseAndRender(template, data)
|
||||||
|
.then((html) => (this.cartTarget.innerHTML = html));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -53,16 +55,16 @@ export default class extends CartBaseController {
|
||||||
*
|
*
|
||||||
* XXX: This also updates the currency
|
* XXX: This also updates the currency
|
||||||
*/
|
*/
|
||||||
subtotalUpdate () {
|
subtotalUpdate() {
|
||||||
if (!this.cart) return
|
if (!this.cart) return;
|
||||||
|
|
||||||
this.subtotalTarget.innerText = this.cart.data.attributes.display_total
|
this.subtotalTarget.innerText = this.cart.data.attributes.display_total;
|
||||||
}
|
}
|
||||||
|
|
||||||
itemCountUpdate () {
|
itemCountUpdate() {
|
||||||
if (!this.hasItemCountTarget) return
|
if (!this.hasItemCountTarget) return;
|
||||||
if (!this.cart) return
|
if (!this.cart) return;
|
||||||
|
|
||||||
this.itemCountTarget.innerText = this.cart.data.attributes.item_count
|
this.itemCountTarget.innerText = this.cart.data.attributes.item_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Al pagar lo que podamos, primero hay que crear una orden y luego
|
* Al pagar lo que podamos, primero hay que crear una orden y luego
|
||||||
|
@ -7,29 +7,29 @@ import { CartBaseController } from './cart_base_controller'
|
||||||
* proceso de pago.
|
* proceso de pago.
|
||||||
*/
|
*/
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
static targets = [ 'form' ]
|
static targets = ["form"];
|
||||||
static values = {
|
static values = {
|
||||||
variantId: Number,
|
variantId: Number,
|
||||||
currency: String,
|
currency: String,
|
||||||
price: Number,
|
price: Number,
|
||||||
firstname: String
|
firstname: String,
|
||||||
}
|
};
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
this.paymentMethodByCurrency = {
|
this.paymentMethodByCurrency = {
|
||||||
ARS: 'Spree::PaymentMethod::MercadoPago',
|
ARS: "Spree::PaymentMethod::MercadoPago",
|
||||||
USD: 'Spree::PaymentMethod::Paypal'
|
USD: "Spree::PaymentMethod::Paypal",
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
store (event) {
|
store(event) {
|
||||||
const target = event.currentTarget || event.target
|
const target = event.currentTarget || event.target;
|
||||||
|
|
||||||
this[`${target.dataset.name}Value`] = target.value
|
this[`${target.dataset.name}Value`] = target.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
set formDisable (disable) {
|
set formDisable(disable) {
|
||||||
this.formTarget.elements.forEach(x => x.disabled = disable)
|
this.formTarget.elements.forEach((x) => (x.disabled = disable));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -45,162 +45,204 @@ export default class extends CartBaseController {
|
||||||
* * Reenviar a confirmación
|
* * Reenviar a confirmación
|
||||||
* * Ejecutar el pago (si aplica)
|
* * Ejecutar el pago (si aplica)
|
||||||
*/
|
*/
|
||||||
async pay (event = undefined) {
|
async pay(event = undefined) {
|
||||||
if (event) {
|
if (event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.formTarget.checkValidity()) {
|
if (!this.formTarget.checkValidity()) {
|
||||||
this.formTarget.classList.add('was-validated')
|
this.formTarget.classList.add("was-validated");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.formDisable = true
|
this.formDisable = true;
|
||||||
|
|
||||||
// Crear pedido. Todos los pedidos van a ser hechos desde
|
// Crear pedido. Todos los pedidos van a ser hechos desde
|
||||||
// Argentina, no hay forma de cambiar esto.
|
// Argentina, no hay forma de cambiar esto.
|
||||||
const orderToken = await this.tempCartCreate()
|
const orderToken = await this.tempCartCreate();
|
||||||
const quantity = 1
|
const quantity = 1;
|
||||||
const include = 'line_items'
|
const include = "line_items";
|
||||||
const currency = this.currencyValue
|
const currency = this.currencyValue;
|
||||||
const price = this.priceValue
|
const price = this.priceValue;
|
||||||
const email = 'noreply@sutty.nl'
|
const email = "noreply@sutty.nl";
|
||||||
const firstname = this.firstnameValue
|
const firstname = this.firstnameValue;
|
||||||
const lastname = '-'
|
const lastname = "-";
|
||||||
const address1 = '-'
|
const address1 = "-";
|
||||||
const country_id = 250 // XXX: Internet
|
const country_id = 250; // XXX: Internet
|
||||||
const city = '-'
|
const city = "-";
|
||||||
const phone = '11111111'
|
const phone = "11111111";
|
||||||
const zipcode = '1111'
|
const zipcode = "1111";
|
||||||
const ship_address_attributes = { firstname, lastname, address1, city, country_id, zipcode, phone }
|
const ship_address_attributes = {
|
||||||
const bill_address_attributes = ship_address_attributes
|
firstname,
|
||||||
const confirmation_delivered = true
|
lastname,
|
||||||
const custom_return_url = this.customReturnUrl()
|
address1,
|
||||||
|
city,
|
||||||
|
country_id,
|
||||||
|
zipcode,
|
||||||
|
phone,
|
||||||
|
};
|
||||||
|
const bill_address_attributes = ship_address_attributes;
|
||||||
|
const confirmation_delivered = true;
|
||||||
|
const custom_return_url = this.customReturnUrl();
|
||||||
|
|
||||||
let variant_id = this.variantIdValue
|
let variant_id = this.variantIdValue;
|
||||||
|
|
||||||
// Crear la variante
|
// Crear la variante
|
||||||
const payWhatYouCanResponse = await this.spree.sutty.payWhatYouCan({ orderToken }, { variant_id, price, currency, quantity })
|
const payWhatYouCanResponse = await this.spree.sutty.payWhatYouCan(
|
||||||
|
{ orderToken },
|
||||||
|
{ variant_id, price, currency, quantity }
|
||||||
|
);
|
||||||
|
|
||||||
variant_id = payWhatYouCanResponse.data.id
|
variant_id = payWhatYouCanResponse.data.id;
|
||||||
|
|
||||||
if (!variant_id) {
|
if (!variant_id) {
|
||||||
this.formDisable = false
|
this.formDisable = false;
|
||||||
console.error('No se pudo generar la variante', { variant_id, price, currency, quantity })
|
console.error("No se pudo generar la variante", {
|
||||||
return
|
variant_id,
|
||||||
|
price,
|
||||||
|
currency,
|
||||||
|
quantity,
|
||||||
|
});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configurar la moneda del pedido
|
// Configurar la moneda del pedido
|
||||||
let response = await this.spree.sutty.updateOrder({ orderToken }, { currency, confirmation_delivered, custom_return_url })
|
let response = await this.spree.sutty.updateOrder(
|
||||||
|
{ orderToken },
|
||||||
|
{ currency, confirmation_delivered, custom_return_url }
|
||||||
|
);
|
||||||
|
|
||||||
if (response.status > 299) {
|
if (response.status > 299) {
|
||||||
console.error(response)
|
console.error(response);
|
||||||
this.formDisable = false
|
this.formDisable = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Agregar al carrito
|
// Agregar al carrito
|
||||||
response = await this.spree.cart.addItem({ orderToken }, { variant_id, quantity, include })
|
response = await this.spree.cart.addItem(
|
||||||
|
{ orderToken },
|
||||||
|
{ variant_id, quantity, include }
|
||||||
|
);
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
this.formDisable = false
|
this.formDisable = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actualizar la dirección
|
// Actualizar la dirección
|
||||||
response = await this.spree.checkout.orderUpdate({ orderToken }, { order: { email, ship_address_attributes, bill_address_attributes }})
|
response = await this.spree.checkout.orderUpdate(
|
||||||
|
{ orderToken },
|
||||||
|
{ order: { email, ship_address_attributes, bill_address_attributes } }
|
||||||
|
);
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
this.formDisable = false
|
this.formDisable = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtener los medios de envío
|
// Obtener los medios de envío
|
||||||
response = await this.spree.checkout.shippingMethods({ orderToken }, { include: 'shipping_rates' })
|
response = await this.spree.checkout.shippingMethods(
|
||||||
|
{ orderToken },
|
||||||
|
{ include: "shipping_rates" }
|
||||||
|
);
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
this.formDisable = false
|
this.formDisable = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Elegir medio de envío
|
// Elegir medio de envío
|
||||||
response = await this.spree.checkout.orderUpdate({ orderToken }, {
|
response = await this.spree.checkout.orderUpdate(
|
||||||
|
{ orderToken },
|
||||||
|
{
|
||||||
order: {
|
order: {
|
||||||
shipments_attributes: [{
|
shipments_attributes: [
|
||||||
|
{
|
||||||
id: response.success().data[0].id,
|
id: response.success().data[0].id,
|
||||||
selected_shipping_rate_id: response.success().included.filter(x => x.type == 'shipping_rate')[0].id
|
selected_shipping_rate_id: response
|
||||||
}]
|
.success()
|
||||||
|
.included.filter((x) => x.type == "shipping_rate")[0].id,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
}
|
}
|
||||||
})
|
);
|
||||||
|
|
||||||
// Elegir medio de pago
|
// Elegir medio de pago
|
||||||
response = await this.spree.checkout.paymentMethods({ orderToken })
|
response = await this.spree.checkout.paymentMethods({ orderToken });
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
this.formDisable = false
|
this.formDisable = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const payment_method_id = response.success().data.find(x => this.paymentMethodByCurrency[this.currencyValue] == x.attributes.type).id
|
const payment_method_id = response
|
||||||
|
.success()
|
||||||
|
.data.find(
|
||||||
|
(x) =>
|
||||||
|
this.paymentMethodByCurrency[this.currencyValue] == x.attributes.type
|
||||||
|
).id;
|
||||||
|
|
||||||
response = await this.spree.checkout.orderUpdate({ orderToken },
|
response = await this.spree.checkout.orderUpdate(
|
||||||
|
{ orderToken },
|
||||||
{
|
{
|
||||||
order: { payments_attributes: [{ payment_method_id }] },
|
order: { payments_attributes: [{ payment_method_id }] },
|
||||||
payment_source: {
|
payment_source: {
|
||||||
[payment_method_id]: {
|
[payment_method_id]: {
|
||||||
name: 'Pepitx',
|
name: "Pepitx",
|
||||||
month: 12,
|
month: 12,
|
||||||
year: 2021
|
year: 2021,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
})
|
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
this.formDisable = false
|
this.formDisable = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
response = await this.spree.checkout.complete({ orderToken })
|
response = await this.spree.checkout.complete({ orderToken });
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
this.formDisable = false
|
this.formDisable = false;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reenviar al medio de pago
|
// Reenviar al medio de pago
|
||||||
const checkoutUrls = await this.spree.sutty.getCheckoutURL({ orderToken })
|
const checkoutUrls = await this.spree.sutty.getCheckoutURL({ orderToken });
|
||||||
const redirectUrl = checkoutUrls.data[0]
|
const redirectUrl = checkoutUrls.data[0];
|
||||||
|
|
||||||
Turbolinks.visit(redirectUrl)
|
Turbolinks.visit(redirectUrl);
|
||||||
|
|
||||||
// Volver
|
// Volver
|
||||||
}
|
}
|
||||||
|
|
||||||
async tempCartCreate () {
|
async tempCartCreate() {
|
||||||
const response = await this.spree.cart.create()
|
const response = await this.spree.cart.create();
|
||||||
|
|
||||||
// If we fail here it's probably a server error, so we inform the
|
// If we fail here it's probably a server error, so we inform the
|
||||||
// user.
|
// user.
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.success().data.attributes.token
|
return response.success().data.attributes.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @return [String]
|
// @return [String]
|
||||||
customReturnUrl () {
|
customReturnUrl() {
|
||||||
const url = new URL(window.location.href)
|
const url = new URL(window.location.href);
|
||||||
url.searchParams.set('open', '')
|
url.searchParams.set("open", "");
|
||||||
|
|
||||||
return url.toString()
|
return url.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subscribes to the country change event and changes the validation
|
* Subscribes to the country change event and changes the validation
|
||||||
* pattern of its input.
|
* pattern of its input.
|
||||||
*/
|
*/
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = [ 'code' ]
|
static targets = ["code"];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Twitter CLDR is pretty big and we only need the postal codes
|
* Twitter CLDR is pretty big and we only need the postal codes
|
||||||
|
@ -13,26 +13,186 @@ export default class extends Controller {
|
||||||
*
|
*
|
||||||
* @see {https://github.com/twitter/twitter-cldr-npm/blob/4388dfc55900b0feb80eafcac030f9f26981a41d/full/core.js#L1999}
|
* @see {https://github.com/twitter/twitter-cldr-npm/blob/4388dfc55900b0feb80eafcac030f9f26981a41d/full/core.js#L1999}
|
||||||
*/
|
*/
|
||||||
postal_codes = {"ad":"^AD\\d{3}$","am":"^(37)?\\d{4}$","ar":"^([A-HJ-NP-Z])?\\d{4}([A-Z]{3})?$","as":"^96799$","at":"^\\d{4}$","au":"^\\d{4}$","ax":"^22\\d{3}$","az":"^\\d{4}$","ba":"^\\d{5}$","bb":"^(BB\\d{5})?$","bd":"^\\d{4}$","be":"^\\d{4}$","bg":"^\\d{4}$","bh":"^((1[0-2]|[2-9])\\d{2})?$","bm":"^[A-Z]{2}[ ]?[A-Z0-9]{2}$","bn":"^[A-Z]{2}[ ]?\\d{4}$","br":"^\\d{5}[\\-]?\\d{3}$","by":"^\\d{6}$","ca":"^[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z][ ]?\\d[ABCEGHJ-NPRSTV-Z]\\d$","cc":"^6799$","ch":"^\\d{4}$","ck":"^\\d{4}$","cl":"^\\d{7}$","cn":"^\\d{6}$","cr":"^\\d{4,5}|\\d{3}-\\d{4}$","cs":"^\\d{5}$","cv":"^\\d{4}$","cx":"^6798$","cy":"^\\d{4}$","cz":"^\\d{3}[ ]?\\d{2}$","de":"^\\d{5}$","dk":"^\\d{4}$","do":"^\\d{5}$","dz":"^\\d{5}$","ec":"^([A-Z]\\d{4}[A-Z]|(?:[A-Z]{2})?\\d{6})?$","ee":"^\\d{5}$","eg":"^\\d{5}$","es":"^\\d{5}$","et":"^\\d{4}$","fi":"^\\d{5}$","fk":"^FIQQ 1ZZ$","fm":"^(9694[1-4])([ \\-]\\d{4})?$","fo":"^\\d{3}$","fr":"^\\d{2}[ ]?\\d{3}$","gb":"^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\\d{1,4}$","ge":"^\\d{4}$","gf":"^9[78]3\\d{2}$","gg":"^GY\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}$","gl":"^39\\d{2}$","gn":"^\\d{3}$","gp":"^9[78][01]\\d{2}$","gr":"^\\d{3}[ ]?\\d{2}$","gs":"^SIQQ 1ZZ$","gt":"^\\d{5}$","gu":"^969[123]\\d([ \\-]\\d{4})?$","gw":"^\\d{4}$","hm":"^\\d{4}$","hn":"^(?:\\d{5})?$","hr":"^\\d{5}$","ht":"^\\d{4}$","hu":"^\\d{4}$","id":"^\\d{5}$","il":"^\\d{5}$","im":"^IM\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}$","in":"^\\d{6}$","io":"^BBND 1ZZ$","iq":"^\\d{5}$","is":"^\\d{3}$","it":"^\\d{5}$","je":"^JE\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}$","jo":"^\\d{5}$","jp":"^\\d{3}-\\d{4}$","ke":"^\\d{5}$","kg":"^\\d{6}$","kh":"^\\d{5}$","kr":"^\\d{3}[\\-]\\d{3}$","kw":"^\\d{5}$","kz":"^\\d{6}$","la":"^\\d{5}$","lb":"^(\\d{4}([ ]?\\d{4})?)?$","li":"^(948[5-9])|(949[0-7])$","lk":"^\\d{5}$","lr":"^\\d{4}$","ls":"^\\d{3}$","lt":"^\\d{5}$","lu":"^\\d{4}$","lv":"^\\d{4}$","ma":"^\\d{5}$","mc":"^980\\d{2}$","md":"^\\d{4}$","me":"^8\\d{4}$","mg":"^\\d{3}$","mh":"^969[67]\\d([ \\-]\\d{4})?$","mk":"^\\d{4}$","mn":"^\\d{6}$","mp":"^9695[012]([ \\-]\\d{4})?$","mq":"^9[78]2\\d{2}$","mt":"^[A-Z]{3}[ ]?\\d{2,4}$","mu":"^(\\d{3}[A-Z]{2}\\d{3})?$","mv":"^\\d{5}$","mx":"^\\d{5}$","my":"^\\d{5}$","nc":"^988\\d{2}$","ne":"^\\d{4}$","nf":"^2899$","ng":"^(\\d{6})?$","ni":"^((\\d{4}-)?\\d{3}-\\d{3}(-\\d{1})?)?$","nl":"^\\d{4}[ ]?[A-Z]{2}$","no":"^\\d{4}$","np":"^\\d{5}$","nz":"^\\d{4}$","om":"^(PC )?\\d{3}$","pf":"^987\\d{2}$","pg":"^\\d{3}$","ph":"^\\d{4}$","pk":"^\\d{5}$","pl":"^\\d{2}-\\d{3}$","pm":"^9[78]5\\d{2}$","pn":"^PCRN 1ZZ$","pr":"^00[679]\\d{2}([ \\-]\\d{4})?$","pt":"^\\d{4}([\\-]\\d{3})?$","pw":"^96940$","py":"^\\d{4}$","re":"^9[78]4\\d{2}$","ro":"^\\d{6}$","rs":"^\\d{6}$","ru":"^\\d{6}$","sa":"^\\d{5}$","se":"^\\d{3}[ ]?\\d{2}$","sg":"^\\d{6}$","sh":"^(ASCN|STHL) 1ZZ$","si":"^\\d{4}$","sj":"^\\d{4}$","sk":"^\\d{3}[ ]?\\d{2}$","sm":"^4789\\d$","sn":"^\\d{5}$","so":"^\\d{5}$","sz":"^[HLMS]\\d{3}$","tc":"^TKCA 1ZZ$","th":"^\\d{5}$","tj":"^\\d{6}$","tm":"^\\d{6}$","tn":"^\\d{4}$","tr":"^\\d{5}$","tw":"^\\d{3}(\\d{2})?$","ua":"^\\d{5}$","us":"^\\d{5}([ \\-]\\d{4})?$","uy":"^\\d{5}$","uz":"^\\d{6}$","va":"^00120$","ve":"^\\d{4}$","vi":"^008(([0-4]\\d)|(5[01]))([ \\-]\\d{4})?$","wf":"^986\\d{2}$","xk":"^\\d{5}$","yt":"^976\\d{2}$","yu":"^\\d{5}$","za":"^\\d{4}$","zm":"^\\d{5}$"}
|
postal_codes = {
|
||||||
|
ad: "^AD\\d{3}$",
|
||||||
|
am: "^(37)?\\d{4}$",
|
||||||
|
ar: "^([A-HJ-NP-Z])?\\d{4}([A-Z]{3})?$",
|
||||||
|
as: "^96799$",
|
||||||
|
at: "^\\d{4}$",
|
||||||
|
au: "^\\d{4}$",
|
||||||
|
ax: "^22\\d{3}$",
|
||||||
|
az: "^\\d{4}$",
|
||||||
|
ba: "^\\d{5}$",
|
||||||
|
bb: "^(BB\\d{5})?$",
|
||||||
|
bd: "^\\d{4}$",
|
||||||
|
be: "^\\d{4}$",
|
||||||
|
bg: "^\\d{4}$",
|
||||||
|
bh: "^((1[0-2]|[2-9])\\d{2})?$",
|
||||||
|
bm: "^[A-Z]{2}[ ]?[A-Z0-9]{2}$",
|
||||||
|
bn: "^[A-Z]{2}[ ]?\\d{4}$",
|
||||||
|
br: "^\\d{5}[\\-]?\\d{3}$",
|
||||||
|
by: "^\\d{6}$",
|
||||||
|
ca: "^[ABCEGHJKLMNPRSTVXY]\\d[ABCEGHJ-NPRSTV-Z][ ]?\\d[ABCEGHJ-NPRSTV-Z]\\d$",
|
||||||
|
cc: "^6799$",
|
||||||
|
ch: "^\\d{4}$",
|
||||||
|
ck: "^\\d{4}$",
|
||||||
|
cl: "^\\d{7}$",
|
||||||
|
cn: "^\\d{6}$",
|
||||||
|
cr: "^\\d{4,5}|\\d{3}-\\d{4}$",
|
||||||
|
cs: "^\\d{5}$",
|
||||||
|
cv: "^\\d{4}$",
|
||||||
|
cx: "^6798$",
|
||||||
|
cy: "^\\d{4}$",
|
||||||
|
cz: "^\\d{3}[ ]?\\d{2}$",
|
||||||
|
de: "^\\d{5}$",
|
||||||
|
dk: "^\\d{4}$",
|
||||||
|
do: "^\\d{5}$",
|
||||||
|
dz: "^\\d{5}$",
|
||||||
|
ec: "^([A-Z]\\d{4}[A-Z]|(?:[A-Z]{2})?\\d{6})?$",
|
||||||
|
ee: "^\\d{5}$",
|
||||||
|
eg: "^\\d{5}$",
|
||||||
|
es: "^\\d{5}$",
|
||||||
|
et: "^\\d{4}$",
|
||||||
|
fi: "^\\d{5}$",
|
||||||
|
fk: "^FIQQ 1ZZ$",
|
||||||
|
fm: "^(9694[1-4])([ \\-]\\d{4})?$",
|
||||||
|
fo: "^\\d{3}$",
|
||||||
|
fr: "^\\d{2}[ ]?\\d{3}$",
|
||||||
|
gb: "^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\\d{1,4}$",
|
||||||
|
ge: "^\\d{4}$",
|
||||||
|
gf: "^9[78]3\\d{2}$",
|
||||||
|
gg: "^GY\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}$",
|
||||||
|
gl: "^39\\d{2}$",
|
||||||
|
gn: "^\\d{3}$",
|
||||||
|
gp: "^9[78][01]\\d{2}$",
|
||||||
|
gr: "^\\d{3}[ ]?\\d{2}$",
|
||||||
|
gs: "^SIQQ 1ZZ$",
|
||||||
|
gt: "^\\d{5}$",
|
||||||
|
gu: "^969[123]\\d([ \\-]\\d{4})?$",
|
||||||
|
gw: "^\\d{4}$",
|
||||||
|
hm: "^\\d{4}$",
|
||||||
|
hn: "^(?:\\d{5})?$",
|
||||||
|
hr: "^\\d{5}$",
|
||||||
|
ht: "^\\d{4}$",
|
||||||
|
hu: "^\\d{4}$",
|
||||||
|
id: "^\\d{5}$",
|
||||||
|
il: "^\\d{5}$",
|
||||||
|
im: "^IM\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}$",
|
||||||
|
in: "^\\d{6}$",
|
||||||
|
io: "^BBND 1ZZ$",
|
||||||
|
iq: "^\\d{5}$",
|
||||||
|
is: "^\\d{3}$",
|
||||||
|
it: "^\\d{5}$",
|
||||||
|
je: "^JE\\d[\\dA-Z]?[ ]?\\d[ABD-HJLN-UW-Z]{2}$",
|
||||||
|
jo: "^\\d{5}$",
|
||||||
|
jp: "^\\d{3}-\\d{4}$",
|
||||||
|
ke: "^\\d{5}$",
|
||||||
|
kg: "^\\d{6}$",
|
||||||
|
kh: "^\\d{5}$",
|
||||||
|
kr: "^\\d{3}[\\-]\\d{3}$",
|
||||||
|
kw: "^\\d{5}$",
|
||||||
|
kz: "^\\d{6}$",
|
||||||
|
la: "^\\d{5}$",
|
||||||
|
lb: "^(\\d{4}([ ]?\\d{4})?)?$",
|
||||||
|
li: "^(948[5-9])|(949[0-7])$",
|
||||||
|
lk: "^\\d{5}$",
|
||||||
|
lr: "^\\d{4}$",
|
||||||
|
ls: "^\\d{3}$",
|
||||||
|
lt: "^\\d{5}$",
|
||||||
|
lu: "^\\d{4}$",
|
||||||
|
lv: "^\\d{4}$",
|
||||||
|
ma: "^\\d{5}$",
|
||||||
|
mc: "^980\\d{2}$",
|
||||||
|
md: "^\\d{4}$",
|
||||||
|
me: "^8\\d{4}$",
|
||||||
|
mg: "^\\d{3}$",
|
||||||
|
mh: "^969[67]\\d([ \\-]\\d{4})?$",
|
||||||
|
mk: "^\\d{4}$",
|
||||||
|
mn: "^\\d{6}$",
|
||||||
|
mp: "^9695[012]([ \\-]\\d{4})?$",
|
||||||
|
mq: "^9[78]2\\d{2}$",
|
||||||
|
mt: "^[A-Z]{3}[ ]?\\d{2,4}$",
|
||||||
|
mu: "^(\\d{3}[A-Z]{2}\\d{3})?$",
|
||||||
|
mv: "^\\d{5}$",
|
||||||
|
mx: "^\\d{5}$",
|
||||||
|
my: "^\\d{5}$",
|
||||||
|
nc: "^988\\d{2}$",
|
||||||
|
ne: "^\\d{4}$",
|
||||||
|
nf: "^2899$",
|
||||||
|
ng: "^(\\d{6})?$",
|
||||||
|
ni: "^((\\d{4}-)?\\d{3}-\\d{3}(-\\d{1})?)?$",
|
||||||
|
nl: "^\\d{4}[ ]?[A-Z]{2}$",
|
||||||
|
no: "^\\d{4}$",
|
||||||
|
np: "^\\d{5}$",
|
||||||
|
nz: "^\\d{4}$",
|
||||||
|
om: "^(PC )?\\d{3}$",
|
||||||
|
pf: "^987\\d{2}$",
|
||||||
|
pg: "^\\d{3}$",
|
||||||
|
ph: "^\\d{4}$",
|
||||||
|
pk: "^\\d{5}$",
|
||||||
|
pl: "^\\d{2}-\\d{3}$",
|
||||||
|
pm: "^9[78]5\\d{2}$",
|
||||||
|
pn: "^PCRN 1ZZ$",
|
||||||
|
pr: "^00[679]\\d{2}([ \\-]\\d{4})?$",
|
||||||
|
pt: "^\\d{4}([\\-]\\d{3})?$",
|
||||||
|
pw: "^96940$",
|
||||||
|
py: "^\\d{4}$",
|
||||||
|
re: "^9[78]4\\d{2}$",
|
||||||
|
ro: "^\\d{6}$",
|
||||||
|
rs: "^\\d{6}$",
|
||||||
|
ru: "^\\d{6}$",
|
||||||
|
sa: "^\\d{5}$",
|
||||||
|
se: "^\\d{3}[ ]?\\d{2}$",
|
||||||
|
sg: "^\\d{6}$",
|
||||||
|
sh: "^(ASCN|STHL) 1ZZ$",
|
||||||
|
si: "^\\d{4}$",
|
||||||
|
sj: "^\\d{4}$",
|
||||||
|
sk: "^\\d{3}[ ]?\\d{2}$",
|
||||||
|
sm: "^4789\\d$",
|
||||||
|
sn: "^\\d{5}$",
|
||||||
|
so: "^\\d{5}$",
|
||||||
|
sz: "^[HLMS]\\d{3}$",
|
||||||
|
tc: "^TKCA 1ZZ$",
|
||||||
|
th: "^\\d{5}$",
|
||||||
|
tj: "^\\d{6}$",
|
||||||
|
tm: "^\\d{6}$",
|
||||||
|
tn: "^\\d{4}$",
|
||||||
|
tr: "^\\d{5}$",
|
||||||
|
tw: "^\\d{3}(\\d{2})?$",
|
||||||
|
ua: "^\\d{5}$",
|
||||||
|
us: "^\\d{5}([ \\-]\\d{4})?$",
|
||||||
|
uy: "^\\d{5}$",
|
||||||
|
uz: "^\\d{6}$",
|
||||||
|
va: "^00120$",
|
||||||
|
ve: "^\\d{4}$",
|
||||||
|
vi: "^008(([0-4]\\d)|(5[01]))([ \\-]\\d{4})?$",
|
||||||
|
wf: "^986\\d{2}$",
|
||||||
|
xk: "^\\d{5}$",
|
||||||
|
yt: "^976\\d{2}$",
|
||||||
|
yu: "^\\d{5}$",
|
||||||
|
za: "^\\d{4}$",
|
||||||
|
zm: "^\\d{5}$",
|
||||||
|
};
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
window.addEventListener('cart:country:update', event => {
|
window.addEventListener("cart:country:update", (event) => {
|
||||||
if (this.data.get('group') !== event.detail.group) return
|
if (this.data.get("group") !== event.detail.group) return;
|
||||||
|
|
||||||
const zipcodeRequired = event.detail.data.zipcodeRequired == 'true'
|
const zipcodeRequired = event.detail.data.zipcodeRequired == "true";
|
||||||
|
|
||||||
this.codeTarget.value = ''
|
this.codeTarget.value = "";
|
||||||
this.codeTarget.disabled = !zipcodeRequired
|
this.codeTarget.disabled = !zipcodeRequired;
|
||||||
this.codeTarget.required = zipcodeRequired
|
this.codeTarget.required = zipcodeRequired;
|
||||||
|
|
||||||
if (!zipcodeRequired) return
|
if (!zipcodeRequired) return;
|
||||||
|
|
||||||
this.codeTarget.pattern = this.postal_codes[event.detail.iso.toLowerCase()] || '.*'
|
this.codeTarget.pattern =
|
||||||
|
this.postal_codes[event.detail.iso.toLowerCase()] || ".*";
|
||||||
|
|
||||||
if (event.detail.selectedZipcode) {
|
if (event.detail.selectedZipcode) {
|
||||||
this.codeTarget.value = event.detail.selectedZipcode
|
this.codeTarget.value = event.detail.selectedZipcode;
|
||||||
this.codeTarget.dispatchEvent(new Event('change'))
|
this.codeTarget.dispatchEvent(new Event("change"));
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Al navegar por el sitio y llegar a ciertas secciones, se van
|
* Al navegar por el sitio y llegar a ciertas secciones, se van
|
||||||
|
@ -8,34 +8,40 @@ import { Controller } from 'stimulus'
|
||||||
* a medida que van apareciendo secciones actualizamos el menú.
|
* a medida que van apareciendo secciones actualizamos el menú.
|
||||||
*/
|
*/
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = [ 'section' ]
|
static targets = ["section"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
for (const section of this.sectionTargets) {
|
for (const section of this.sectionTargets) {
|
||||||
this.observer.observe(section)
|
this.observer.observe(section);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Solo nos interesa la primera
|
* Solo nos interesa la primera
|
||||||
*/
|
*/
|
||||||
get observer () {
|
get observer() {
|
||||||
if (!this._observer) this._observer = new IntersectionObserver((entries, observer) => this.update(entries), this.options)
|
if (!this._observer)
|
||||||
|
this._observer = new IntersectionObserver(
|
||||||
|
(entries, observer) => this.update(entries),
|
||||||
|
this.options
|
||||||
|
);
|
||||||
|
|
||||||
return this._observer
|
return this._observer;
|
||||||
}
|
}
|
||||||
|
|
||||||
get options () {
|
get options() {
|
||||||
if (!this._options) this._options = { threshold: 0, rootMargin: '0px' }
|
if (!this._options) this._options = { threshold: 0, rootMargin: "0px" };
|
||||||
|
|
||||||
return this._options
|
return this._options;
|
||||||
}
|
}
|
||||||
|
|
||||||
update (entries) {
|
update(entries) {
|
||||||
const section = entries.find(x => x.isIntersecting)
|
const section = entries.find((x) => x.isIntersecting);
|
||||||
|
|
||||||
if (!section) return
|
if (!section) return;
|
||||||
|
|
||||||
window.dispatchEvent(new CustomEvent('scroll:section', { detail: { id: section.target.id }}))
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("scroll:section", { detail: { id: section.target.id } })
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +1,96 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
import { Liquid } from 'liquidjs'
|
import { Liquid } from "liquidjs";
|
||||||
|
|
||||||
const lunr = require("lunr")
|
const lunr = require("lunr");
|
||||||
require("lunr-languages/lunr.stemmer.support")(lunr)
|
require("lunr-languages/lunr.stemmer.support")(lunr);
|
||||||
require("lunr-languages/lunr.es")(lunr)
|
require("lunr-languages/lunr.es")(lunr);
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = [ 'q' ]
|
static targets = ["q"];
|
||||||
|
|
||||||
get q () {
|
get q() {
|
||||||
if (!this.hasQTarget) return
|
if (!this.hasQTarget) return;
|
||||||
if (!this.qTarget.value.trim().length === 0) return
|
if (!this.qTarget.value.trim().length === 0) return;
|
||||||
|
|
||||||
return this.qTarget.value.trim().replaceAll(/[:~\*\^\+\-]/gi, '')
|
return this.qTarget.value.trim().replaceAll(/[:~\*\^\+\-]/gi, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
const q = new URLSearchParams(window.location.search).get('q')?.trim()
|
const q = new URLSearchParams(window.location.search).get("q")?.trim();
|
||||||
|
|
||||||
if (q) {
|
if (q) {
|
||||||
this.qTarget.value = q
|
this.qTarget.value = q;
|
||||||
this.search()
|
this.search();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async search (event) {
|
async search(event) {
|
||||||
// Detiene el envío del formulario
|
// Detiene el envío del formulario
|
||||||
if (event) {
|
if (event) {
|
||||||
event.preventDefault()
|
event.preventDefault();
|
||||||
event.stopPropagation()
|
event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.formDisable = true
|
this.formDisable = true;
|
||||||
|
|
||||||
// Obtiene el término de búsqueda
|
// Obtiene el término de búsqueda
|
||||||
const q = this.q
|
const q = this.q;
|
||||||
// Si no hay término de búsqueda, no hay búsqueda
|
// Si no hay término de búsqueda, no hay búsqueda
|
||||||
if (q) {
|
if (q) {
|
||||||
// Trae el índice de búsqueda
|
// Trae el índice de búsqueda
|
||||||
await this.fetch()
|
await this.fetch();
|
||||||
|
|
||||||
// Hasta que no haya índice no buscamos nada, esto evita que se
|
// Hasta que no haya índice no buscamos nada, esto evita que se
|
||||||
// aprete enter dos veces y se fallen cosas.
|
// aprete enter dos veces y se fallen cosas.
|
||||||
if (!window.index) return
|
if (!window.index) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const main = document.querySelector('main')
|
const main = document.querySelector("main");
|
||||||
const results = window.index.search(q).map(r => window.data.find(a => a.id == r.ref))
|
const results = window.index
|
||||||
const site = window.site
|
.search(q)
|
||||||
const template = window.templates.results
|
.map((r) => window.data.find((a) => a.id == r.ref));
|
||||||
const html = await this.engine.parseAndRender(template, { q, site, results })
|
const site = window.site;
|
||||||
const title = `${site.i18n.search.title} - ${q}`
|
const template = window.templates.results;
|
||||||
const query = new URLSearchParams({ q })
|
const html = await this.engine.parseAndRender(template, {
|
||||||
|
q,
|
||||||
|
site,
|
||||||
|
results,
|
||||||
|
});
|
||||||
|
const title = `${site.i18n.search.title} - ${q}`;
|
||||||
|
const query = new URLSearchParams({ q });
|
||||||
|
|
||||||
window.history.pushState({ q }, title, `?${query.toString()}`)
|
window.history.pushState({ q }, title, `?${query.toString()}`);
|
||||||
document.title = title
|
document.title = title;
|
||||||
|
|
||||||
main.innerHTML = html
|
main.innerHTML = html;
|
||||||
this.formDisable = false
|
this.formDisable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetch () {
|
async fetch() {
|
||||||
// Solo permite descargar uno a la vez
|
// Solo permite descargar uno a la vez
|
||||||
if (this.fetching) return
|
if (this.fetching) return;
|
||||||
|
|
||||||
this.fetching = true
|
this.fetching = true;
|
||||||
let response
|
let response;
|
||||||
|
|
||||||
// Si no existe el índice, lo descarga y procesa Lunr
|
// Si no existe el índice, lo descarga y procesa Lunr
|
||||||
if (!window.data) {
|
if (!window.data) {
|
||||||
response = await fetch('data.json')
|
response = await fetch("data.json");
|
||||||
window.data = await response.json()
|
window.data = await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!window.index) {
|
if (!window.index) {
|
||||||
response = await fetch('idx.json')
|
response = await fetch("idx.json");
|
||||||
const idx = await response.json()
|
const idx = await response.json();
|
||||||
window.index = lunr.Index.load(idx)
|
window.index = lunr.Index.load(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Permitir volver a ejecutar
|
// Permitir volver a ejecutar
|
||||||
this.fetching = false
|
this.fetching = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
set formDisable (disable) {
|
set formDisable(disable) {
|
||||||
this.element.elements.forEach(x => x.disabled = disable)
|
this.element.elements.forEach((x) => (x.disabled = disable));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -92,9 +98,9 @@ export default class extends Controller {
|
||||||
*
|
*
|
||||||
* @return Liquid
|
* @return Liquid
|
||||||
*/
|
*/
|
||||||
get engine () {
|
get engine() {
|
||||||
if (!window.liquid) window.liquid = new Liquid()
|
if (!window.liquid) window.liquid = new Liquid();
|
||||||
|
|
||||||
return window.liquid
|
return window.liquid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static values = {
|
static values = {
|
||||||
title: String,
|
title: String,
|
||||||
text: String,
|
text: String,
|
||||||
url: String
|
url: String,
|
||||||
}
|
};
|
||||||
|
|
||||||
async share (event = undefined) {
|
async share(event = undefined) {
|
||||||
event?.preventDefault()
|
event?.preventDefault();
|
||||||
event?.stopPropagation()
|
event?.stopPropagation();
|
||||||
|
|
||||||
const title = this.titleValue
|
const title = this.titleValue;
|
||||||
const text = this.textValue
|
const text = this.textValue;
|
||||||
const url = this.urlValue
|
const url = this.urlValue;
|
||||||
const data = { title, text, url }
|
const data = { title, text, url };
|
||||||
|
|
||||||
if ('share' in navigator) {
|
if ("share" in navigator) {
|
||||||
if (navigator.canShare(data)) {
|
if (navigator.canShare(data)) {
|
||||||
navigator.share(data)
|
navigator.share(data);
|
||||||
} else {
|
} else {
|
||||||
console.error('No se puede compartir', data)
|
console.error("No se puede compartir", data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +1,73 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Slider con scroll automático
|
* Slider con scroll automático
|
||||||
*/
|
*/
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = [ 'control' ]
|
static targets = ["control"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
this.active(this.controlTargets.find(x => x.href.endsWith(window.location.hash)))
|
this.active(
|
||||||
|
this.controlTargets.find((x) => x.href.endsWith(window.location.hash))
|
||||||
|
);
|
||||||
|
|
||||||
this.interval = setInterval(() => this.inViewport ? this.controlTargets[this.next].click() : null, this.duration * 1000)
|
this.interval = setInterval(
|
||||||
|
() => (this.inViewport ? this.controlTargets[this.next].click() : null),
|
||||||
|
this.duration * 1000
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get duration () {
|
get duration() {
|
||||||
const duration = parseInt(this.data.get('duration'))
|
const duration = parseInt(this.data.get("duration"));
|
||||||
|
|
||||||
return isNaN(duration) ? 15 : duration
|
return isNaN(duration) ? 15 : duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnect () {
|
disconnect() {
|
||||||
clearInterval(this.interval)
|
clearInterval(this.interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
active (control) {
|
active(control) {
|
||||||
if (!control) return
|
if (!control) return;
|
||||||
|
|
||||||
this.controlTargets.forEach(other => other.classList.toggle('active', control.href === other.href))
|
this.controlTargets.forEach((other) =>
|
||||||
this.current = this.controlTargets.indexOf(control)
|
other.classList.toggle("active", control.href === other.href)
|
||||||
|
);
|
||||||
|
this.current = this.controlTargets.indexOf(control);
|
||||||
}
|
}
|
||||||
|
|
||||||
activate (event) {
|
activate(event) {
|
||||||
// XXX: En Firefox, el target del evento también puede ser el
|
// XXX: En Firefox, el target del evento también puede ser el
|
||||||
// contenido del link :/
|
// contenido del link :/
|
||||||
let t = (event.target.href) ? event.target : event.target.parentElement
|
let t = event.target.href ? event.target : event.target.parentElement;
|
||||||
|
|
||||||
this.active(t)
|
this.active(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
get current () {
|
get current() {
|
||||||
return parseInt(this.data.get('current')) || 0
|
return parseInt(this.data.get("current")) || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
set current (value) {
|
set current(value) {
|
||||||
this.data.set('current', value)
|
this.data.set("current", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
get next () {
|
get next() {
|
||||||
const next = this.current + 1
|
const next = this.current + 1;
|
||||||
|
|
||||||
return (this.controlTargets[next]) ? next : 0
|
return this.controlTargets[next] ? next : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
get inViewport () {
|
get inViewport() {
|
||||||
const bounding = this.element.getBoundingClientRect();
|
const bounding = this.element.getBoundingClientRect();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
bounding.top >= 0 &&
|
bounding.top >= 0 &&
|
||||||
bounding.left >= 0 &&
|
bounding.left >= 0 &&
|
||||||
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
|
bounding.bottom <=
|
||||||
bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
|
(window.innerHeight || document.documentElement.clientHeight) &&
|
||||||
|
bounding.right <=
|
||||||
|
(window.innerWidth || document.documentElement.clientWidth)
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { CartBaseController } from './cart_base_controller'
|
import { CartBaseController } from "./cart_base_controller";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populates a state field where users can type to filter and select
|
* Populates a state field where users can type to filter and select
|
||||||
|
@ -7,85 +7,91 @@ import { CartBaseController } from './cart_base_controller'
|
||||||
*/
|
*/
|
||||||
export default class extends CartBaseController {
|
export default class extends CartBaseController {
|
||||||
// All are required!
|
// All are required!
|
||||||
static targets = [ 'id', 'list', 'name' ]
|
static targets = ["id", "list", "name"];
|
||||||
|
|
||||||
connect () {
|
connect() {
|
||||||
window.addEventListener('cart:country:update', async event => {
|
window.addEventListener("cart:country:update", async (event) => {
|
||||||
if (this.data.get('group') !== event.detail.group) return
|
if (this.data.get("group") !== event.detail.group) return;
|
||||||
|
|
||||||
this.idTarget.value = ''
|
this.idTarget.value = "";
|
||||||
this.nameTarget.value = ''
|
this.nameTarget.value = "";
|
||||||
this.listTarget.innerHTML = ''
|
this.listTarget.innerHTML = "";
|
||||||
|
|
||||||
const statesRequired = event.detail.data.statesRequired == 'true'
|
const statesRequired = event.detail.data.statesRequired == "true";
|
||||||
|
|
||||||
this.nameTarget.disabled = !statesRequired
|
this.nameTarget.disabled = !statesRequired;
|
||||||
this.nameTarget.required = statesRequired
|
this.nameTarget.required = statesRequired;
|
||||||
|
|
||||||
if (!statesRequired) return
|
if (!statesRequired) return;
|
||||||
|
|
||||||
const states = await this.states(event.detail.iso)
|
const states = await this.states(event.detail.iso);
|
||||||
const site = window.site
|
const site = window.site;
|
||||||
|
|
||||||
states.forEach(state => {
|
states.forEach((state) => {
|
||||||
let option = document.createElement('option')
|
let option = document.createElement("option");
|
||||||
option.value = state.attributes.name
|
option.value = state.attributes.name;
|
||||||
option.dataset.id = state.id
|
option.dataset.id = state.id;
|
||||||
|
|
||||||
this.listTarget.appendChild(option)
|
this.listTarget.appendChild(option);
|
||||||
})
|
});
|
||||||
|
|
||||||
this.nameTarget.pattern = states.map(x => x.attributes.name).join('|')
|
this.nameTarget.pattern = states.map((x) => x.attributes.name).join("|");
|
||||||
this.nameTarget.addEventListener('input', event => this.nameTarget.setCustomValidity(''))
|
this.nameTarget.addEventListener("input", (event) =>
|
||||||
this.nameTarget.addEventListener('invalid', event => this.nameTarget.setCustomValidity(site.i18n.states.validation))
|
this.nameTarget.setCustomValidity("")
|
||||||
|
);
|
||||||
|
this.nameTarget.addEventListener("invalid", (event) =>
|
||||||
|
this.nameTarget.setCustomValidity(site.i18n.states.validation)
|
||||||
|
);
|
||||||
|
|
||||||
if (event.detail.selectedState) {
|
if (event.detail.selectedState) {
|
||||||
this.nameTarget.value = event.detail.selectedState
|
this.nameTarget.value = event.detail.selectedState;
|
||||||
this.nameTarget.dispatchEvent(new Event('change'))
|
this.nameTarget.dispatchEvent(new Event("change"));
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// When the input changes we update the actual value and also the
|
// When the input changes we update the actual value and also the
|
||||||
// state list via an Event
|
// state list via an Event
|
||||||
this.nameTarget.addEventListener('change', event => {
|
this.nameTarget.addEventListener("change", (event) => {
|
||||||
const options = Array.from(this.listTarget.options)
|
const options = Array.from(this.listTarget.options);
|
||||||
const option = options.find(x => x.value == this.nameTarget.value)
|
const option = options.find((x) => x.value == this.nameTarget.value);
|
||||||
|
|
||||||
// TODO: If no option is found, mark the field as invalid
|
// TODO: If no option is found, mark the field as invalid
|
||||||
if (!option) return
|
if (!option) return;
|
||||||
|
|
||||||
this.idTarget.value = option.dataset.id
|
this.idTarget.value = option.dataset.id;
|
||||||
this.idTarget.dispatchEvent(new Event('change'))
|
this.idTarget.dispatchEvent(new Event("change"));
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch the state list from storage or from API using a country ISO
|
* Fetch the state list from storage or from API using a country ISO
|
||||||
* code
|
* code
|
||||||
*/
|
*/
|
||||||
async states (countryIso) {
|
async states(countryIso) {
|
||||||
const stateId = `states:${countryIso}`
|
const stateId = `states:${countryIso}`;
|
||||||
let states = JSON.parse(this.storageTemp.getItem(stateId))
|
let states = JSON.parse(this.storageTemp.getItem(stateId));
|
||||||
|
|
||||||
if (states) return states
|
if (states) return states;
|
||||||
|
|
||||||
// There's no state query, but we can fetch the country and include
|
// There's no state query, but we can fetch the country and include
|
||||||
// its states.
|
// its states.
|
||||||
const response = await this.spree.countries.show(countryIso, { include: 'states' })
|
const response = await this.spree.countries.show(countryIso, {
|
||||||
|
include: "states",
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: Show error message
|
// TODO: Show error message
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
this.handleFailure(response)
|
this.handleFailure(response);
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
states = response.success().included
|
states = response.success().included;
|
||||||
|
|
||||||
// Order alphabetically by name
|
// Order alphabetically by name
|
||||||
states.sort((x, y) => x.attributes.name > y.attributes.name)
|
states.sort((x, y) => x.attributes.name > y.attributes.name);
|
||||||
|
|
||||||
this.storageTemp.setItem(stateId, JSON.stringify(states))
|
this.storageTemp.setItem(stateId, JSON.stringify(states));
|
||||||
|
|
||||||
return states
|
return states;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Controller } from 'stimulus'
|
import { Controller } from "stimulus";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mantiene el stock actualizado, consultando a la API.
|
* Mantiene el stock actualizado, consultando a la API.
|
||||||
|
@ -9,48 +9,48 @@ import { Controller } from 'stimulus'
|
||||||
* * Deshabilita botón si no está en stock
|
* * Deshabilita botón si no está en stock
|
||||||
*/
|
*/
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = [ 'product' ]
|
static targets = ["product"];
|
||||||
|
|
||||||
async connect () {
|
async connect() {
|
||||||
const all_skus = this.skus
|
const all_skus = this.skus;
|
||||||
|
|
||||||
if (all_skus.length === 0) return
|
if (all_skus.length === 0) return;
|
||||||
|
|
||||||
// El paginado es para prevenir que la petición se haga muy grande y
|
// El paginado es para prevenir que la petición se haga muy grande y
|
||||||
// falle entera.
|
// falle entera.
|
||||||
const pages = Math.ceil(all_skus.length / this.per_page)
|
const pages = Math.ceil(all_skus.length / this.per_page);
|
||||||
|
|
||||||
let start = 0
|
let start = 0;
|
||||||
let end = this.per_page
|
let end = this.per_page;
|
||||||
|
|
||||||
for (let local_page = 1; local_page <= pages; local_page++) {
|
for (let local_page = 1; local_page <= pages; local_page++) {
|
||||||
const skus = all_skus.slice(start, end).join(',')
|
const skus = all_skus.slice(start, end).join(",");
|
||||||
|
|
||||||
start = this.per_page * local_page
|
start = this.per_page * local_page;
|
||||||
end = start + this.per_page
|
end = start + this.per_page;
|
||||||
|
|
||||||
const filter = { skus }
|
const filter = { skus };
|
||||||
let response = await window.spree.products.list({ filter })
|
let response = await window.spree.products.list({ filter });
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
console.error(response.fail())
|
console.error(response.fail());
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.update_local_products(response.success().data)
|
this.update_local_products(response.success().data);
|
||||||
|
|
||||||
// Recorrer todas las páginas
|
// Recorrer todas las páginas
|
||||||
// XXX: Podríamos usar next pero la página 1 siempre se devuelve a
|
// XXX: Podríamos usar next pero la página 1 siempre se devuelve a
|
||||||
// sí misma y entraríamos en un loop infinito.
|
// sí misma y entraríamos en un loop infinito.
|
||||||
for (let page = 2; page <= response.success().meta.total_pages; page++) {
|
for (let page = 2; page <= response.success().meta.total_pages; page++) {
|
||||||
response = await window.spree.products.list({ filter, page })
|
response = await window.spree.products.list({ filter, page });
|
||||||
|
|
||||||
if (response.isFail()) {
|
if (response.isFail()) {
|
||||||
console.error(response.fail())
|
console.error(response.fail());
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.update_local_products(response.success().data)
|
this.update_local_products(response.success().data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,34 +62,56 @@ export default class extends Controller {
|
||||||
*
|
*
|
||||||
* @return [Array]
|
* @return [Array]
|
||||||
*/
|
*/
|
||||||
get skus () {
|
get skus() {
|
||||||
return [...new Set(this.productTargets.map(p=> p.dataset.sku).filter(x => x.length > 0))]
|
return [
|
||||||
|
...new Set(
|
||||||
|
this.productTargets
|
||||||
|
.map((p) => p.dataset.sku)
|
||||||
|
.filter((x) => x.length > 0)
|
||||||
|
),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* La cantidad de productos por página que vamos a pedir
|
* La cantidad de productos por página que vamos a pedir
|
||||||
*/
|
*/
|
||||||
get per_page () {
|
get per_page() {
|
||||||
if (!this._per_page) {
|
if (!this._per_page) {
|
||||||
this._per_page = parseInt(this.element.dataset.perPage)
|
this._per_page = parseInt(this.element.dataset.perPage);
|
||||||
if (isNaN(this._per_page)) this._per_page = 100
|
if (isNaN(this._per_page)) this._per_page = 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._per_page
|
return this._per_page;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Los productos pueden estar duplicados así que buscamos todos.
|
* Los productos pueden estar duplicados así que buscamos todos.
|
||||||
*/
|
*/
|
||||||
update_local_products (products) {
|
update_local_products(products) {
|
||||||
for (const local of this.productTargets) {
|
for (const local of this.productTargets) {
|
||||||
for (const product of products.filter(p => local.dataset.cartVariantId === p.relationships.default_variant.data.id)) {
|
for (const product of products.filter(
|
||||||
local.dataset.cartInStock = product.attributes.in_stock
|
(p) =>
|
||||||
local.dataset.cartPrice = product.attributes.price
|
local.dataset.cartVariantId ===
|
||||||
|
p.relationships.default_variant.data.id
|
||||||
|
)) {
|
||||||
|
local.dataset.cartInStock = product.attributes.in_stock;
|
||||||
|
local.dataset.cartPrice = product.attributes.price;
|
||||||
|
|
||||||
local.querySelectorAll('[data-stock-add]').forEach(button => button.disabled = !product.attributes.in_stock)
|
local
|
||||||
local.querySelectorAll('[data-stock-price]').forEach(price => price.innerText = parseInt(product.attributes.price))
|
.querySelectorAll("[data-stock-add]")
|
||||||
local.querySelectorAll('[data-stock-currency]').forEach(currency => currency.innerText = product.attributes.currency)
|
.forEach(
|
||||||
|
(button) => (button.disabled = !product.attributes.in_stock)
|
||||||
|
);
|
||||||
|
local
|
||||||
|
.querySelectorAll("[data-stock-price]")
|
||||||
|
.forEach(
|
||||||
|
(price) => (price.innerText = parseInt(product.attributes.price))
|
||||||
|
);
|
||||||
|
local
|
||||||
|
.querySelectorAll("[data-stock-currency]")
|
||||||
|
.forEach(
|
||||||
|
(currency) => (currency.innerText = product.attributes.currency)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,80 +1,81 @@
|
||||||
import Axios from 'axios'
|
import Axios from "axios";
|
||||||
import * as qs from 'qs'
|
import * as qs from "qs";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX: We're copying code from @spree/storefront-api-v2-sdk/src/Http.ts
|
* XXX: We're copying code from @spree/storefront-api-v2-sdk/src/Http.ts
|
||||||
* because we don't know how to mix Typescript :D
|
* because we don't know how to mix Typescript :D
|
||||||
*/
|
*/
|
||||||
export class Sutty {
|
export class Sutty {
|
||||||
constructor (host = 'http://localhost:3000') {
|
constructor(host = "http://localhost:3000") {
|
||||||
this.host = host
|
this.host = host;
|
||||||
|
|
||||||
this.axios = Axios.create({
|
this.axios = Axios.create({
|
||||||
baseURL: this.host,
|
baseURL: this.host,
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { "Content-Type": "application/json" },
|
||||||
paramsSerializer: params => qs.stringify(params, { arrayFormat: 'brackets' })
|
paramsSerializer: (params) =>
|
||||||
})
|
qs.stringify(params, { arrayFormat: "brackets" }),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCheckoutURL(tokens = {}) {
|
async getCheckoutURL(tokens = {}) {
|
||||||
const headers = this.spreeOrderHeaders(tokens)
|
const headers = this.spreeOrderHeaders(tokens);
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
url: 'api/v2/storefront/checkout_redirect.json',
|
url: "api/v2/storefront/checkout_redirect.json",
|
||||||
params: {},
|
params: {},
|
||||||
method: 'get',
|
method: "get",
|
||||||
headers
|
headers,
|
||||||
}
|
};
|
||||||
|
|
||||||
return await this.axios(axiosConfig)
|
return await this.axios(axiosConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
async assignOrderOwnership(tokens = {}, params = {}) {
|
async assignOrderOwnership(tokens = {}, params = {}) {
|
||||||
const headers = this.spreeOrderHeaders(tokens)
|
const headers = this.spreeOrderHeaders(tokens);
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
url: 'api/v2/storefront/assign_order_ownership.json',
|
url: "api/v2/storefront/assign_order_ownership.json",
|
||||||
params,
|
params,
|
||||||
method: 'post',
|
method: "post",
|
||||||
headers
|
headers,
|
||||||
}
|
};
|
||||||
|
|
||||||
return await this.axios(axiosConfig)
|
return await this.axios(axiosConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
async assignOrderShippingAddress(tokens = {}, params = {}) {
|
async assignOrderShippingAddress(tokens = {}, params = {}) {
|
||||||
const headers = this.spreeOrderHeaders(tokens)
|
const headers = this.spreeOrderHeaders(tokens);
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
url: 'api/v2/storefront/assign_order_shipping_address.json',
|
url: "api/v2/storefront/assign_order_shipping_address.json",
|
||||||
params,
|
params,
|
||||||
method: 'post',
|
method: "post",
|
||||||
headers
|
headers,
|
||||||
}
|
};
|
||||||
|
|
||||||
return await this.axios(axiosConfig)
|
return await this.axios(axiosConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
async assignOrderBillingAddress(tokens = {}, params = {}) {
|
async assignOrderBillingAddress(tokens = {}, params = {}) {
|
||||||
const headers = this.spreeOrderHeaders(tokens)
|
const headers = this.spreeOrderHeaders(tokens);
|
||||||
const axiosConfig = {
|
const axiosConfig = {
|
||||||
url: 'api/v2/storefront/assign_order_billing_address.json',
|
url: "api/v2/storefront/assign_order_billing_address.json",
|
||||||
params,
|
params,
|
||||||
method: 'post',
|
method: "post",
|
||||||
headers
|
headers,
|
||||||
}
|
};
|
||||||
|
|
||||||
return await this.axios(axiosConfig)
|
return await this.axios(axiosConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
spreeOrderHeaders(tokens) {
|
spreeOrderHeaders(tokens) {
|
||||||
const header = {}
|
const header = {};
|
||||||
|
|
||||||
if (tokens.orderToken) {
|
if (tokens.orderToken) {
|
||||||
header['X-Spree-Order-Token'] = tokens.orderToken
|
header["X-Spree-Order-Token"] = tokens.orderToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokens.bearerToken) {
|
if (tokens.bearerToken) {
|
||||||
header['Authorization'] = `Bearer ${tokens.bearerToken}`
|
header["Authorization"] = `Bearer ${tokens.bearerToken}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return header
|
return header;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
import BotDetector from 'device-detector-js/dist/parsers/bot'
|
import BotDetector from "device-detector-js/dist/parsers/bot";
|
||||||
import { Notifier } from '@airbrake/browser'
|
import { Notifier } from "@airbrake/browser";
|
||||||
|
|
||||||
window.bot_detector = new BotDetector
|
window.bot_detector = new BotDetector();
|
||||||
const bot = window.bot_detector.parse(navigator.userAgent)
|
const bot = window.bot_detector.parse(navigator.userAgent);
|
||||||
|
|
||||||
if (!bot) {
|
if (!bot) {
|
||||||
window.airbrake = new Notifier({
|
window.airbrake = new Notifier({
|
||||||
projectId: window.env.AIRBRAKE_PROJECT_ID,
|
projectId: window.env.AIRBRAKE_PROJECT_ID,
|
||||||
projectKey: window.env.AIRBRAKE_PROJECT_KEY,
|
projectKey: window.env.AIRBRAKE_PROJECT_KEY,
|
||||||
host: 'https://panel.sutty.nl'
|
host: "https://panel.sutty.nl",
|
||||||
})
|
});
|
||||||
|
|
||||||
console.originalError = console.error
|
console.originalError = console.error;
|
||||||
console.error = (...e) => {
|
console.error = (...e) => {
|
||||||
window.airbrake.notify(e.join(' '))
|
window.airbrake.notify(e.join(" "));
|
||||||
return console.originalError(...e)
|
return console.originalError(...e);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
import 'core-js/stable'
|
import "core-js/stable";
|
||||||
import 'regenerator-runtime/runtime'
|
import "regenerator-runtime/runtime";
|
||||||
|
|
||||||
// Turbo acelera la navegación al no tener que recargar todo el JS y CSS
|
// Turbo acelera la navegación al no tener que recargar todo el JS y CSS
|
||||||
// de la página, con lo que se siente más rápida y "nativa".
|
// de la página, con lo que se siente más rápida y "nativa".
|
||||||
|
@ -27,46 +27,49 @@ import 'regenerator-runtime/runtime'
|
||||||
// Cambiamos de turbolinks a turbo porque turbo soporta la función
|
// Cambiamos de turbolinks a turbo porque turbo soporta la función
|
||||||
// fetch(), que luego es interceptada por el SW para obtener las
|
// fetch(), que luego es interceptada por el SW para obtener las
|
||||||
// direcciones localmente.
|
// direcciones localmente.
|
||||||
import * as Turbo from "@hotwired/turbo"
|
import * as Turbo from "@hotwired/turbo";
|
||||||
Turbo.start()
|
Turbo.start();
|
||||||
|
|
||||||
import { Application } from 'stimulus'
|
import { Application } from "stimulus";
|
||||||
import { definitionsFromContext } from "stimulus/webpack-helpers"
|
import { definitionsFromContext } from "stimulus/webpack-helpers";
|
||||||
|
|
||||||
const application = Application.start()
|
const application = Application.start();
|
||||||
const context = require.context("./controllers", true, /\.js$/)
|
const context = require.context("./controllers", true, /\.js$/);
|
||||||
application.load(definitionsFromContext(context))
|
application.load(definitionsFromContext(context));
|
||||||
|
|
||||||
import { makeClient } from '@spree/storefront-api-v2-sdk'
|
import { makeClient } from "@spree/storefront-api-v2-sdk";
|
||||||
import { Sutty } from './endpoints/sutty'
|
import { Sutty } from "./endpoints/sutty";
|
||||||
|
|
||||||
window.spree = makeClient({ host: window.env.SPREE_URL })
|
window.spree = makeClient({ host: window.env.SPREE_URL });
|
||||||
window.spree.sutty = new Sutty(window.spree.host)
|
window.spree.sutty = new Sutty(window.spree.host);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
window.axe = require('axe-core/axe')
|
window.axe = require("axe-core/axe");
|
||||||
} catch(e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
if (window.axe) window.axe.configure({ locale: require('axe-core/locales/es.json') })
|
if (window.axe)
|
||||||
|
window.axe.configure({ locale: require("axe-core/locales/es.json") });
|
||||||
|
|
||||||
document.addEventListener('turbo:load', event => {
|
document.addEventListener("turbo:load", (event) => {
|
||||||
document.querySelectorAll("a[href^='http://'],a[href^='https://'],a[href^='//']").forEach(a => {
|
document
|
||||||
a.rel = "noopener"
|
.querySelectorAll("a[href^='http://'],a[href^='https://'],a[href^='//']")
|
||||||
a.target = "_blank"
|
.forEach((a) => {
|
||||||
})
|
a.rel = "noopener";
|
||||||
|
a.target = "_blank";
|
||||||
|
});
|
||||||
|
|
||||||
if (!window.axe) return
|
if (!window.axe) return;
|
||||||
|
|
||||||
window.axe.run().then(results => {
|
window.axe.run().then((results) => {
|
||||||
results.violations.forEach(violation => {
|
results.violations.forEach((violation) => {
|
||||||
violation.nodes.forEach(node => {
|
violation.nodes.forEach((node) => {
|
||||||
node.target.forEach(target => {
|
node.target.forEach((target) => {
|
||||||
document.querySelectorAll(target).forEach(element => {
|
document.querySelectorAll(target).forEach((element) => {
|
||||||
element.classList.add('inaccesible')
|
element.classList.add("inaccesible");
|
||||||
element.ariaLabel = node.failureSummary
|
element.ariaLabel = node.failureSummary;
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
Loading…
Reference in a new issue