Skip to content

Instantly share code, notes, and snippets.

@EduardoRodriguesF
Created March 18, 2022 21:07
Show Gist options
  • Save EduardoRodriguesF/9ff2fbac9bc8e5900b28f8901ab6d0a8 to your computer and use it in GitHub Desktop.
Save EduardoRodriguesF/9ff2fbac9bc8e5900b28f8901ab6d0a8 to your computer and use it in GitHub Desktop.
Modal CPG for VTEX Legacy. Can be used and adapted for any store easily.
<script>
window.modalCpgConfig = {
enabled: true, // true - LIGADO | false - DESLIGADO
promotionId: 'd33dff00-919a-4d18-bf4e-6f1d286acb8f', // ID da promoção para aparecer no Modal
modalTitle: 'Esse descontão é pra você!', // Título do modal
addButtonText: 'Eu quero!', // Texto do botão adicionar à sacola
refuseButtonText: 'Não quero, obrigado!', // Texto do botão de recusar
}
</script>
<div id="e-modalCpg" class="e-modalCpg" style="display: none">
<div class="e-modalCpg__content">
<span id="e-modalCpg-close" class="e-modalCpg__closeButton"></span>
<h2>[Título]</h2>
<p>Escolha um desses produtos para ganhar <strong><span id="e-modalCpg-discount">[desconto]</span> OFF!</strong></p>
<ul id="e-modalCpg-shelf"></ul>
<button id="e-modalCpg-add">
<span>[addButtonText]</span>
<div class="icon">
<span></span>
</div>
</button>
<a href="#" id="e-modalCpg-refuse">[refuseButtonText]</a>
</div>
</div>
const ModalCpg = {
triggerItemsList: [],
itemsAdded: [],
promo: null,
previousOrderForm: {},
selectors: {
overlay: '#e-modalCpg',
content: '.e-modalCpg__content',
closeButton: '#e-modalCpg-close',
title: '#e-modalCpg h2',
discount: '#e-modalCpg-discount',
addButton: '#e-modalCpg-add',
addButtonIcon: '#e-modalCpg-add .icon',
refuseButton: '#e-modalCpg-refuse',
shelf: '#e-modalCpg-shelf',
selectedItem: '#e-modalCpg-shelf .slick-current',
slickSlider: '#e-modalCpg .slick-slider',
slickArrows: '#e-modalCpg-shelf .slick-arrow',
},
api: {
getPromo: function() {
const promoId = `promoId=${modalCpgConfig.promotionId}`;
const url = `https://app.econverse.com.br/cliente/imaginarium/casa-mind/get-promo.php?${promoId}`;
return $.ajax({ url });
},
getProductBySku: function(sku) {
const fq = `fq=skuId:${sku}`;
const url = `/api/catalog_system/pub/products/search/?${fq}`;
$.ajax({
url,
success: function(data) {
if (!data.length) return;
ModalCpg.build.setProduct(data[0]);
}
});
}
},
build: {
setTitle: function() {
$(ModalCpg.selectors.content).find('h2').text(modalCpgConfig.modalTitle);
},
setAddButtonText: function() {
$(ModalCpg.selectors.addButton).find('> span').text(modalCpgConfig.addButtonText);
},
setRefuseButtonText: function() {
$(ModalCpg.selectors.refuseButton).text(modalCpgConfig.refuseButtonText);
},
setDiscountLabel: function() {
const percentual = ModalCpg.promo.percentualDiscountValueList2;
$(ModalCpg.selectors.discount).text(`${percentual}%`);
},
unslickShelf: function() {
$(ModalCpg.selectors.shelf).slick('unslick');
},
slickShelf: function() {
$(ModalCpg.selectors.shelf).slick({
infinite: false,
centerMode: true,
variableWidth: true,
});
},
setProduct: function(product) {
const floatToCurrency = (price, base = 1) => `R$ ${(price/base).toFixed(2).toString().replace('.', ',')}`
const item = product.items[0];
if (!item.sellers[0].commertialOffer.AvailableQuantity) return;
ModalCpg.build.unslickShelf();
const skuId = item.itemId;
const imageUrl = item.images[0].imageUrl;
const imageAlt = item.images[0].imageAlt;
const productName = product.productName;
const listPriceFormatted = floatToCurrency(item.sellers[0].commertialOffer.ListPrice);
const bestPrice = Math.min(
item.sellers[0].commertialOffer.ListPrice *
Math.abs(ModalCpg.promo.percentualDiscountValueList2 / 100 - 1),
item.sellers[0].commertialOffer.Price
);
const bestPriceFormatted = floatToCurrency(bestPrice);
const installments = item.sellers[0].commertialOffer.PaymentOptions.installmentOptions[0].installments.length;
const installmentsPrice = floatToCurrency(bestPrice / installments);
$(ModalCpg.selectors.shelf).append(`
<li class="modalShelfItem" data-skuid=${skuId}>
<img src=${imageUrl} alt=${imageAlt} />
<h3>${productName}</h3>
<span class="modalShelfItem__listPrice">${listPriceFormatted}</span>
<span class="modalShelfItem__bestPrice">${bestPriceFormatted}</span>
<span class="modalShelfItem__installments">Ou ${installments}x ${installmentsPrice}</span>
</li>
`);
ModalCpg.build.slickShelf();
},
setShelfContent: function() {
ModalCpg.promo.listSku2BuyTogether.forEach(function(item) {
ModalCpg.api.getProductBySku(item.id);
});
},
init: function() {
ModalCpg.build.setTitle();
ModalCpg.build.setAddButtonText();
ModalCpg.build.setRefuseButtonText();
ModalCpg.build.setDiscountLabel();
ModalCpg.build.slickShelf();
ModalCpg.build.setShelfContent();
}
},
addButton: {
setDisabled(disabled) {
$(ModalCpg.selectors.addButton).attr('disabled', disabled);
},
setLoading(loading) {
if (loading) {
$(ModalCpg.selectors.addButton).addClass('loading');
$(ModalCpg.selectors.slickArrows).addClass('slick-disabled');
} else {
$(ModalCpg.selectors.addButton).removeClass('loading');
$(ModalCpg.selectors.slickArrows).removeClass('slick-disabled');
}
ModalCpg.addButton.setDisabled(loading);
},
setDone: function(done) {
if (done) {
$(ModalCpg.selectors.addButton).addClass('done');
} else {
$(ModalCpg.selectors.addButton).removeClass('done');
}
ModalCpg.addButton.setDisabled(done);
},
handleClick: function() {
$(ModalCpg.selectors.addButton).on('click', function() {
const selectedItem = $(ModalCpg.selectors.selectedItem);
const id = selectedItem.find('*[data-skuid]').attr('data-skuid');
const quantity = 1;
const seller = 1;
const item = {
id,
quantity,
seller,
}
ModalCpg.addButton.setLoading(true);
vtexjs.checkout.addToCart([item]).then(function() {
ModalCpg.addButton.setLoading(false);
ModalCpg.addButton.setDone(true);
ModalCpg.itemsAdded.push(id);
});
});
},
init: function() {
ModalCpg.addButton.handleClick();
}
},
events: {
handleOrderFormUpdate: function() {
$(window).on('orderFormUpdated.vtex', function(_, orderForm) {
if (
!ModalCpg.previousOrderForm
|| ModalCpg.previousOrderForm.items.length >= orderForm.items.length
|| orderForm.value < ModalCpg.promo.totalValueFloor
) return;
let hasTriggerItemsInCart = false;
orderForm.items.every(function(item) {
if (ModalCpg.triggerItemsList.indexOf(item.id) > -1) {
hasTriggerItemsInCart = true;
}
return !hasTriggerItemsInCart;
});
if (!hasTriggerItemsInCart) return;
setTimeout(ModalCpg.open, 5000);
ModalCpg.previousOrderForm = orderForm;
});
},
handleModalClose: function() {
$(ModalCpg.selectors.closeButton).on('click', ModalCpg.close);
$(ModalCpg.selectors.refuseButton).on('click', ModalCpg.close);
},
handleSlideChange: function() {
$(document).on('beforeChange', ModalCpg.selectors.slickSlider, function(_e, _slick, _currentSlick, nextSlide) {
const isNextItemAdded = ModalCpg.itemsAdded.indexOf(
$(ModalCpg.selectors.slickSlider).find(`*[data-slick-index=${nextSlide}] *[data-skuid]`).attr('data-skuid')
) > -1;
ModalCpg.addButton.setDone(isNextItemAdded);
});
},
init: function() {
ModalCpg.events.handleOrderFormUpdate();
ModalCpg.events.handleModalClose();
ModalCpg.events.handleSlideChange();
}
},
open: function() {
$(ModalCpg.selectors.overlay).show();
$('body').css('overflow', 'hidden');
$('#e-modalCpg-shelf').slick('refresh');
},
close: function() {
$(ModalCpg.selectors.overlay).hide();
$('body').css('overflow', 'initial');
},
init: function() {
if (!modalCpgConfig.promotionId || !modalCpgConfig.enabled) return;
ModalCpg.api.getPromo().then(function(promo) {
if (!promo) return;
ModalCpg.promo = promo;
ModalCpg.previousOrderForm = vtexjs.checkout.orderForm;
ModalCpg.triggerItemsList = ModalCpg.promo.listSku1BuyTogether.map((item) => item.id);
ModalCpg.events.init();
ModalCpg.build.init();
ModalCpg.addButton.init();
});
}
}
ModalCpg.init();
window.ModalCpg = ModalCpg;
.e-modalCpg {
position: fixed;
z-index: 10000000; // <-- I didn't want to do this.
top: 0;
left: 0;
width: 100%;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: rgba(45, 45, 45, 0.7);
&__content {
position: relative;
width: 100%;
max-width: 304px;
background: #fff;
margin-inline: 16px;
padding: 30px;
text-align: center;
border-radius: 10px;
overflow: hidden;
#e-modalCpg-close {
color: #616161;
position: absolute;
top: 12px;
right: 10px;
font-size: 26px;
transform: rotate(-45deg);
font-weight: 700;
cursor: pointer;
&::before { content: '+'; }
}
h2 {
color: #ff2767;
font-size: 22px;
line-height: 22px;
font-weight: 700;
padding-inline: 30px;
}
p {
color: #5e5e5e;
font-size: 12px;
line-height: 16px;
font-weight: 500;
margin-top: 15px;
strong {
color: #ff2767;
font-weight: 700;
text-transform: uppercase;
}
}
#e-modalCpg-shelf {
position: relative;
margin-top: 18px;
.slick-arrow {
position: absolute;
font-size: 0;
top: 40%;
z-index: 10;
&::before {
content: '';
background-image: url("data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='21' fill='none' xmlns:v='https://vecta.io/nano'%3E%3Cpath d='M3.583 1.168a1.81 1.81 0 0 0-2.522 0c-.735.712-.735 1.89 0 2.602l5.612 5.44a2 2 0 0 1 0 2.872l-5.612 5.439c-.735.712-.735 1.89 0 2.602a1.81 1.81 0 0 0 2.522 0l8.297-8.042a2 2 0 0 0 0-2.872L3.583 1.168z' fill='%23ff2767'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
}
&.slick-disabled {
opacity: 0.3;
pointer-events: none;
}
&.slick-prev {
left: -8px;
transform: rotate(180deg);
}
&.slick-next {
right: -8px;
}
}
.slick-list {
overflow: visible;
margin-inline: -20px;
.slick-slide {
margin-inline: 20px;
}
}
.modalShelfItem {
position: relative;
width: 100%;
max-width: 189px;
text-align: center;
box-sizing: content-box;
margin-inline: auto;
img {
width: 100%;
border-radius: 10px;
}
h3 {
color: #454545;
font-size: 15px;
line-height: 18px;
font-weight: 500;
margin-block: 10px 12px;
}
span {
display: block;
}
&__listPrice {
color: #a9a9a9;
font-size: 12px;
line-height: 16px;
font-weight: 400;
&::before { content: 'De ' }
}
&__bestPrice {
color: #ff2767;
font-size: 16px;
line-height: 16px;
font-weight: 700;
margin-top: 3px;
&::before { content: 'Por ' }
}
&__installments {
color: #454545;
font-size: 11px;
line-height: 18px;
font-weight: 400;
margin-top: 3px;
}
}
}
#e-modalCpg-add {
display: flex;
width: 100%;
height: 48px;
margin-top: 27px;
border: 1px solid #ff2767;
border-radius: 10px;
overflow: hidden;
font-size: 16px;
line-height: 16px;
font-weight: 600;
transition: 0.35s;
&.loading {
.icon {
color: #fff;
background: #ff2767;
span {
background-image: url("data:image/svg+xml,%0A%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M12 2V6' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M12 18V22' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M4.93018 4.92999L7.76018 7.75999' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M16.2402 16.24L19.0702 19.07' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M2 12H6' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M18 12H22' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M4.93018 19.07L7.76018 16.24' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M16.2402 7.75999L19.0702 4.92999' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A");
}
}
}
&.done {
.icon {
span {
background-image: url("data:image/svg+xml,%0A%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M20 6L9 17L4 12' stroke='%23FF2767' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A");
}
}
}
> span, .icon {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
> span {
color: #fff;
background: #ff2767;
width: 100%;
}
.icon {
color: #ff2767;
background: #fff;
width: 65px;
span {
width: 100%;
height: 100%;
background-position: center;
background-repeat: no-repeat;
background-image: url("data:image/svg+xml,%0A%3Csvg width='20' height='24' viewBox='0 0 20 24' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M6.66667 4.625C6.66667 2.89911 8.06578 1.5 9.79167 1.5C11.5176 1.5 12.9167 2.89911 12.9167 4.625V5.16667H6.66667V4.625ZM5.16667 6.66667V8.5C5.16667 8.91421 5.50245 9.25 5.91667 9.25C6.33088 9.25 6.66667 8.91421 6.66667 8.5V6.66667H12.9167V8.5C12.9167 8.91421 13.2525 9.25 13.6667 9.25C14.0809 9.25 14.4167 8.91421 14.4167 8.5V6.66667H16.8471L18.0234 21.9583H1.55991L2.73619 6.66667H5.16667ZM5.16667 5.16667V4.625C5.16667 2.07068 7.23735 0 9.79167 0C12.346 0 14.4167 2.07068 14.4167 4.625V5.16667H17.5417C17.9336 5.16667 18.2594 5.4684 18.2895 5.85914L19.5811 22.6508C19.5971 22.8591 19.5256 23.0646 19.3836 23.2179C19.2417 23.3712 19.0422 23.4583 18.8333 23.4583H0.750002C0.541094 23.4583 0.341653 23.3712 0.19971 23.2179C0.0577681 23.0646 -0.0138112 22.8591 0.00221127 22.6508L1.29388 5.85914C1.32394 5.4684 1.64977 5.16667 2.04167 5.16667H5.16667Z' fill='%23FF2767'/%3E%3C/svg%3E%0A");
}
}
}
#e-modalCpg-refuse {
display: inline-block;
color: #a9a9a9;
font-size: 12px;
line-height: 15px;
font-weight: 400;
text-decoration: underline;
margin-top: 10px;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment