Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Quick Add Bulk] Don't block quantity input during cart API call #3461

Merged
merged 16 commits into from
May 13, 2024
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"editor.formatOnSave": false,
"[javascript]": {
"editor.formatOnSave": true
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.formatOnSave": true
Expand Down
73 changes: 55 additions & 18 deletions assets/bulk-add.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,78 @@
class BulkAdd extends HTMLElement {
constructor() {
super();
this.queue = []
this.queue = [];
this.requestStarted = false;
this.ids = []
this.ids = [];
}

startQueue(id, quantity) {
this.queue.push({id, quantity})
this.queue.push({ id, quantity });
const interval = setInterval(() => {
if (this.queue.length > 0) {
if (!this.requestStarted) {
this.sendRequest(this.queue)
if (!this.requestStarted) {
this.sendRequest(this.queue);
}
} else {
clearInterval(interval)
clearInterval(interval);
}
}, 250)
}, 250);
}


sendRequest(queue) {
this.requestStarted = true;
const items = {}
const ids = []
const items = {};
queue.forEach((queueItem) => {
items[parseInt(queueItem.id)] = queueItem.quantity;
ids.push(queueItem.id)
});
this.queue = this.queue.filter(queueElement => !queue.includes(queueElement));
const quickOrderList = this.closest('quick-order-list');
quickOrderList.updateMultipleQty(items, ids)
this.queue = this.queue.filter((queueElement) => !queue.includes(queueElement));
const quickBulkElement = this.closest('quick-order-list') || this.closest('quick-add-bulk');
quickBulkElement.updateMultipleQty(items);
}
}

if (!customElements.get('bulk-add')) {
customElements.define('bulk-add', BulkAdd)
};
resetQuantityInput(id) {
const input = this.querySelector(`#Quantity-${id}`);
input.value = input.getAttribute('value');
this.isEnterPressed = false;
}

setValidity(event, index, message) {
event.target.setCustomValidity(message);
event.target.reportValidity();
this.resetQuantityInput(index);
event.target.select();
}

validateQuantity(event) {
const inputValue = parseInt(event.target.value);
const index = event.target.dataset.index;

if (inputValue < event.target.dataset.min) {
this.setValidity(event, index, window.quickOrderListStrings.min_error.replace('[min]', event.target.dataset.min));
} else if (inputValue > parseInt(event.target.max)) {
this.setValidity(event, index, window.quickOrderListStrings.max_error.replace('[max]', event.target.max));
} else if (inputValue % parseInt(event.target.step) != 0) {
this.setValidity(event, index, window.quickOrderListStrings.step_error.replace('[step]', event.target.step));
} else {
event.target.setCustomValidity('');
event.target.reportValidity();
this.startQueue(index, inputValue);
}
}

getSectionsUrl() {
if (window.pageNumber) {
return `${window.location.pathname}?page=${window.pageNumber}`;
} else {
return `${window.location.pathname}`;
}
}

getSectionInnerHTML(html, selector) {
return new DOMParser().parseFromString(html, 'text/html').querySelector(selector).innerHTML;
}
}

