Label com porcentagem de desconto

Neste tutorial, veremos como exibir uma etiqueta que calcula a porcentagem de desconto quando um produto tiver um preço original e um preço promocional, tanto no detalhe do produto quanto na lista:

Essa porcentagem é calculada quando o usuário altera uma variável nos detalhes do produto para casos em que eles têm um preço diferente.

HTML

A primeira coisa que vamos fazer é criar o tpl geral para todas as etiquetas relacionadas a um produto: desconto, frete grátis e sem estoque. Se você não precisa de tudo, você pode excluir o código que não precisa.

1. Adicione o arquivo labels.tpl à pasta snipplets

Vamos notar duas coisas importantes aqui:

  • O condicional {% if product_detail%} que usamos ao incluir o snipplet para perguntar se ele se aplica ao detalhe do produto ou não, dessa forma podemos usar as classes “js -...”
  • A variável price_discount_percentage que faz a conta para calcular qual é a porcentagem de desconto.
{% if product.compare_at_price > product.price %}
{% set price_discount_percentage = ((product.compare_at_price) - (product.price)) * 100 / (product.compare_at_price) %}
{% endif %}

{% if not product.has_stock or product.free_shipping or product.compare_at_price %}
  <div class="labels">
    {% if not product.has_stock %}
      <div class="{% if product_detail %}js-stock-label {% endif %}label label-default">{{ "Sin stock" | translate }}</div>
    {% else %}
      {% if product.compare_at_price %}
        <div class="js-offer-label label label-primary" {% if (not product.compare_at_price) or not product.display_price %}style="display:none;"{% endif %}>
          <span {% if product_detail %}class="js-offer-percentage"{% endif %}>{{ price_discount_percentage |round }}</span>% OFF
        </div>
      {% endif %}
      {% if product.free_shipping %}
        <div class="label label-secondary">{{ "Envío gratis" | translate }}</div>
      {% endif %}
    {% endif %}
  </div>
{% endif %}

2.  Com labels.tpl criado, temos que incluí-lo no detalhe do produto e na lista de produtos.

Para o item na lista nós o incluímos no item snipplet.tpl dentro da pasta snipplets/grid, pode ser que no seu layout este snipplet seja chamado single_product.tpl.

Chamamos o snipplet da seguinte maneira (idealmente dentro do componente de imagem do produto):

{% include 'snipplets/labels.tpl' %}

Incluiremos o mesmo snipplet nos detalhes do produto. No layout Base, fazemos isso no arquivo product-image.tpl na pasta snipplets/product, no seu caso você pode ter que incluí-lo no template product.tpl. O importante é que esteja dentro do contexto da imagem do produto, já que o componente da etiqueta tem uma posição absoluta no CSS.

{% include 'snipplets/labels.tpl' with {'product_detail': true} %}

3. Continuando com os detalhes do produto, aplicamos as seguintes alterações:

No modelo product.tpl no div principal que engloba todo o conteúdo desta página adicionamos os seguintes IDs e seletores “js -...”, sendo os seguintes:

<div id="single-product" class=”js-product-detail js-product-container" data-variants="{{product.variants_object | json_encode }}" itemscope itemtype="http://schema.org/Product">
…
</div>

Depois substituímos o HTML que mostra o preço e o preço promocional dentro do snipplet product-form.tpl ou, talvez, no seu caso ele esteja no product.tpl, com o seguinte código:

