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!