Files
linumiq-shopify-theme/assets/quick-add-bulk.js
T
2026-08-24 21:41:12 +02:00

207 lines
6.9 KiB
JavaScript

if (!customElements.get('quick-add-bulk')) {
customElements.define(
'quick-add-bulk',
class QuickAddBulk extends BulkAdd {
constructor() {
super();
this.quantity = this.querySelector('quantity-input');
const debouncedOnChange = debounce((event) => {
if (parseInt(event.target.value) === 0) {
this.startQueue(event.target.dataset.index, parseInt(event.target.value));
} else {
this.validateQuantity(event);
}
}, ON_CHANGE_DEBOUNCE_TIMER);
this.addEventListener('change', debouncedOnChange.bind(this));
this.listenForActiveInput();
this.listenForKeydown();
this.lastActiveInputId = null;
}
connectedCallback() {
this.cartUpdateUnsubscriber = subscribe(PUB_SUB_EVENTS.cartUpdate, (event) => {
if (
event.source === 'quick-add' ||
(event.cartData.items && !event.cartData.items.some((item) => item.id === parseInt(this.dataset.index))) ||
(event.cartData.variant_id && !(event.cartData.variant_id === parseInt(this.dataset.index)))
) {
return;
}
// If its another section that made the update
this.onCartUpdate().then(() => {
this.listenForActiveInput();
this.listenForKeydown();
});
});
}
disconnectedCallback() {
if (this.cartUpdateUnsubscriber) {
this.cartUpdateUnsubscriber();
}
}
get input() {
return this.querySelector('quantity-input input');
}
selectProgressBar() {
return this.querySelector('.progress-bar-container');
}
listenForActiveInput() {
if (!this.classList.contains('hidden')) {
this.input?.addEventListener('focusin', (event) => event.target.select());
}
this.isEnterPressed = false;
}
listenForKeydown() {
this.input?.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
this.input?.blur();
this.isEnterPressed = true;
}
});
}
cleanErrorMessageOnType(event) {
event.target.addEventListener(
'keypress',
() => {
event.target.setCustomValidity('');
},
{ once: true }
);
}
get sectionId() {
if (!this._sectionId) {
this._sectionId = this.closest('.collection-quick-add-bulk').dataset.id;
}
return this._sectionId;
}
onCartUpdate() {
return new Promise((resolve, reject) => {
fetch(`${this.getSectionsUrl()}?section_id=${this.sectionId}`)
.then((response) => response.text())
.then((responseText) => {
const html = new DOMParser().parseFromString(responseText, 'text/html');
const sourceQty = html.querySelector(`#quick-add-bulk-${this.dataset.index}-${this.sectionId}`);
if (sourceQty) {
this.innerHTML = sourceQty.innerHTML;
}
resolve();
})
.catch((e) => {
console.error(e);
reject(e);
});
});
}
getSectionsUrl() {
const pageParams = new URLSearchParams(window.location.search);
const pageNumber = decodeURIComponent(pageParams.get('page') || '');
return `${window.location.pathname}${pageNumber ? `?page=${pageNumber}` : ''}`;
}
updateMultipleQty(items) {
this.selectProgressBar().classList.remove('hidden');
const ids = Object.keys(items);
const linesUpdate = this.startCartLinesUpdate(items);
const body = JSON.stringify({
updates: items,
sections: this.getSectionsToRender().map((section) => section.section),
sections_url: this.getSectionsUrl(),
});
fetch(`${routes.cart_update_url}`, { ...fetchConfig(), ...{ body } })
.then((response) => response.json())
.then((parsedState) => {
if (parsedState.errors) {
throw Object.assign(new Error(parsedState.errors), { code: 'INVALID' });
}
linesUpdate?.resolve(parsedState);
this.renderSections(parsedState, ids);
publish(PUB_SUB_EVENTS.cartUpdate, { source: 'quick-add', cartData: parsedState });
})
.catch((e) => {
if (e.code !== 'INVALID') console.error(e);
this.dispatchCartErrorEvent(
e.code === 'INVALID' ? e.message : window.cartStrings.error,
e.code || 'SERVICE_UNAVAILABLE'
);
linesUpdate?.reject(e);
// Commented out for now and will be fixed when BE issue is done https://github.com/Shopify/shopify/issues/440605
// e.target.setCustomValidity(error);
// e.target.reportValidity();
// this.resetQuantityInput(ids[index]);
// this.selectProgressBar().classList.add('hidden');
// e.target.select();
// this.cleanErrorMessageOnType(e);
})
.finally(() => {
this.selectProgressBar().classList.add('hidden');
this.setRequestStarted(false);
});
}
getSectionsToRender() {
return [
{
id: `quick-add-bulk-${this.dataset.index}-${this.sectionId}`,
section: this.sectionId,
selector: `#quick-add-bulk-${this.dataset.index}-${this.sectionId}`,
},
{
id: 'cart-icon-bubble',
section: 'cart-icon-bubble',
selector: '.shopify-section',
},
{
id: 'CartDrawer',
selector: '.drawer__inner',
section: 'cart-drawer',
},
];
}
renderSections(parsedState, ids) {
const intersection = this.queue.filter((element) => ids.includes(element.id));
if (intersection.length !== 0) return;
this.getSectionsToRender().forEach((section) => {
const sectionElement = document.getElementById(section.id);
if (section.section === 'cart-drawer') {
sectionElement.closest('cart-drawer')?.classList.toggle('is-empty', parsedState.items.length.length === 0);
}
const elementToReplace =
sectionElement && sectionElement.querySelector(section.selector)
? sectionElement.querySelector(section.selector)
: sectionElement;
if (elementToReplace) {
elementToReplace.innerHTML = this.getSectionInnerHTML(
parsedState.sections[section.section],
section.selector
);
}
});
if (this.isEnterPressed) {
this.querySelector(`#Quantity-${this.lastActiveInputId}`).select();
}
this.listenForActiveInput();
this.listenForKeydown();
}
}
);
}