Skip to content

Commit

Permalink
Quick Add Bulk Modal - Increase performance with Intersection Observe…
Browse files Browse the repository at this point in the history
…r and clean up network requests (Shopify#3480)
  • Loading branch information
sofiamatulis authored and nathan-scheele committed Jul 1, 2024
1 parent 044ca3a commit 4b15e89
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 22 deletions.
32 changes: 32 additions & 0 deletions assets/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,38 @@ class ModalDialog extends HTMLElement {
}
customElements.define('modal-dialog', ModalDialog);

class BulkModal extends HTMLElement {
constructor() {
super();
}

connectedCallback() {
const handleIntersection = (entries, observer) => {
if (!entries[0].isIntersecting) return;
observer.unobserve(this);
if (this.innerHTML.trim() === '') {
const productUrl = this.dataset.url.split('?')[0];
fetch(`${productUrl}?section_id=bulk-quick-order-list`)
.then((response) => response.text())
.then((responseText) => {
const html = new DOMParser().parseFromString(responseText, 'text/html');
const sourceQty = html.querySelector('.quick-order-list-container').parentNode;
this.innerHTML = sourceQty.innerHTML;
})
.catch((e) => {
console.error(e);
});
}
};

new IntersectionObserver(handleIntersection.bind(this)).observe(
document.querySelector(`#QuickBulk-${this.dataset.productId}-${this.dataset.sectionId}`)
);
}
}

customElements.define('bulk-modal', BulkModal);

class ModalOpener extends HTMLElement {
constructor() {
super();
Expand Down
6 changes: 5 additions & 1 deletion assets/quick-add-bulk.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ if (!customElements.get('quick-add-bulk')) {

connectedCallback() {
this.cartUpdateUnsubscriber = subscribe(PUB_SUB_EVENTS.cartUpdate, (event) => {
if (event.source === 'quick-add') {
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
Expand Down
10 changes: 10 additions & 0 deletions assets/quick-add.css
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,17 @@
display: inline-block;
}

.section-bulk-quick-order-list-padding {
padding-top: 2.7rem;
padding-bottom: 2.7rem;
}

@media screen and (min-width: 750px) {
.section-bulk-quick-order-list-padding {
padding-top: 3.6rem;
padding-bottom: 3.6rem;
}

.quick-add-modal__content-info--bulk .card__information-volume-pricing-note {
padding-left: 1.6rem;
}
Expand Down
27 changes: 18 additions & 9 deletions assets/quick-order-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ if (!customElements.get('quick-order-list')) {
constructor() {
super();
this.cart = document.querySelector('cart-drawer');
this.quickOrderListId = `quick-order-list-${this.dataset.productId}`;
this.quickOrderListId = `${this.dataset.section}-${this.dataset.productId}`;
this.defineInputsAndQuickOrderTable();

this.variantItemStatusElement = document.getElementById('shopping-cart-variant-item-status');
Expand Down Expand Up @@ -114,7 +114,15 @@ if (!customElements.get('quick-order-list')) {

connectedCallback() {
this.cartUpdateUnsubscriber = subscribe(PUB_SUB_EVENTS.cartUpdate, (event) => {
if (event.source === this.quickOrderListId) {
const variantIds = [];
this.querySelectorAll('.variant-item').forEach((item) => {
variantIds.push(item.dataset.variantId);
});

if (
event.source === this.quickOrderListId ||
(event.cartData.items && variantIds.some((element) => !event.cartData.items.includes(element)))
) {
return;
}
// If its another section that made the update
Expand All @@ -123,15 +131,16 @@ if (!customElements.get('quick-order-list')) {
this.addMultipleDebounce();
});
});

this.sectionRefreshUnsubscriber = subscribe(PUB_SUB_EVENTS.sectionRefreshed, (event) => {
const isParentSectionUpdated =
this.sectionId && (event.data?.sectionId ?? '') === `${this.sectionId.split('__')[0]}__main`;

if (isParentSectionUpdated) {
this.refresh();
}
});
this.sectionId = this.dataset.id;
this.sectionId = this.dataset.section;
}

disconnectedCallback() {
Expand Down Expand Up @@ -202,7 +211,7 @@ if (!customElements.get('quick-order-list')) {
return [
{
id: this.quickOrderListId,
section: document.getElementById(this.quickOrderListId).dataset.id,
section: document.getElementById(this.quickOrderListId).dataset.section,
selector: `#${this.quickOrderListId} .js-contents`,
},
{
Expand All @@ -216,8 +225,8 @@ if (!customElements.get('quick-order-list')) {
selector: '.shopify-section',
},
{
id: `quick-order-list-total-${this.dataset.productId}`,
section: document.getElementById(this.quickOrderListId).dataset.id,
id: `quick-order-list-total-${this.dataset.productId}-${this.dataset.section}`,
section: document.getElementById(this.quickOrderListId).dataset.section,
selector: `#${this.quickOrderListId} .quick-order-list__total`,
},
{
Expand Down Expand Up @@ -373,13 +382,12 @@ if (!customElements.get('quick-order-list')) {

updateMultipleQty(items) {
this.querySelector('.variant-remove-total .loading__spinner')?.classList.remove('hidden');

const ids = Object.keys(items);

const body = JSON.stringify({
updates: items,
sections: this.getSectionsToRender().map((section) => section.section),
sections_url: this.getSectionsUrl(),
sections_url: this.dataset.url,
});

this.updateMessage();
Expand All @@ -392,6 +400,7 @@ if (!customElements.get('quick-order-list')) {
.then((state) => {
const parsedState = JSON.parse(state);
this.renderSections(parsedState, ids);
publish(PUB_SUB_EVENTS.cartUpdate, { source: this.quickOrderListId, cartData: parsedState });
})
.catch(() => {
this.setErrorMessage(window.cartStrings.error);
Expand Down
15 changes: 15 additions & 0 deletions sections/bulk-quick-order-list.liquid
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{ 'quick-order-list.css' | asset_url | stylesheet_tag }}

<script src="{{ 'quick-order-list.js' | asset_url }}" defer="defer"></script>

{% render 'quick-order-list', product: product, show_image: true, show_sku: true, is_modal: true %}

{% schema %}
{
"name": "t:sections.quick-order-list.name",
"limit": 1,
"enabled_on": {
"templates": ["product"]
}
}
{% endschema %}
20 changes: 12 additions & 8 deletions snippets/card-product.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,10 @@
assign qty_rules = true
endif
-%}
<modal-opener data-modal="#QuickAddBulk-{{ card_product.id }}">
<modal-opener
id="QuickBulk-{{ card_product.id }}-{{ section_id }}"
data-modal="#QuickAddBulk-{{ card_product.id }}-{{ section.id }}"
>
<button
id="{{ product_form_id }}-submit"
type="submit"
Expand All @@ -417,7 +420,7 @@
</button>
</modal-opener>
<modal-dialog
id="QuickAddBulk-{{ card_product.id }}"
id="QuickAddBulk-{{ card_product.id }}-{{ section_id }}"
class="quick-add-modal color-{{ section.settings.color_scheme }}"
>
<div
Expand Down Expand Up @@ -503,12 +506,13 @@
</div>
{%- endif -%}
</div>
{%- render 'quick-order-list',
product: card_product,
show_image: true,
show_sku: true,
is_modal: true
-%}
<bulk-modal
id="QuickBulkModal-{{ card_product.id }}-{{ section_id }}"
data-url="{{ card_product.url }}"
data-section-id="{{ section_id }}"
data-product-id="{{ card_product.id }}"
>
</bulk-modal>
</div>
</div>
</div>
Expand Down
21 changes: 17 additions & 4 deletions snippets/quick-order-list.liquid
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
{% comment %}
Renders a list of product's variants
Accepts:
- product: {Object} Product Liquid object
- show_image: {Boolean} Shows image of the variant in the row
- is_modal: {Boolean} Defines if this snippet lives in a modal (optional)
Usage:
{% render 'quick-order-list', product: product %}
{% endcomment %}

{% comment %} TODO: enable theme-check once `line_items_for` is accepted as valid filter {% endcomment %}
{% # theme-check-disable %}
{%- assign items_in_cart = cart | line_items_for: product | sum: 'quantity' -%}
{% # theme-check-enable %}
<div class="color-{{ section.settings.color_scheme }}{% unless is_modal %} gradient{% endunless %}">
<div class="quick-order-list-container color-{{ section.settings.color_scheme }}{% unless is_modal %} gradient{% endunless %}">
<quick-order-list
class="page-width section-{{ section.id }}-padding"
id="quick-order-list-{{ product.id }}"
data-id="{{ section.id }}"
id="{{ section.id }}-{{ product.id }}"
data-section="{{ section.id }}"
data-product-id="{{ product.id }}"
data-url="{{ product.url }}"
>
<form
action="{{ routes.cart_update_url }}"
Expand Down Expand Up @@ -112,7 +125,7 @@
{%- else -%}
<div
class="quick-order-list__total{% unless is_modal %} gradient{% endunless %}"
id="quick-order-list-total-{{ product.id }}"
id="quick-order-list-total-{{ product.id }}-{{ section.id }}"
>
<div class="quick-order-list-total__info">
<div class="quick-order-list-total__column small-hide medium-hide">
Expand Down

0 comments on commit 4b15e89

Please sign in to comment.