Neste tutorial, vamos adicionar visibilidade aos meios de pagamento e parcelas em seu design:
O código neste tutorial inclui:
- Parcelas na lista de produtos, detalhes do produto e carrinho (aplica-se apenas em lojas no Brasil)
- Modal que mostra o detalhe dos meios de pagamento oferecidos pela loja
HTML
1. A primeira coisa que vamos fazer é chamar o componente parcelas para mostrar na lista de produtos.
No arquivo item.tpl vamos adicionar a seguinte chamada
{{ component('installments', {'location' : 'product_item', container_classes: { installment: "item-installments"}}) }} Este componente inclui a mensagem de parcelas e permite os seguintes parâmetros:
location:
- cart: Vamos usá-lo incluindo-o no carrinho
- product_item: Vamos usá-lo incluindo-o no item da lista de produtos
- product_detail: Vamos utilizá-lo incluindo-o nos detalhes do produto, por exemplo, abaixo do preço
container_classes.installment: Usado para passar classes para o contêiner geral da mensagem de parcelas
Deve quedar algo semelhante a isto:

2. Do mesmo jeito que fizemos para o item da lista de produtos, agora faremos para a mensagem de parcelas no carrinho de compras. Vamos procurar o tpl cart-totals.tpl ou onde temos o total do carrinho, e logo abaixo vamos adicionar o seguinte código:
{{ component('installments', {'location': 'cart', container_classes: { installment: "mt-1 font-weight-bold text-right"}}) }}Vamos lembrar os parâmetros que usamos para o item produto, mas neste caso usamos "location" : "cart" e as classes que precisamos para o CSS, deixando algo como o exemplo a seguir:

3. Deixamos o detalhe do produto para o final, pois teremos 2 partes: a mensagem de cota abaixo do preço e o popup que mostra o detalhe do meio de pagamento.
A primeira coisa que vamos fazer é entender onde temos o formulário do produto, por exemplo pode ser o tpl product-form.tpl e abaixo do preço incluir o componente de parcelas como fizemos antes (não esqueçamos de colocar o "localização "parâmetro corretamente)
{{ component('installments', {'location' : 'product_detail', container_classes: { installment: "product-detail-installments text-center text-md-left mb-2" }}) }}Deixando algo como o seguinte:

