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

[Variant Selector] Toggle automatic variant selection #3467

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions assets/global.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,27 +156,36 @@ class QuantityInput extends HTMLElement {
constructor() {
super();
this.input = this.querySelector('input');
this.variantId = this.input.dataset.variantId;
this.changeEvent = new Event('change', { bubbles: true });
this.input.addEventListener('change', this.onInputChange.bind(this));
this.querySelectorAll('button').forEach((button) =>
button.addEventListener('click', this.onButtonClick.bind(this))
);

this.buttonMinus = this.querySelector('.quantity__button[name="minus"]') || undefined;
this.buttonPlus = this.querySelector('.quantity__button[name="plus"]') || undefined;
}

quantityUpdateUnsubscriber = undefined;
variantUpdateUnsubscriber = undefined;

connectedCallback() {
this.validateQtyRules();
this.validateVariantSelection(this.variantId);
this.quantityUpdateUnsubscriber = subscribe(PUB_SUB_EVENTS.quantityUpdate, this.validateQtyRules.bind(this));
this.variantUpdateUnsubscriber = subscribe(PUB_SUB_EVENTS.variantChange, (event) => {
this.variantId = event.data.variant.id.toString();
this.validateVariantSelection(this.variantId);
});
}

disconnectedCallback() {
if (this.quantityUpdateUnsubscriber) {
this.quantityUpdateUnsubscriber();
}
this.quantityUpdateUnsubscriber?.();
this.variantUpdateUnsubscriber?.();
}

onInputChange(event) {
onInputChange() {
this.validateQtyRules();
}

Expand All @@ -201,16 +210,28 @@ class QuantityInput extends HTMLElement {
}
}

validateVariantSelection(variantId) {
if (!variantId?.length) {
this.input.disabled = true;
this.buttonMinus?.classList.add('disabled');
this.buttonPlus?.classList.add('disabled');
} else {
this.validateQtyRules();
if (!this.input.max) {
this.buttonPlus?.classList.remove('disabled');
}
this.input.removeAttribute('disabled');
}
}

validateQtyRules() {
const value = parseInt(this.input.value);
if (this.input.min) {
const buttonMinus = this.querySelector(".quantity__button[name='minus']");
buttonMinus.classList.toggle('disabled', parseInt(value) <= parseInt(this.input.min));
this.buttonMinus?.classList.toggle('disabled', parseInt(value) <= parseInt(this.input.min));
}
if (this.input.max) {
const max = parseInt(this.input.max);
const buttonPlus = this.querySelector(".quantity__button[name='plus']");
buttonPlus.classList.toggle('disabled', value >= max);
this.buttonPlus?.classList.toggle('disabled', value >= max);
}
}
}
Expand Down Expand Up @@ -948,7 +969,7 @@ class SlideshowComponent extends SliderComponent {
const slideScrollPosition =
this.slider.scrollLeft +
this.sliderFirstItemNode.clientWidth *
(this.sliderControlLinksArray.indexOf(event.currentTarget) + 1 - this.currentPage);
(this.sliderControlLinksArray.indexOf(event.currentTarget) + 1 - this.currentPage);
this.slider.scrollTo({
left: slideScrollPosition,
});
Expand Down Expand Up @@ -1172,8 +1193,7 @@ class VariantSelects extends HTMLElement {
const sectionId = this.dataset.originalSection ? this.dataset.originalSection : this.dataset.section;

fetch(
`${this.dataset.url}?variant=${requestedVariantId}&section_id=${
this.dataset.originalSection ? this.dataset.originalSection : this.dataset.section
`${this.dataset.url}?variant=${requestedVariantId}&section_id=${this.dataset.originalSection ? this.dataset.originalSection : this.dataset.section
}`
)
.then((response) => response.text())
Expand Down
8 changes: 4 additions & 4 deletions assets/product-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ if (!customElements.get('product-info')) {
if (!this.input) return;
this.quantityForm = this.querySelector('.product-form__quantity');
if (!this.quantityForm) return;
this.setQuantityBoundries();
this.setQuantityBoundaries();
if (!this.dataset.originalSection) {
this.cartUpdateUnsubscriber = subscribe(PUB_SUB_EVENTS.cartUpdate, this.fetchQuantityRules.bind(this));
}
this.variantChangeUnsubscriber = subscribe(PUB_SUB_EVENTS.variantChange, (event) => {
const sectionId = this.dataset.originalSection ? this.dataset.originalSection : this.dataset.section;
if (event.data.sectionId !== sectionId) return;
this.updateQuantityRules(event.data.sectionId, event.data.html);
this.setQuantityBoundries();
this.setQuantityBoundaries();
});
}

Expand All @@ -37,7 +37,7 @@ if (!customElements.get('product-info')) {
}
}

setQuantityBoundries() {
setQuantityBoundaries() {
const data = {
cartQuantity: this.input.dataset.cartQuantity ? parseInt(this.input.dataset.cartQuantity) : 0,
min: this.input.dataset.min ? parseInt(this.input.dataset.min) : 1,
Expand Down Expand Up @@ -70,7 +70,7 @@ if (!customElements.get('product-info')) {
.then((responseText) => {
const html = new DOMParser().parseFromString(responseText, 'text/html');
this.updateQuantityRules(this.dataset.section, html);
this.setQuantityBoundries();
this.setQuantityBoundaries();
})
.catch((e) => {
console.error(e);
Expand Down
1 change: 1 addition & 0 deletions locales/en.default.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
"product": {
"add_to_cart": "Add to cart",
"choose_options": "Choose options",
"choose_option_named": "Choose {{ option_name }}",
"choose_product_options": "Choose options for {{ product_name }}",
"description": "Description",
"inventory_in_stock": "In stock",
Expand Down
4 changes: 4 additions & 0 deletions locales/en.default.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2415,6 +2415,10 @@
"hide_variants": {
"label": "Hide other variants’ media after selecting a variant"
},
"auto_set_variant": {
"label": "Auto-select first available variant",
"info": "If enabled, the first available variant will be selected by default."
},
"enable_video_looping": {
"label": "Enable video looping"
}
Expand Down
78 changes: 45 additions & 33 deletions sections/featured-product.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@

{%- liquid
assign product = section.settings.product

assign variant_images = product.images | where: 'attached_to_variant?', true | map: 'src'
assign selected_variant = product.selected_variant
if section.settings.auto_set_variant or product.variants.size == 1
assign selected_variant = product.selected_or_first_available_variant
endif
-%}

{% comment %} TODO: assign `product.selected_or_first_available_variant` to variable and replace usage to reduce verbosity {% endcomment %}
Expand All @@ -54,8 +60,6 @@
>
{%- endif -%}

{% assign variant_images = product.images | where: 'attached_to_variant?', true | map: 'src' %}

<section class="color-{{ section.settings.color_scheme }} {% if section.settings.secondary_background %}background-secondary{% else %}gradient{% endif %}">
<div class="page-width section-{{ section.id }}-padding{% if section.settings.secondary_background %} isolate{% endif %}">
<div class="featured-product product product--{{ section.settings.media_size }} grid grid--1-col gradient color-{{ section.settings.color_scheme }} product--{{ section.settings.media_position }}{% if section.settings.secondary_background == false %} isolate{% endif %} {% if product.media.size > 0 or section.settings.product == blank %}grid--2-col-tablet{% else %}product--no-media{% endif %}">
Expand Down Expand Up @@ -128,20 +132,20 @@
{%- if product != blank -%}
<div {{ block.shopify_attributes }}>
{%- form 'product', product -%}
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
<input type="hidden" name="id" value="{{ selected_variant.id }}">
{{ form | payment_terms }}
{%- endform -%}
</div>
{%- endif -%}
{%- when 'sku' -%}
<p
class="product__sku{% if block.settings.text_style == 'uppercase' %} caption-with-letter-spacing{% elsif block.settings.text_style == 'subtitle' %} subtitle{% endif %}{% if product.selected_or_first_available_variant.sku.size == 0 %} visibility-hidden{% endif %}"
class="product__sku{% if block.settings.text_style == 'uppercase' %} caption-with-letter-spacing{% elsif block.settings.text_style == 'subtitle' %} subtitle{% endif %}{% if selected_variant.sku.size == 0 %} visibility-hidden{% endif %}"
id="Sku-{{ section.id }}"
role="status"
{{ block.shopify_attributes }}
>
<span class="visually-hidden">{{ 'products.product.sku' | t }}:</span>
{{- product.selected_or_first_available_variant.sku -}}
{{- selected_variant.sku -}}
</p>
{%- when 'quantity_selector' -%}
<div
Expand All @@ -152,7 +156,7 @@
{% comment %} TODO: enable theme-check once `item_count_for_variant` is accepted as valid filter {% endcomment %}
{% # theme-check-disable %}
{%- assign cart_qty = cart
| item_count_for_variant: product.selected_or_first_available_variant.id
| item_count_for_variant: selected_variant.id
-%}
{% # theme-check-enable %}
<label class="quantity__label form__label" for="Quantity-{{ section.id }}">
Expand Down Expand Up @@ -180,14 +184,15 @@
name="quantity"
id="Quantity-{{ section.id }}"
data-cart-quantity="{{ cart_qty }}"
data-min="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
min="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
{% if product.selected_or_first_available_variant.quantity_rule.max != null %}
data-max="{{ product.selected_or_first_available_variant.quantity_rule.max }}"
max="{{ product.selected_or_first_available_variant.quantity_rule.max }}"
data-variant-id="{{ selected_variant.id }}"
data-min="{{ selected_variant.quantity_rule.min }}"
min="{{ selected_variant.quantity_rule.min }}"
{% if selected_variant.quantity_rule.max != null %}
data-max="{{ selected_variant.quantity_rule.max }}"
max="{{ selected_variant.quantity_rule.max }}"
{% endif %}
step="{{ product.selected_or_first_available_variant.quantity_rule.increment }}"
value="{{ product.selected_or_first_available_variant.quantity_rule.min }}"
step="{{ selected_variant.quantity_rule.increment }}"
value="{{ selected_variant.quantity_rule.min }}"
form="{{ product_form_id }}"
>
<button class="quantity__button" name="plus" type="button">
Expand All @@ -198,20 +203,20 @@
</button>
</quantity-input>
{%- liquid
assign volume_pricing_array = product.selected_or_first_available_variant.quantity_price_breaks | sort: 'quantity' | reverse
assign current_qty_for_volume_pricing = cart_qty | plus: product.selected_or_first_available_variant.quantity_rule.min
assign volume_pricing_array = selected_variant.quantity_price_breaks | sort: 'quantity' | reverse
assign current_qty_for_volume_pricing = cart_qty | plus: selected_variant.quantity_rule.min
if cart_qty > 0
assign current_qty_for_volume_pricing = cart_qty | plus: product.selected_or_first_available_variant.quantity_rule.increment
assign current_qty_for_volume_pricing = cart_qty | plus: selected_variant.quantity_rule.increment
endif
-%}
{%- if product.quantity_price_breaks_configured? -%}
<price-per-item
id="Price-Per-Item-{{ section.id }}"
data-section-id="{{ section.id }}"
data-variant-id="{{ product.selected_or_first_available_variant.id }}"
data-variant-id="{{ selected_variant.id }}"
>
{%- if product.selected_or_first_available_variant.quantity_price_breaks.size > 0 -%}
{%- assign variant_price_compare = product.selected_or_first_available_variant.compare_at_price -%}
{%- if selected_variant.quantity_price_breaks.size > 0 -%}
{%- assign variant_price_compare = selected_variant.compare_at_price -%}
<div class="price-per-item">
{%- if variant_price_compare -%}
<dl class="price-per-item--current">
Expand All @@ -226,7 +231,7 @@
</dl>
{%- endif -%}
{%- if current_qty_for_volume_pricing < volume_pricing_array.last.minimum_quantity -%}
{%- assign variant_price = product.selected_or_first_available_variant.price
{%- assign variant_price = selected_variant.price
| money_with_currency
-%}
<span class="price-per-item--current">
Expand All @@ -248,10 +253,10 @@
{%- endif -%}
</div>
{%- else -%}
{%- assign variant_price = product.selected_or_first_available_variant.price
{%- assign variant_price = selected_variant.price
| money_with_currency
-%}
{%- assign variant_price_compare = product.selected_or_first_available_variant.compare_at_price -%}
{%- assign variant_price_compare = selected_variant.compare_at_price -%}
<div class="price-per-item">
{%- if variant_price_compare -%}
<dl class="price-per-item--current">
Expand Down Expand Up @@ -283,46 +288,46 @@
{%- endif -%}
</div>
<div class="quantity__rules caption" id="Quantity-Rules-{{ section.id }}">
{%- if product.selected_or_first_available_variant.quantity_rule.increment > 1 -%}
{%- if selected_variant.quantity_rule.increment > 1 -%}
<span class="divider">
{{-
'products.product.quantity.multiples_of'
| t: quantity: product.selected_or_first_available_variant.quantity_rule.increment
| t: quantity: selected_variant.quantity_rule.increment
-}}
</span>
{%- endif -%}
{%- if product.selected_or_first_available_variant.quantity_rule.min > 1 -%}
{%- if selected_variant.quantity_rule.min > 1 -%}
<span class="divider">
{{-
'products.product.quantity.minimum_of'
| t: quantity: product.selected_or_first_available_variant.quantity_rule.min
| t: quantity: selected_variant.quantity_rule.min
-}}
</span>
{%- endif -%}
{%- if product.selected_or_first_available_variant.quantity_rule.max != null -%}
{%- if selected_variant.quantity_rule.max != null -%}
<span class="divider">
{{-
'products.product.quantity.maximum_of'
| t: quantity: product.selected_or_first_available_variant.quantity_rule.max
| t: quantity: selected_variant.quantity_rule.max
-}}
</span>
{%- endif -%}
</div>
{%- if product.quantity_price_breaks_configured? -%}
<volume-pricing class="parent-display" id="Volume-{{ section.id }}">
{%- if product.selected_or_first_available_variant.quantity_price_breaks.size > 0 -%}
{%- if selected_variant.quantity_price_breaks.size > 0 -%}
<span class="caption-large">{{ 'products.product.volume_pricing.title' | t }}</span>
<ul class="list-unstyled">
<li>
<span>{{ product.selected_or_first_available_variant.quantity_rule.min }}+</span>
{%- assign price = product.selected_or_first_available_variant.price
<span>{{ selected_variant.quantity_rule.min }}+</span>
{%- assign price = selected_variant.price
| money_with_currency
-%}
<span data-text="{{ 'products.product.volume_pricing.price_at_each' | t: price: variant_price }}">
{{ 'sections.quick_order_list.each' | t: money: price -}}
</span>
</li>
{%- for price_break in product.selected_or_first_available_variant.quantity_price_breaks -%}
{%- for price_break in selected_variant.quantity_price_breaks -%}
{%- assign price_break_price = price_break.price | money_with_currency -%}
<li class="{%- if forloop.index >= 3 -%}show-more-item hidden{%- endif -%}">
<span>
Expand All @@ -336,7 +341,7 @@
</li>
{%- endfor -%}
</ul>
{%- if product.selected_or_first_available_variant.quantity_price_breaks.size >= 3 -%}
{%- if selected_variant.quantity_price_breaks.size >= 3 -%}
<show-more-button>
<button
class="button-show-more link underlined-link"
Expand Down Expand Up @@ -1450,6 +1455,13 @@
"default": false,
"label": "t:sections.main-product.settings.hide_variants.label"
},
{
"id": "auto_set_variant",
"label": "t:sections.main-product.settings.auto_set_variant.label",
"type": "checkbox",
"default": true,
"info": "t:sections.main-product.settings.auto_set_variant.info"
},
{
"type": "checkbox",
"id": "enable_video_looping",
Expand Down
1 change: 1 addition & 0 deletions sections/main-cart-items.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@
value="{{ item.quantity }}"
{% # theme-check-disable %}
data-cart-quantity="{{ cart | item_count_for_variant: item.variant.id }}"
data-variant-id="{{ item.variant.id }}"
min="0"
data-min="{{ item.variant.quantity_rule.min }}"
{% if item.variant.quantity_rule.max != null %}
Expand Down
Loading
Loading