404 lines
13 KiB
JavaScript
404 lines
13 KiB
JavaScript
class QuickOrderListRemoveButton extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.addEventListener('click', (event) => {
|
|
event.preventDefault();
|
|
const quickOrderList = this.closest('quick-order-list');
|
|
quickOrderList.updateQuantity(this.dataset.index, 0);
|
|
});
|
|
}
|
|
}
|
|
|
|
customElements.define('quick-order-list-remove-button', QuickOrderListRemoveButton);
|
|
|
|
class QuickOrderListRemoveAllButton extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
const allVariants = Array.from(document.querySelectorAll('[data-variant-id]'));
|
|
const items = {};
|
|
let hasVariantsInCart = false;
|
|
this.quickOrderList = this.closest('quick-order-list');
|
|
|
|
allVariants.forEach((variant) => {
|
|
const cartQty = parseInt(variant.dataset.cartQty);
|
|
if (cartQty > 0) {
|
|
hasVariantsInCart = true;
|
|
items[parseInt(variant.dataset.variantId)] = 0;
|
|
}
|
|
});
|
|
|
|
if (!hasVariantsInCart) {
|
|
this.classList.add('hidden');
|
|
}
|
|
|
|
this.actions = {
|
|
confirm: 'confirm',
|
|
remove: 'remove',
|
|
cancel: 'cancel',
|
|
};
|
|
|
|
this.addEventListener('click', (event) => {
|
|
event.preventDefault();
|
|
if (this.dataset.action === this.actions.confirm) {
|
|
this.toggleConfirmation(false, true);
|
|
} else if (this.dataset.action === this.actions.remove) {
|
|
this.quickOrderList.updateMultipleQty(items);
|
|
this.toggleConfirmation(true, false);
|
|
} else if (this.dataset.action === this.actions.cancel) {
|
|
this.toggleConfirmation(true, false);
|
|
}
|
|
});
|
|
}
|
|
|
|
toggleConfirmation(showConfirmation, showInfo) {
|
|
this.quickOrderList
|
|
.querySelector('.quick-order-list-total__confirmation')
|
|
.classList.toggle('hidden', showConfirmation);
|
|
this.quickOrderList.querySelector('.quick-order-list-total__info').classList.toggle('hidden', showInfo);
|
|
}
|
|
}
|
|
|
|
customElements.define('quick-order-list-remove-all-button', QuickOrderListRemoveAllButton);
|
|
|
|
class QuickOrderList extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.cart = document.querySelector('cart-drawer');
|
|
this.actions = {
|
|
add: 'ADD',
|
|
update: 'UPDATE',
|
|
};
|
|
this.quickOrderListId = 'quick-order-list';
|
|
this.variantItemStatusElement = document.getElementById('shopping-cart-variant-item-status');
|
|
const form = this.querySelector('form');
|
|
|
|
form.addEventListener('submit', this.onSubmit.bind(this));
|
|
|
|
const debouncedOnChange = debounce((event) => {
|
|
this.onChange(event);
|
|
}, ON_CHANGE_DEBOUNCE_TIMER);
|
|
this.addEventListener('change', debouncedOnChange.bind(this));
|
|
}
|
|
|
|
cartUpdateUnsubscriber = undefined;
|
|
|
|
onSubmit(event) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
connectedCallback() {
|
|
this.cartUpdateUnsubscriber = subscribe(PUB_SUB_EVENTS.cartUpdate, (event) => {
|
|
if (event.source === this.quickOrderListId) {
|
|
return;
|
|
}
|
|
// If its another section that made the update
|
|
this.onCartUpdate();
|
|
});
|
|
this.sectionId = this.dataset.id;
|
|
}
|
|
|
|
disconnectedCallback() {
|
|
if (this.cartUpdateUnsubscriber) {
|
|
this.cartUpdateUnsubscriber();
|
|
}
|
|
}
|
|
|
|
onChange(event) {
|
|
const inputValue = parseInt(event.target.value);
|
|
const cartQuantity = parseInt(event.target.dataset.cartQuantity);
|
|
const index = event.target.dataset.index;
|
|
const name = document.activeElement.getAttribute('name');
|
|
|
|
const quantity = inputValue - cartQuantity;
|
|
|
|
if (cartQuantity > 0) {
|
|
this.updateQuantity(index, inputValue, name, this.actions.update);
|
|
} else {
|
|
this.updateQuantity(index, quantity, name, this.actions.add);
|
|
}
|
|
}
|
|
|
|
onCartUpdate() {
|
|
fetch(`${window.location.pathname}?section_id=${this.sectionId}`)
|
|
.then((response) => response.text())
|
|
.then((responseText) => {
|
|
const html = new DOMParser().parseFromString(responseText, 'text/html');
|
|
const sourceQty = html.querySelector(this.quickOrderListId);
|
|
this.innerHTML = sourceQty.innerHTML;
|
|
})
|
|
.catch((e) => {
|
|
console.error(e);
|
|
});
|
|
}
|
|
|
|
getSectionsToRender() {
|
|
return [
|
|
{
|
|
id: this.quickOrderListId,
|
|
section: document.getElementById(this.quickOrderListId).dataset.id,
|
|
selector: '.js-contents',
|
|
},
|
|
{
|
|
id: 'cart-icon-bubble',
|
|
section: 'cart-icon-bubble',
|
|
selector: '.shopify-section',
|
|
},
|
|
{
|
|
id: 'quick-order-list-live-region-text',
|
|
section: 'cart-live-region-text',
|
|
selector: '.shopify-section',
|
|
},
|
|
{
|
|
id: 'quick-order-list-total',
|
|
section: document.getElementById(this.quickOrderListId).dataset.id,
|
|
selector: '.quick-order-list__total',
|
|
},
|
|
{
|
|
id: 'CartDrawer',
|
|
selector: '#CartDrawer',
|
|
section: 'cart-drawer',
|
|
},
|
|
];
|
|
}
|
|
|
|
renderSections(parsedState) {
|
|
this.getSectionsToRender().forEach((section) => {
|
|
const sectionElement = document.getElementById(section.id);
|
|
if (sectionElement && sectionElement.parentElement && sectionElement.parentElement.classList.contains('drawer')) {
|
|
parsedState.items.length > 0
|
|
? sectionElement.parentElement.classList.remove('is-empty')
|
|
: sectionElement.parentElement.classList.add('is-empty');
|
|
|
|
setTimeout(() => {
|
|
document.querySelector('#CartDrawer-Overlay').addEventListener('click', this.cart.close.bind(this.cart));
|
|
});
|
|
}
|
|
const elementToReplace =
|
|
sectionElement && sectionElement.querySelector(section.selector)
|
|
? sectionElement.querySelector(section.selector)
|
|
: sectionElement;
|
|
if (elementToReplace) {
|
|
elementToReplace.innerHTML = this.getSectionInnerHTML(parsedState.sections[section.section], section.selector);
|
|
}
|
|
});
|
|
}
|
|
|
|
updateMultipleQty(items) {
|
|
this.querySelector('.variant-remove-total .loading__spinner').classList.remove('hidden');
|
|
|
|
const body = JSON.stringify({
|
|
updates: items,
|
|
sections: this.getSectionsToRender().map((section) => section.section),
|
|
sections_url: window.location.pathname,
|
|
});
|
|
|
|
this.updateMessage();
|
|
this.setErrorMessage();
|
|
|
|
fetch(`${routes.cart_update_url}`, { ...fetchConfig(), ...{ body } })
|
|
.then((response) => {
|
|
return response.text();
|
|
})
|
|
.then((state) => {
|
|
const parsedState = JSON.parse(state);
|
|
this.renderSections(parsedState);
|
|
})
|
|
.catch(() => {
|
|
this.setErrorMessage(window.cartStrings.error);
|
|
})
|
|
.finally(() => {
|
|
this.querySelector('.variant-remove-total .loading__spinner').classList.add('hidden');
|
|
});
|
|
}
|
|
|
|
updateQuantity(id, quantity, name, action) {
|
|
this.toggleLoading(id, true);
|
|
|
|
let routeUrl = routes.cart_change_url;
|
|
let body = JSON.stringify({
|
|
quantity,
|
|
id,
|
|
sections: this.getSectionsToRender().map((section) => section.section),
|
|
sections_url: window.location.pathname,
|
|
});
|
|
let fetchConfigType;
|
|
if (action === this.actions.add) {
|
|
fetchConfigType = 'javascript';
|
|
routeUrl = routes.cart_add_url;
|
|
body = JSON.stringify({
|
|
items: [
|
|
{
|
|
quantity: parseInt(quantity),
|
|
id: parseInt(id),
|
|
},
|
|
],
|
|
sections: this.getSectionsToRender().map((section) => section.section),
|
|
sections_url: window.location.pathname,
|
|
});
|
|
}
|
|
|
|
this.updateMessage();
|
|
this.setErrorMessage();
|
|
|
|
fetch(`${routeUrl}`, { ...fetchConfig(fetchConfigType), ...{ body } })
|
|
.then((response) => {
|
|
return response.text();
|
|
})
|
|
.then((state) => {
|
|
const parsedState = JSON.parse(state);
|
|
const quantityElement = document.getElementById(`Quantity-${id}`);
|
|
const items = document.querySelectorAll('.variant-item');
|
|
|
|
if (parsedState.description || parsedState.errors) {
|
|
const variantItem = document.querySelector(
|
|
`[id^="Variant-${id}"] .variant-item__totals.small-hide .loading__spinner`
|
|
);
|
|
variantItem.classList.add('loading__spinner--error');
|
|
this.resetQuantityInput(id, quantityElement);
|
|
if (parsedState.errors) {
|
|
this.updateLiveRegions(id, parsedState.errors);
|
|
} else {
|
|
this.updateLiveRegions(id, parsedState.description);
|
|
}
|
|
return;
|
|
}
|
|
|
|
this.classList.toggle('is-empty', parsedState.item_count === 0);
|
|
|
|
this.renderSections(parsedState);
|
|
|
|
let hasError = false;
|
|
|
|
const currentItem = parsedState.items.find((item) => item.variant_id === parseInt(id));
|
|
const updatedValue = currentItem ? currentItem.quantity : undefined;
|
|
if (updatedValue && updatedValue !== quantity) {
|
|
this.updateError(updatedValue, id);
|
|
hasError = true;
|
|
}
|
|
|
|
const variantItem = document.getElementById(`Variant-${id}`);
|
|
if (variantItem && variantItem.querySelector(`[name="${name}"]`)) {
|
|
variantItem.querySelector(`[name="${name}"]`).focus();
|
|
}
|
|
publish(PUB_SUB_EVENTS.cartUpdate, { source: this.quickOrderListId, cartData: parsedState });
|
|
|
|
if (hasError) {
|
|
this.updateMessage();
|
|
} else if (action === this.actions.add) {
|
|
this.updateMessage(parseInt(quantity));
|
|
} else if (action === this.actions.update) {
|
|
this.updateMessage(parseInt(quantity - quantityElement.dataset.cartQuantity));
|
|
} else {
|
|
this.updateMessage(-parseInt(quantityElement.dataset.cartQuantity));
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
this.querySelectorAll('.loading__spinner').forEach((overlay) => overlay.classList.add('hidden'));
|
|
this.resetQuantityInput(id);
|
|
console.error(error);
|
|
this.setErrorMessage(window.cartStrings.error);
|
|
})
|
|
.finally(() => {
|
|
this.toggleLoading(id);
|
|
});
|
|
}
|
|
|
|
resetQuantityInput(id, quantityElement) {
|
|
const input = quantityElement ?? document.getElementById(`Quantity-${id}`);
|
|
input.value = input.getAttribute('value');
|
|
}
|
|
|
|
setErrorMessage(message = null) {
|
|
this.errorMessageTemplate =
|
|
this.errorMessageTemplate ??
|
|
document.getElementById(`QuickOrderListErrorTemplate-${this.sectionId}`).cloneNode(true);
|
|
const errorElements = document.querySelectorAll('.quick-order-list-error');
|
|
|
|
errorElements.forEach((errorElement) => {
|
|
errorElement.innerHTML = '';
|
|
if (!message) return;
|
|
const updatedMessageElement = this.errorMessageTemplate.cloneNode(true);
|
|
updatedMessageElement.content.querySelector('.quick-order-list-error-message').innerText = message;
|
|
errorElement.appendChild(updatedMessageElement.content);
|
|
});
|
|
}
|
|
|
|
updateMessage(quantity = null) {
|
|
const messages = this.querySelectorAll('.quick-order-list__message-text');
|
|
const icons = this.querySelectorAll('.quick-order-list__message-icon');
|
|
|
|
if (quantity === null || isNaN(quantity)) {
|
|
messages.forEach((message) => (message.innerHTML = ''));
|
|
icons.forEach((icon) => icon.classList.add('hidden'));
|
|
return;
|
|
}
|
|
|
|
const isQuantityNegative = quantity < 0;
|
|
const absQuantity = Math.abs(quantity);
|
|
|
|
const textTemplate = isQuantityNegative
|
|
? absQuantity === 1
|
|
? window.quickOrderListStrings.itemRemoved
|
|
: window.quickOrderListStrings.itemsRemoved
|
|
: quantity === 1
|
|
? window.quickOrderListStrings.itemAdded
|
|
: window.quickOrderListStrings.itemsAdded;
|
|
|
|
messages.forEach((msg) => (msg.innerHTML = textTemplate.replace('[quantity]', absQuantity)));
|
|
|
|
if (!isQuantityNegative) {
|
|
icons.forEach((i) => i.classList.remove('hidden'));
|
|
}
|
|
}
|
|
|
|
updateError(updatedValue, id) {
|
|
let message = '';
|
|
if (typeof updatedValue === 'undefined') {
|
|
message = window.cartStrings.error;
|
|
} else {
|
|
message = window.cartStrings.quantityError.replace('[quantity]', updatedValue);
|
|
}
|
|
this.updateLiveRegions(id, message);
|
|
}
|
|
|
|
updateLiveRegions(id, message) {
|
|
const variantItemErrorDesktop = document.getElementById(`Quick-order-list-item-error-desktop-${id}`);
|
|
const variantItemErrorMobile = document.getElementById(`Quick-order-list-item-error-mobile-${id}`);
|
|
if (variantItemErrorDesktop) {
|
|
variantItemErrorDesktop.querySelector('.variant-item__error-text').innerHTML = message;
|
|
variantItemErrorDesktop.closest('tr').classList.remove('hidden');
|
|
}
|
|
if (variantItemErrorMobile) variantItemErrorMobile.querySelector('.variant-item__error-text').innerHTML = message;
|
|
|
|
this.variantItemStatusElement.setAttribute('aria-hidden', true);
|
|
|
|
const cartStatus = document.getElementById('quick-order-list-live-region-text');
|
|
cartStatus.setAttribute('aria-hidden', false);
|
|
|
|
setTimeout(() => {
|
|
cartStatus.setAttribute('aria-hidden', true);
|
|
}, 1000);
|
|
}
|
|
|
|
getSectionInnerHTML(html, selector) {
|
|
return new DOMParser().parseFromString(html, 'text/html').querySelector(selector).innerHTML;
|
|
}
|
|
|
|
toggleLoading(id, enable) {
|
|
const quickOrderList = document.getElementById(this.quickOrderListId);
|
|
const quickOrderListItems = this.querySelectorAll(`#Variant-${id} .loading__spinner`);
|
|
|
|
if (enable) {
|
|
quickOrderList.classList.add('quick-order-list__container--disabled');
|
|
[...quickOrderListItems].forEach((overlay) => overlay.classList.remove('hidden'));
|
|
document.activeElement.blur();
|
|
this.variantItemStatusElement.setAttribute('aria-hidden', false);
|
|
} else {
|
|
quickOrderList.classList.remove('quick-order-list__container--disabled');
|
|
quickOrderListItems.forEach((overlay) => overlay.classList.add('hidden'));
|
|
}
|
|
}
|
|
}
|
|
|
|
customElements.define('quick-order-list', QuickOrderList);
|