Por fim, para o popup de meios de pagamento, adicionamos o arquivo product-payment-details.tpl dentro da pasta product, com o seguinte código.
{# Product payments details #}
{% if product.installments_info_from_any_variant %}
{% embed "snipplets/modal.tpl" with{
modal_id: 'installments-modal',
modal_position: 'bottom',
modal_transition: 'slide',
modal_header: true,
modal_footer: true,
modal_width: 'centered',
modal_mobile_full_screen: 'true'} %}
{% block modal_head %}
{{ 'Medios de pago' | translate }}
{% endblock %}
{% block modal_body %}
{# Modal header and gateways tab links #}
{{ component('payments/payments-details',
{
text_classes: {
text_accent: "label label-accent ml-1",
subtitles: "mb-3",
text_big: "font-big",
text_small: "font-small",
align_right: "text-right"
},
spacing_classes: {
top_1x: "mt-1",
top_2x: "mt-2",
top_3x: "mt-3",
right_1x: "mr-1",
right_2x: "mr-2",
right_3x: "mr-3",
bottom_1x: "mb-1",
bottom_2x: "mb-2",
bottom_3x: "mb-3",
left_3x: "ml-3",
},
container_classes : {
payment_method: "card p-3"
}
})
}}
{% endblock %}
{% block modal_foot %}
<div class="text-right">
<span class="js-modal-close js-fullscreen-modal-close btn-link pull-right">{{ 'Volver al producto' | translate }}</span>
</div>
{% endblock %}
{% endembed %}
{% endif %}Os parâmetros que o componente de detalhes de pagamentos aceita são principalmente classes para CSS
Classes para textos:
- text_classes.text_accent: Usado para os textos de destaque, como descontos
- text_classes.subtitles: Usado para os subtítulos dentro do pop-up
- text_classes.text_big: Usado para textos grandes que ainda é menor que um título
- text_classes.text_small: Usado para textos pequenos
Classes de espaçamento:
- spacing_classes.top_1x: Usado para margens superiores em 1x
- spacing_classes.right_1x: Usado para margens à direita em 1x
- spacing_classes.right_2x: Usado para margens à direita em 2x
- spacing_classes.right_3x: Usado para margens à direita em 3x
- spacing_classes.bottom_1x: Usado para margens inferiores em 1x
- spacing_classes.bottom_2x: Usado para margens inferiores em 2x
- spacing_classes.bottom_3x: Usado para margens inferiores em 3x
- spacing_classes.left_3x: Usado para margens à esquerda em 3x
E o incluímos no final do formulário do produto no arquivo product-form.tpl
{# Product payments details #}
{% include 'snipplets/product/product-payment-details.tpl' %}Este pop-up inclui o detalhe de todos os meios de pagamento bem como os descontos que cada um pode oferecer.

Antes de prosseguir não devemos esquecer de adicionar o link que abre o pop-up. Podemos adicioná-lo onde precisarmos:
<a id="btn-installments" class="btn-link" {% if not (product.get_max_installments and product.get_max_installments(false)) %}style="display: none;"{% endif %}>
{{ "Ver medios de pago" | translate }}
</a>4. Teremos que adicionar alguns IDs e classes nos detalhes do produto para que as cotas sejam atualizadas ao alterar a variante. No layout Base, modificamos o template product.tpl e o snipplet product-form.tpl; mas no seu caso, você só precisa modificar product.tpl.
product.tpl
No div pai que abrange todo o conteúdo do detalhe do produto, inclua os seguintes IDs e seletores "js -..."
<div id="single-product" class=”js-product-detail js-product-container" data-variants="{{product.variants_object | json_encode }}" itemscope itemtype="http://schema.org/Product">product-form.tpl
Neste arquivo iremos substituir o código que você tem em relação ao preço do produto com o seguinte (lembre-se que esta alteração se aplica neste snipplet mas no seu caso você pode aplicá-lo onde quer que você tenha o preço do produto)
{# 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 product_can_show_installments or (product.promotional_offer and not product.promotional_offer.script.is_percentage_off) %}mb-2{% endif %}" {% 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 {% if product_can_show_installments or (product.promotional_offer and not product.promotional_offer.script.is_percentage_off) %}mb-2{% endif %}" 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>Também precisamos adicionar a classe js-addtocart ao botão “Comprar”, assim:
{% set state = store.is_catalog ? 'catalog' : (product.available ? product.display_price ? 'cart' : 'contact' : 'nostock') %}
{% set texts = {'cart': "Agregar al carrito", 'contact': "Consultar precio", 'nostock': "Sin stock", 'catalog': "Consultar"} %}
<input type="submit" class="js-addtocart js-prod-submit-form btn btn-primary btn-block mb-4 {{ state }}" value="{{ texts[state] | translate }}" {% if state == 'nostock' %}disabled{% endif %} />5. Agora precisamos criar o snipplet para o componente modal ou pop-up dentro da pasta snipplets. Este tpl é chamado modal.tpl e o código é:
{# /*============================================================================
#Modal
==============================================================================*/
#Properties
// ID
// Position - Top, Right, Bottom, Left
// Transition - Slide and Fade
// Width - Full and Box
// modal_form_action - For modals that has a form
#Head
// Block - modal_head
#Body
// Block - modal_body
#Footer
// Block - modal_footer
#}
{% set modal_overlay = modal_overlay | default(true) %}
<div id="{{ modal_id }}" class="js-modal modal modal-{{ modal_class }} modal-{{modal_position}} transition-{{modal_transition}} modal-{{modal_width}} transition-soft" style="display: none;">
{% if modal_form_action %}
<form action="{{ modal_form_action }}" method="post" class="{{ modal_form_class }}">
{% endif %}
<div class="js-modal-close modal-header">
<span class="modal-close">
{% include "snipplets/svg/times.tpl" with {svg_custom_class: "icon-inline svg-icon-text"} %}
</span>
{% block modal_head %}{% endblock %}
</div>
<div class="modal-body">
{% block modal_body %}{% endblock %}
</div>
{% if modal_footer %}
<div class="modal-footer d-md-block">
{% block modal_foot %}{% endblock %}
</div>
{% endif %}
{% if modal_form_action %}
</form>
{% endif %}
</div>6. Adicionamos a classe js-variation-option no select para variantes de detalhes do produto. No layout Base, isso está no tpl product-variants.tpl dentro da pasta snipplets/product. Em seu design, esse arquivo pode ser chamado de variants.tpl ou você deve aplicar a alteração diretamente no modelo product.tpl
7. Finalmente, para a parte HTML, precisamos adicionar uma pasta SVG dentro da pasta snipplets. Aqui vamos adicionar os SVGs para o ícone do cartão de crédito no detalhe do produto com o nome credit-card-blank.tpl, e o ícone para fechar o popup com o nome times.tpl
credit-card-blank.tpl
<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M527.9 32H48.1C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48.1 48h479.8c26.6 0 48.1-21.5 48.1-48V80c0-26.5-21.5-48-48.1-48zm-6 400H54.1c-3.3 0-6-2.7-6-6V86c0-3.3 2.7-6 6-6h467.8c3.3 0 6 2.7 6 6v340c0 3.3-2.7 6-6 6zM192 364v8c0 6.6-5.4 12-12 12h-72c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h72c6.6 0 12 5.4 12 12zm192 0v8c0 6.6-5.4 12-12 12H236c-6.6 0-12-5.4-12-12v-8c0-6.6 5.4-12 12-12h136c6.6 0 12 5.4 12 12z"/></svg>times.tpl
<svg class="{{ svg_custom_class }}" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>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 na 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 layout:
@mixin prefix($property, $value, $prefixes: ()) {
@each $prefix in $prefixes {
#{'-' + $prefix + '-' + $property}: $value;
}
#{$property}: $value;
}
/* // Wrappers */
.box{
float: left;
width: 100%;
margin-bottom: 20px;
padding:8px;
border:1px solid rgba($main-foreground, .2);
}
/* // Dividers */
.divider{
margin-top: 20px;
margin-bottom: 20px;
clear: both;
border-bottom: 1px solid rgba($main-foreground, .1);
}
/* // Modals */
.modal{
color: $main-foreground;
background-color:$main-background;
}
/* // Links */
.btn-link{
color: $primary-color;
fill: $primary-color;
text-transform: uppercase;
border-bottom: 1px solid;
font-weight: bold;
cursor: pointer;
&:hover,
&:focus{
color: rgba($primary-color, .5);
fill: rgba($primary-color, .5);
}
}
/* // Tables */
.table{
background-color: $main-background;
color: $main-foreground;
tbody{
tr:nth-child(odd){
background-color: rgba($main-foreground, .05);
}
}
th{
padding: 8px;
text-align: left;
}
}
/* // Tabs */
.tab-group{
border-bottom: 1px solid rgba($main-foreground, .1);
.tab{
&-link{
color: $main-foreground;
}
&.active{
.tab-link{
border-bottom: 2px solid rgba($primary-color, .5);
color: $primary-color;
}
}
}
}2. Adicione os estilos no arquivo static/style-critical.tpl
Se em seu layout você usar um stylesheet para o CSS crítico, precisaremos do seguinte código dentro dele, do contrário, você pode unificar o CSS dos passos 2 e 3 em um único arquivo.
/* // Images */
.card-img{
margin: 0 5px 5px 0;
border: 1px solid #00000012;
}
.card-img-small{
height: 25px;
}
.card-img-medium{
height: 35px;
}
.card-img-big{
height: 50px;
}3. Adicione os estilos no arquivo static/style-async.tpl
Se em seu layout você usar um stylesheet CSS assíncrono, precisaremos do seguinte código dentro dela, do contrário, você pode unificar o CSS dos passos 2 e 3 em um único arquivo.
@mixin prefix($property, $value, $prefixes: ()) {
@each $prefix in $prefixes {
#{'-' + $prefix + '-' + $property}: $value;
}
#{$property}: $value;
}
/* // Modals */
.modal {
position: fixed;
top: 0;
display: block;
width: 80%;
height: 100%;
padding: 10px;
-webkit-overflow-scrolling: touch;
overflow-y: auto;
transition: all .2s cubic-bezier(.16,.68,.43,.99);
z-index: 20000;
&-header{
width: calc(100% + 20px);
margin: -10px 0 10px -10px;
padding: 10px 15px;
font-size: 20px;
}
&-footer{
padding: 10px;
clear: both;
}
&-full {
width: 100%;
}
&-docked-sm{
width: 100%;
}
&-docked-small{
width: 80%;
}
&-top{
top: -100%;
left: 0;
}
&-bottom{
top: 100%;
left: 0;
}
&-left{
left: -100%;
}
&-right{
right: -100%;
}
&-centered{
height: 100%;
width: 100%;
}
&-top.modal-show,
&-bottom.modal-show {
top: 0;
}
&-left.modal-show {
left: 0;
}
&-right.modal-show {
right: 0;
}
&-close {
display: inline-block;
padding: 1px 5px 5px 0;
margin-right: 5px;
vertical-align: middle;
cursor: pointer;
}
.tab-group{
margin: 0 -10px 20px -10px;
}
}
.modal-overlay{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #00000047;
z-index: 10000;
}
/* // Tables */
.table{
width: 100%;
border-collapse: collapse;
border-spacing: 0;
thead{
th{
padding: 8px;
&:first-of-type{
padding-left: 0;
}
}
}
td{
padding: 8px;
text-align: left;
}
}
/* // Tabs */
.tab-group{
width: 100vw;
padding: 0;
overflow-x: scroll;
white-space: nowrap;
.tab{
display: inline-flex;
float: none;
&-link{
float: left;
padding: 10px;
text-align: center;
}
}
}
.tab-panel:not(.active){
display: none;
}
.tab-panel.active{
display: block;
}
/* // Min width 768px */
@media (min-width: 768px) {
/* //// Components */
/* Modals */
.modal{
&-centered{
height: 80%;
width: 80%;
left: 10%;
margin: 5% auto;
}
&-docked-sm{
width: 500px;
}
&-docked-small{
width: 350px;
}
}
/* Tabs */
.tab-group{
width: calc(100% + 20px);
overflow-x: auto;
white-space: normal;
.tab{
float: 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.
1. JavaScript precisam ser adicionados no arquivo store.js.tpl (ou onde você tem suas funções JS). O código que precisamos é o seguinte:
{# /* // Installments */ #}
{# Installments without interest #}
function get_max_installments_without_interests(number_of_installment, installment_data, max_installments_without_interests) {
if (parseInt(number_of_installment) > parseInt(max_installments_without_interests[0])) {
if (installment_data.without_interests) {
return [number_of_installment, installment_data.installment_value.toFixed(2)];
}
}
return max_installments_without_interests;
}
{# Installments with interest #}
function get_max_installments_with_interests(number_of_installment, installment_data, max_installments_with_interests) {
if (parseInt(number_of_installment) > parseInt(max_installments_with_interests[0])) {
if (installment_data.without_interests == false) {
return [number_of_installment, installment_data.installment_value.toFixed(2)];
}
}
return max_installments_with_interests;
}
{# Refresh installments inside detail popup #}
function refreshInstallmentv2(price){
jQueryNuvem(".js-modal-installment-price" ).each(function( el ) {
const installment = Number(jQueryNuvem(el).data('installment'));
jQueryNuvem(el).text(LS.currency.display_short + (price/installment).toLocaleString('de-DE', {maximumFractionDigits: 2, minimumFractionDigits: 2}));
});
}
{# Refresh price on payments popup with payment discount applied #}
function refreshPaymentDiscount(price){
jQueryNuvem(".js-price-with-discount" ).each(function( el ) {
const payment_discount = jQueryNuvem(el).data('paymentDiscount');
jQueryNuvem(el).text(LS.formatToCurrency(price - ((price * payment_discount) / 100)))
});
}Localize a função changeVariant da função e substitua-a pelo seguinte: O código que precisamos para o carrinho é o seguinte:
{# /* // Change variant */ #}
{# Updates price, installments, labels and CTA on variant change #}
function changeVariant(variant){
jQueryNuvem(".js-product-detail .js-shipping-calculator-response").hide();
jQueryNuvem("#shipping-variant-id").val(variant.id);
var parent = jQueryNuvem("body");
if (variant.element){
parent = jQueryNuvem(variant.element);
}
var sku = parent.find('#sku');
if(sku.length) {
sku.text(variant.sku).show();
}
var installment_helper = function($element, amount, price){
$element.find('.js-installment-amount').text(amount);
$element.find('.js-installment-price').attr("data-value", price);
$element.find('.js-installment-price').text(LS.currency.display_short + parseFloat(price).toLocaleString('de-DE', { minimumFractionDigits: 2 }));
if(variant.price_short && Math.abs(variant.price_number - price * amount) < 1) {
$element.find('.js-installment-total-price').text((variant.price_short).toLocaleString('de-DE', { minimumFractionDigits: 2 }));
} else {
$element.find('.js-installment-total-price').text(LS.currency.display_short + (price * amount).toLocaleString('de-DE', { minimumFractionDigits: 2 }));
}
};
if (variant.installments_data) {
var variant_installments = JSON.parse(variant.installments_data);
var max_installments_without_interests = [0,0];
var max_installments_with_interests = [0,0];
for (let payment_method in variant_installments) {
let installments = variant_installments[payment_method];
for (let number_of_installment in installments) {
let installment_data = installments[number_of_installment];
max_installments_without_interests = get_max_installments_without_interests(number_of_installment, installment_data, max_installments_without_interests);
max_installments_with_interests = get_max_installments_with_interests(number_of_installment, installment_data, max_installments_with_interests);
var installment_container_selector = '#installment_' + payment_method.replace(" ", "_") + '_' + number_of_installment;
if(!parent.hasClass("js-quickshop-container")){
installment_helper(jQueryNuvem(installment_container_selector), number_of_installment, installment_data.installment_value.toFixed(2));
}
}
}
var $installments_container = jQueryNuvem(variant.element + ' .js-max-installments-container .js-max-installments');
var $installments_modal_link = jQueryNuvem(variant.element + ' #btn-installments');
var $payments_module = jQueryNuvem(variant.element + ' .js-product-payments-container');
var $installmens_card_icon = jQueryNuvem(variant.element + ' .js-installments-credit-card-icon');
{% if product.has_direct_payment_only %}
var installments_to_use = max_installments_without_interests[0] >= 1 ? max_installments_without_interests : max_installments_with_interests;
if(installments_to_use[0] <= 0 ) {
{% else %}
var installments_to_use = max_installments_without_interests[0] > 1 ? max_installments_without_interests : max_installments_with_interests;
if(installments_to_use[0] <= 1 ) {
{% endif %}
$installments_container.hide();
$installments_modal_link.hide();
$payments_module.hide();
$installmens_card_icon.hide();
} else {
$installments_container.show();
$installments_modal_link.show();
$payments_module.show();
$installmens_card_icon.show();
installment_helper($installments_container, installments_to_use[0], installments_to_use[1]);
}
}
if(!parent.hasClass("js-quickshop-container")){
jQueryNuvem('#installments-modal .js-installments-one-payment').text(variant.price_short).attr("data-value", variant.price_number);
}
if (variant.price_short){
var variant_price_clean = variant.price_short.replace('$', '').replace('R', '').replace(',', '').replace('.', '');
var variant_price_raw = parseInt(variant_price_clean, 10);
parent.find('.js-price-display').text(variant.price_short).show();
parent.find('.js-price-display').attr("content", variant.price_number).data('productPrice', variant_price_raw);
} else {
parent.find('.js-price-display').hide();
}
if ((variant.compare_at_price_short) && !(parent.find(".js-price-display").css("display") == "none")) {
parent.find('.js-compare-price-display').text(variant.compare_at_price_short).show();
} else {
parent.find('.js-compare-price-display').hide();
}
var button = parent.find('.js-addtocart');
button.removeClass('cart').removeClass('contact').removeClass('nostock');
var $product_shipping_calculator = parent.find("#product-shipping-container");
{# Update CTA wording and status #}
{% if not store.is_catalog %}
if (!variant.available){
button.val('{{ "Sin stock" | translate }}');
button.addClass('nostock');
button.attr('disabled', 'disabled');
$product_shipping_calculator.hide();
} else if (variant.contact) {
button.val('{{ "Consultar precio" | translate }}');
button.addClass('contact');
button.removeAttr('disabled');
$product_shipping_calculator.hide();
} else {
button.val('{{ "Agregar al carrito" | translate }}');
button.addClass('cart');
button.removeAttr('disabled');
$product_shipping_calculator.show();
}
{% endif %}
{% if template == 'product' %}
const base_price = Number(jQueryNuvem("#price_display").attr("content"));
refreshInstallmentv2(base_price);
refreshPaymentDiscount(variant.price_number);
{% if settings.last_product and product.variations %}
if(variant.stock == 1) {
jQueryNuvem('.js-last-product').show();
} else {
jQueryNuvem('.js-last-product').hide();
}
{% endif %}
{% endif %}
{# Update shipping on variant change #}
LS.updateShippingProduct();
zipcode_on_changevariant = jQueryNuvem("#product-shipping-container .js-shipping-input").val();
jQueryNuvem("#product-shipping-container .js-shipping-calculator-current-zip").text(zipcode_on_changevariant);
}Por fim, adicione a seguinte função:
{# /* // Product labels on variant change */ #}
{# Stock, Offer and discount labels update #}
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 #}
var quick_id = $quickshop_parent_wrapper.attr("data-quickshop-id");
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);
{% if settings.product_color_variants %}
{# Match selected color variant with selected quickshop variant #}
if(($variants_group).hasClass("js-color-variants-container")){
var selected_option_id = jQueryNuvem(this).find("option:selected").val();
if($quickshop_parent.hasClass("js-item-slide")){
var $color_parent_to_update = jQueryNuvem('.js-swiper-slide-visible .js-quickshop-container[data-quickshop-id="'+quick_id+'"]');
}else{
var $color_parent_to_update = jQueryNuvem('.js-quickshop-container[data-quickshop-id="'+quick_id+'"]');
}
$color_parent_to_update.find('.js-color-variant, .js-insta-variant').removeClass("selected");
$color_parent_to_update.find('.js-color-variant[data-option="'+selected_option_id+'"], .js-insta-variant[data-option="'+selected_option_id+'"]').addClass("selected");
}
{% endif %}
} 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();
}
});2. Pero también necesitamos agregar el JS que hace funcionar al componente del modal en general y para las tabs
{#/*============================================================================
#Modals
==============================================================================*/ #}
{# Full screen mobile modals back events #}
if (window.innerWidth < 768) {
{# Clean url hash function #}
cleanURLHash = function(){
const uri = window.location.toString();
const clean_uri = uri.substring(0, uri.indexOf("#"));
window.history.replaceState({}, document.title, clean_uri);
};
{# Go back 1 step on browser history #}
goBackBrowser = function(){
cleanURLHash();
history.back();
};
{# Clean url hash on page load: All modals should be closed on load #}
if(window.location.href.indexOf("modal-fullscreen") > -1) {
cleanURLHash();
}
{# Open full screen modal and url hash #}
jQueryNuvem(document).on("click", ".js-fullscreen-modal-open", function(e) {
e.preventDefault();
var modal_url_hash = jQueryNuvem(this).data("modalUrl");
window.location.hash = modal_url_hash;
});
{# Close full screen modal: Remove url hash #}
jQueryNuvem(document).on("click", ".js-fullscreen-modal-close", function(e) {
e.preventDefault();
goBackBrowser();
});
{# Hide panels or modals on browser backbutton #}
window.onhashchange = function() {
if(window.location.href.indexOf("modal-fullscreen") <= -1) {
{# Close opened modal #}
if(jQueryNuvem(".js-fullscreen-modal").hasClass("modal-show")){
{# Remove body lock only if a single modal is visible on screen #}
if(jQueryNuvem(".js-modal.modal-show").length == 1){
jQueryNuvem("body").removeClass("overflow-none");
}
var $opened_modal = jQueryNuvem(".js-fullscreen-modal.modal-show");
var $opened_modal_overlay = $opened_modal.prev();
$opened_modal.removeClass("modal-show");
setTimeout(() => $opened_modal.hide(), 500);
$opened_modal_overlay.fadeOut(500);
}
}
}
}
jQueryNuvem(document).on("click", ".js-modal-open", function(e) {
e.preventDefault();
var modal_id = jQueryNuvem(this).data('toggle');
var $overlay_id = jQueryNuvem('.js-modal-overlay[data-modal-id="' + modal_id + '"]');
if (jQueryNuvem(modal_id).hasClass("modal-show")) {
let modal = jQueryNuvem(modal_id).removeClass("modal-show");
setTimeout(() => modal.hide(), 500);
} else {
{# Lock body scroll if there is no modal visible on screen #}
if(!jQueryNuvem(".js-modal.modal-show").length){
jQueryNuvem("body").addClass("overflow-none");
}
$overlay_id.fadeIn(400);
jQueryNuvem(modal_id).detach().appendTo("body");
$overlay_id.detach().insertBefore(modal_id);
jQueryNuvem(modal_id).show().addClass("modal-show");
}
});
jQueryNuvem(document).on("click", ".js-modal-close", function(e) {
e.preventDefault();
{# Remove body lock only if a single modal is visible on screen #}
if(jQueryNuvem(".js-modal.modal-show").length == 1){
jQueryNuvem("body").removeClass("overflow-none");
}
var $modal = jQueryNuvem(this).closest(".js-modal");
var modal_id = $modal.attr('id');
var $overlay_id = jQueryNuvem('.js-modal-overlay[data-modal-id="#' + modal_id + '"]');
$modal.removeClass("modal-show");
setTimeout(() => $modal.hide(), 500);
$overlay_id.fadeOut(500);
{# Close full screen modal: Remove url hash #}
if ((window.innerWidth < 768) && (jQueryNuvem(this).hasClass(".js-fullscreen-modal-close"))) {
goBackBrowser();
}
});
jQueryNuvem(document).on("click", ".js-modal-overlay", function(e) {
e.preventDefault();
{# Remove body lock only if a single modal is visible on screen #}
if(jQueryNuvem(".js-modal.modal-show").length == 1){
jQueryNuvem("body").removeClass("overflow-none");
}
var modal_id = jQueryNuvem(this).data('modalId');
let modal = jQueryNuvem(modal_id).removeClass("modal-show");
setTimeout(() => modal.hide(), 500);
jQueryNuvem(this).fadeOut(500);
if (jQueryNuvem(this).hasClass("js-fullscreen-overlay") && (window.innerWidth < 768)) {
cleanURLHash();
}
});
{#/*============================================================================
#Tabs
==============================================================================*/ #}
var $tab_open = jQueryNuvem('.js-tab');
$tab_open.on("click", function (e) {
e.preventDefault();
var $tab_container = jQueryNuvem(e.currentTarget).closest(".js-tab-container");
$tab_container.find(".js-tab, .js-tab-panel").removeClass("active");
jQueryNuvem(e.currentTarget).addClass("active");
var tab_to_show = jQueryNuvem(e.currentTarget).find(".js-tab-link").attr("href");
$tab_container.find(tab_to_show).addClass("active");
});3. Como neste tutorial usamos a técnica de lazy load com o plugin Lazysizes, precisamos adicioná-lo. Para ver como fazer isso, você pode ler este pequeno artigo e continuar com este tutorial.
Traduções
Nesta etapa, adicionamos os textos para as traduções no arquivo config/translations.txt
es "Ver medios de pago" pt "Ver meios de pagamento" en "See payment options" es_mx "Ver métodos de pago"
Pronto! Já tem a funcionalidade aplicada. Parabéns!