if (!customElements.get('bulk-add')) {
customElements.define('bulk-add', BulkAdd);
}
108 changes: 24 additions & 84 deletions assets/quick-add-bulk.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
if (!customElements.get('quick-add-bulk')) {
customElements.define(
'quick-add-bulk',
class QuickAddBulk extends HTMLElement {
class QuickAddBulk extends BulkAdd {
constructor() {
super();
this.quantity = this.querySelector('quantity-input');

const debouncedOnChange = debounce((event) => {
if (parseInt(event.target.dataset.cartQuantity) === 0) {
this.addToCart(event);
if (parseInt(event.target.value) === 0) {
this.startQueue(event.target.dataset.index, parseInt(event.target.value));
} else {
this.updateCart(event);
this.validateQuantity(event);
}
}, ON_CHANGE_DEBOUNCE_TIMER);

Expand Down Expand Up @@ -65,12 +65,6 @@ if (!customElements.get('quick-add-bulk')) {
});
}

resetQuantityInput(id) {
const input = document.getElementById(id);
input.value = input.getAttribute('value');
this.isEnterPressed = false;
}

cleanErrorMessageOnType(event) {
event.target.addEventListener(
'keypress',
Expand Down Expand Up @@ -102,81 +96,37 @@ if (!customElements.get('quick-add-bulk')) {
});
}

updateCart(event) {
this.lastActiveInputId = event.target.getAttribute('data-index');
this.quantity.classList.add('quantity__input-disabled');
updateMultipleQty(items) {
this.selectProgressBar().classList.remove('hidden');

const ids = Object.keys(items);
const body = JSON.stringify({
quantity: event.target.value,
id: event.target.getAttribute('data-index'),
updates: items,
sections: this.getSectionsToRender().map((section) => section.section),
sections_url: this.getSectionsUrl(),
});

fetch(`${routes.cart_change_url}`, { ...fetchConfig('javascript'), ...{ body } })
fetch(`${routes.cart_update_url}`, { ...fetchConfig(), ...{ body } })
.then((response) => {
return response.text();
})
.then((state) => {
const parsedState = JSON.parse(state);
this.quantity.classList.remove('quantity__input-disabled');
if (parsedState.description || parsedState.errors) {
event.target.setCustomValidity(parsedState.description);
event.target.reportValidity();
this.resetQuantityInput(event.target.id);
this.selectProgressBar().classList.add('hidden');
event.target.select();
this.cleanErrorMessageOnType(event);
return;
}

this.renderSections(parsedState);

this.renderSections(parsedState, ids);
publish(PUB_SUB_EVENTS.cartUpdate, { source: 'quick-add', cartData: parsedState });
})
.catch((error) => {
console.log(error, 'error');
});
}

addToCart(event) {
this.quantity.classList.add('quantity__input-disabled');
this.selectProgressBar().classList.remove('hidden');
this.lastActiveInputId = event.target.getAttribute('data-index');
const body = JSON.stringify({
items: [
{
quantity: parseInt(event.target.value),
id: parseInt(this.dataset.id),
},
],
sections: this.getSectionsToRender().map((section) => section.section),
});

fetch(`${routes.cart_add_url}`, { ...fetchConfig('javascript'), ...{ body } })
.then((response) => {
return response.text();
})
.then((state) => {
const parsedState = JSON.parse(state);
this.quantity.classList.remove('quantity__input-disabled');
if (parsedState.description || parsedState.errors) {
event.target.setCustomValidity(parsedState.description);
event.target.reportValidity();
this.resetQuantityInput(event.target.id);
this.selectProgressBar().classList.add('hidden');
event.target.select();
this.cleanErrorMessageOnType(event);
// Error handling
return;
}

this.renderSections(parsedState);

publish(PUB_SUB_EVENTS.cartUpdate, { source: 'quick-add', cartData: parsedState });
.catch(() => {
// 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);
})
.catch((error) => {
console.error(error);
.finally(() => {
this.selectProgressBar().classList.add('hidden');
this.requestStarted = false;
});
}

Expand All @@ -200,19 +150,9 @@ if (!customElements.get('quick-add-bulk')) {
];
}

getSectionsUrl() {
if (window.pageNumber) {
return `${window.location.pathname}?page=${window.pageNumber}`;
} else {
return `${window.location.pathname}`;
}
}

getSectionInnerHTML(html, selector) {
return new DOMParser().parseFromString(html, 'text/html').querySelector(selector).innerHTML;
}

renderSections(parsedState) {
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 (
Expand Down
1 change: 1 addition & 0 deletions assets/quick-add.css
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ quick-add-bulk .progress-bar-container {
overflow: hidden;
border-radius: var(--inputs-radius-outset);
border: var(--inputs-border-width) solid transparent;
z-index: -1;
}

quick-add-bulk quantity-input {
Expand Down
Loading
Loading