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

O JavaScript deve ser adicionado no arquivo store.js.tpl (ou onde você tem suas funções JS). Adicionamos o seguinte código:

$(document).on("change", ".js-variation-option", function(e) {
    var $this_compare_price =  $(this).closest(".js-product-container").find(".js-compare-price-display");
    var $this_price = $(this).closest(".js-product-container").find(".js-price-display");
    var $installment_container = $(this).closest(".js-product-container").find(".js-product-payments-container");
    var $installment_text = $(this).closest(".js-product-container").find(".js-max-installments-container");
    var $this_product_container = $(this).closest(".js-product-container");
    var $this_add_to_cart =  $(this).closest(".js-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();
    // Filter prices to only have numbers
    old_price_value_filtered = parseInt(compare_price_value.replace(/[^0-9]/gi, ''), 10)/100;
    current_price_value_filtered = parseInt(price_value.replace(/[^0-9]/gi, ''), 10)/100;
    // Calculate new discount percentage based on difference between filtered old and new prices
    price_difference = (old_price_value_filtered-current_price_value_filtered);
    updated_discount_percentage = Math.round(((price_difference*100)/old_price_value_filtered));
    $this_product_container.find(".js-offer-percentage").html(updated_discount_percentage);
    if ($this_compare_price.css("display") == "none") {
        $this_product_container.find(".js-offer-label").hide();
    }
    else {
        $this_product_container.find(".js-offer-label").css("display" , "table");
    }
    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.