Skip to content

Commit

Permalink
Update variantselects to publish an option value selection change eve…
Browse files Browse the repository at this point in the history
…nt instead of a variant change start event, defer variant info until section rendering API request comes back (#3495)

Only update media when the selection has an associated variant
  • Loading branch information
lhoffbeck committed Jun 6, 2024
1 parent f85cd24 commit e4dddd0
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 36 deletions.
2 changes: 1 addition & 1 deletion assets/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const ON_CHANGE_DEBOUNCE_TIMER = 300;
const PUB_SUB_EVENTS = {
cartUpdate: 'cart-update',
quantityUpdate: 'quantity-update',
variantChangeStart: 'variant-change-start',
optionValueSelectionChange: 'option-value-selection-change',
variantChange: 'variant-change',
cartError: 'cart-error',
sectionRefreshed: 'section-refreshed',
Expand Down
4 changes: 2 additions & 2 deletions assets/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -1075,11 +1075,11 @@ class VariantSelects extends HTMLElement {
this.currentVariant = this.getVariantData(target.id);
this.updateSelectedSwatchValue(event);

publish(PUB_SUB_EVENTS.variantChangeStart, {
publish(PUB_SUB_EVENTS.optionValueSelectionChange, {
data: {
event,
target,
variant: this.currentVariant,
selectedOptionValues: this.selectedOptionValues,
},
});
});
Expand Down
71 changes: 38 additions & 33 deletions assets/product-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ if (!customElements.get('product-info')) {
cartUpdateUnsubscriber = undefined;
swapProductUtility = undefined;
abortController = undefined;
inflightRequestProductUrl = null;

constructor() {
super();
Expand All @@ -19,7 +20,7 @@ if (!customElements.get('product-info')) {
this.initializeProductSwapUtility();

this.onVariantChangeUnsubscriber = subscribe(
PUB_SUB_EVENTS.variantChangeStart,
PUB_SUB_EVENTS.optionValueSelectionChange,
this.handleOptionValueChange.bind(this)
);

Expand Down Expand Up @@ -68,37 +69,30 @@ if (!customElements.get('product-info')) {
});
}

handleOptionValueChange({ data: { event, target, variant } }) {
handleOptionValueChange({ data: { event, target, selectedOptionValues } }) {
if (!this.contains(event.target)) return;

const targetUrl = target.dataset.productUrl || this.dataset.url;
const baseUrl = target.dataset.productUrl || this.inflightRequestProductUrl || this.dataset.url;
this.inflightRequestProductUrl = baseUrl;

const productForm = this.productForm;
productForm?.toggleSubmitButton(true);
productForm?.handleErrorMessage();

let callback = () => {};
let productUrl = this.getProductInfoUrl(targetUrl, variant?.id);
if (this.dataset.url !== targetUrl) {
callback = this.handleSwapProduct(targetUrl, variant);
productUrl = this.getProductInfoUrl(targetUrl, variant?.id, true);
} else if (!variant) {
this.setUnavailable();
callback = (html) => {
this.pickupAvailability?.update(variant);
this.updateOptionValues(html);
};
} else {
this.updateVariantInputs(variant.id);
callback = this.handleUpdateProductInfo(targetUrl, variant);
}

this.renderProductInfo(productUrl, target.id, callback);
const shouldSwapProduct = this.dataset.url !== baseUrl;
this.renderProductInfo({
productUrl: this.getProductInfoUrl(baseUrl, selectedOptionValues, shouldSwapProduct),
targetId: target.id,
callback: shouldSwapProduct ? this.handleSwapProduct(baseUrl) : this.handleUpdateProductInfo(baseUrl),
});
}

handleSwapProduct(baseUrl, variant) {
handleSwapProduct(baseUrl) {
return (html) => {
this.productModal?.remove();

// Grab the selected variant from the new product info
const variant = this.getSelectedVariant(html.querySelector(`product-info[data-section=${this.sectionId}]`));
this.updateURL(baseUrl, variant?.id);

// If we are in an embedded context (quick add, featured product, etc), only swap product info.
Expand All @@ -107,18 +101,20 @@ if (!customElements.get('product-info')) {
this.swapProductUtility.viewTransition(this, html.querySelector('product-info'));
} else {
document.querySelector('head title').innerHTML = html.querySelector('head title').innerHTML;

this.swapProductUtility.viewTransition(document.querySelector('main'), html.querySelector('main'));
}
};
}

renderProductInfo(productUrl, targetId, callback) {
renderProductInfo({ productUrl, targetId, callback }) {
this.abortController?.abort();
this.abortController = new AbortController();

fetch(productUrl, { signal: this.abortController.signal })
.then((response) => response.text())
.then((responseText) => {
this.inflightRequestProductUrl = null;
const html = new DOMParser().parseFromString(responseText, 'text/html');
callback(html);
})
Expand All @@ -135,18 +131,18 @@ if (!customElements.get('product-info')) {
});
}

getProductInfoUrl(url, variantId, shouldFetchFullPage = false) {
getSelectedVariant(productInfoNode) {
const selectedVariant = productInfoNode.querySelector('variant-selects [data-selected-variant]')?.innerHTML;
return !!selectedVariant ? JSON.parse(selectedVariant) : null;
}

getProductInfoUrl(url, optionValues, shouldFetchFullPage = false) {
const params = [];

!shouldFetchFullPage && params.push(`section_id=${this.sectionId}`);

if (variantId) {
params.push(`variant=${variantId}`);
} else {
const optionValues = this.variantSelectors.selectedOptionValues;
if (optionValues.length) {
params.push(`option_values=${optionValues.join(',')}`);
}
if (optionValues.length) {
params.push(`option_values=${optionValues.join(',')}`);
}

return `${url}?${params.join('&')}`;
Expand All @@ -157,12 +153,21 @@ if (!customElements.get('product-info')) {
if (variantSelects) this.variantSelectors.innerHTML = variantSelects.innerHTML;
}

handleUpdateProductInfo(baseUrl, variant) {
handleUpdateProductInfo(baseUrl) {
return (html) => {
const variant = this.getSelectedVariant(html);

this.pickupAvailability?.update(variant);
this.updateMedia(html, variant?.featured_media?.id);
this.updateOptionValues(html);
this.updateURL(baseUrl, variant?.id);
this.updateVariantInputs(variant?.id);

if (!variant) {
this.setUnavailable();
return;
}

this.updateMedia(html, variant?.featured_media?.id);

const updateSourceFromDestination = (id, shouldHide = (source) => false) => {
const source = html.getElementById(`${id}-${this.sectionId}`);
Expand Down Expand Up @@ -203,7 +208,7 @@ if (!customElements.get('product-info')) {
`#product-form-${this.dataset.section}, #product-form-installment-${this.dataset.section}`
).forEach((productForm) => {
const input = productForm.querySelector('input[name="id"]');
input.value = variantId;
input.value = variantId ?? '';
input.dispatchEvent(new Event('change', { bubbles: true }));
});
}
Expand Down
2 changes: 2 additions & 0 deletions snippets/product-variant-picker.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,7 @@
</div>
{%- endif -%}
{%- endfor -%}

<script type="application/json" data-selected-variant>{{ product.selected_or_first_available_variant | json }}</script>
</variant-selects>
{%- endunless -%}

0 comments on commit e4dddd0

Please sign in to comment.