{# Product price #}

<div class="price-container text-center text-sm-left" itemprop="offers" itemscope itemtype="http://schema.org/Offer">
    <span class="d-inline-block">
       <h4 id="compare_price_display" class="js-compare-price-display price-compare" {% if not product.compare_at_price or not product.display_price %}style="display:none;"{% else %} style="display:block;"{% endif %}>{% if product.compare_at_price and product.display_price %}{{ product.compare_at_price | money }}{% endif %}</h4>
    </span>
    <spa class="d-inline-block">
        <h4 class="js-price-display" id="price_display" itemprop="price"{% if product.display_price %} content="{{ product.price / 100 }}"{% endif %} {% if not product.display_price %}style="display:none;"{% endif %}>{% if product.display_price %}{{ product.price | money }}{% endif %}</h4>
    </span>
    <meta itemprop="priceCurrency" content="{{ product.currency }}" />
    {% if product.stock_control %}
        <meta itemprop="inventoryLevel" content="{{ product.stock }}" />
        <meta itemprop="availability" href="http://schema.org/{{ product.stock ? 'InStock' : 'OutOfStock' }}" content="{{ product.stock ? 'In stock' : 'Out of stock' }}" />
    {% endif %}
</div>

Por último adicionamos a classe js-variation-option dentro do select das variantes do detalhe do produto. No layout Base, isso está no tpl product-variants.tpl dentro da pasta snipplets/product. Em seu layout, esse arquivo pode ser chamado de variants.tpl ou talvez você deva aplicar a alteração diretamente no template product.tpl

CSS

Requisito:

Ter adicionado helper classes em seu layout. Você pode seguir este pequeno tutorial para fazer isso (é só copiar e colar algumas classes, não leva mais que 1 minuto).

1.  Adicionamos o seguinte SASS de cores em style-colors.scss.tpl (ou no stylesheet do seu layout que possui as cores e fontes da loja). Lembre-se de que as variáveis de cores e fontes podem variar em relação ao seu design:

{# /* // Labels */ #}

.label {
  background: darken($main-background, 1%);
  &.label-primary{
    background: $main-foreground;
    color: $main-background;
  }
}

2. Adicione os estilos no arquivo static/style-critical.tpl

{# /* // Labels */ #}

.labels {
  position: absolute;
  top: 0;
  z-index: 9;
}

.label {
  margin-bottom: 10px;
  padding: 5px 10px; 
  font-size: 12px;
  text-align: left;
}

JS

⚠️ A partir do dia 30 de janeiro de 2023, a biblioteca jQuery será removida do código de nossas lojas, portanto, a função "$" não poderá ser utilizada.

O JavaScript deve ser adicionado no arquivo store.js.tpl (ou onde você tem suas funções JS). Adicionamos o seguinte código para para executar a mudança de variante (e labels do produto):

jQueryNuvem(document).on("change", ".js-variation-option", function(e) {

    var $parent = jQueryNuvem(this).closest(".js-product-variants");
    var $variants_group = jQueryNuvem(this).closest(".js-product-variants-group");
    var $quickshop_parent_wrapper = jQueryNuvem(this).closest(".js-quickshop-container");

    {# If quickshop is used from modal, use quickshop-id from the item that opened it #}
    
    if($quickshop_parent_wrapper.hasClass("js-quickshop-modal")){
        var quick_id = jQueryNuvem(".js-quickshop-opened .js-quickshop-container").data("quickshopId");
    }else{
        var quick_id = $quickshop_parent_wrapper.data("quickshopId");
    }

    if($parent.hasClass("js-product-quickshop-variants")){

        var $quickshop_parent = jQueryNuvem(this).closest(".js-item-product");

        {# Target visible slider item if necessary #}
        
        if($quickshop_parent.hasClass("js-item-slide")){
            var $quickshop_variant_selector = '.js-swiper-slide-visible .js-quickshop-container[data-quickshop-id="'+quick_id+'"]';
        }else{
            var $quickshop_variant_selector = '.js-quickshop-container[data-quickshop-id="'+quick_id+'"]';
        }
        
        LS.changeVariant(changeVariant, $quickshop_variant_selector);
    } else {
        LS.changeVariant(changeVariant, '#single-product');
    }

    {# Offer and discount labels update #}

    var $this_product_container = jQueryNuvem(this).closest(".js-product-container");

    if($this_product_container.hasClass("js-quickshop-container")){
        var this_quickshop_id = $this_product_container.attr("data-quickshop-id");
        var $this_product_container = jQueryNuvem('.js-product-container[data-quickshop-id="'+this_quickshop_id+'"]');
    }
    var $this_compare_price = $this_product_container.find(".js-compare-price-display");
    var $this_price = $this_product_container.find(".js-price-display");
    var $installment_container = $this_product_container.find(".js-product-payments-container");
    var $installment_text = $this_product_container.find(".js-max-installments-container");
    var $this_add_to_cart = $this_product_container.find(".js-prod-submit-form");

    // Get the current product discount percentage value
    var current_percentage_value = $this_product_container.find(".js-offer-percentage");

    // Get the current product price and promotional price
    var compare_price_value = $this_compare_price.html();
    var price_value = $this_price.html();

    // Calculate new discount percentage based on difference between filtered old and new prices
    const percentageDifference = window.moneyDifferenceCalculator.percentageDifferenceFromString(compare_price_value, price_value);
    if(percentageDifference){
        $this_product_container.find(".js-offer-percentage").text(percentageDifference);
        $this_product_container.find(".js-offer-label").css("display" , "table");
    }

    if ($this_compare_price.css("display") == "none" || !percentageDifference) {
        $this_product_container.find(".js-offer-label").hide();
    }

    if ($this_add_to_cart.hasClass("nostock")) {
        $this_product_container.find(".js-stock-label").show();
    }
    else {
        $this_product_container.find(".js-stock-label").hide();
    }
    if ($this_price.css('display') == 'none'){
        $installment_container.hide();
        $installment_text.hide();
    }else{
        $installment_text.show();
    }
});

Pronto, você já tem em sua loja a funcionalidade aplicada.