fm-lp-factory
Version:
package created to build web ui components for FidelizarMais LP services
523 lines (455 loc) • 18.7 kB
JavaScript
import { updateFmTemplateCss } from "../index.js";
let slideIndex = 1;
let section = null;
export default (component) => {
css();
createCpfModal(); // Criação do modal para inserir CPF
section = document.createElement("section");
section.classList.add("fm-carousel-of-awards-with-redemption", "fm-section-container", "fm-carrousel-hidden");
section.innerHTML = template
.replace("%title%", component.title)
.replace("%subtitle%", component.subtitle);
document.querySelector("#fm-landing-page-content").appendChild(section);
LoyalJS.public.services().getAllPossibleAwards()
.then((listOfAwards) => {
if (listOfAwards.length > 0) {
section.classList.remove("fm-carrousel-hidden");
createCardImage(listOfAwards);
} else throw new Error("No data for carrousel found");
})
.catch((error) => {
console.log(error);
});
section.querySelector('[fm-action="slidePrev"]').addEventListener("click", () => {
plusSlides(-1);
});
section.querySelector('[fm-action="slideNext"]').addEventListener("click", () => {
plusSlides(1);
});
};
const template = /*html*/ `
<div class="fm-carousel-of-awards-with-redemption-inner-container">
<div class="fm-carousel-of-awards-with-redemption-header">
<span class="fm-carousel-of-awards-with-redemption-inner-subtitle">%subtitle%</span>
<span class="fm-carousel-of-awards-with-redemption-inner-title">%title%</span>
</div>
<div class="carousel-inner-container">
<div class="fm-carousel-control">
<span class="fm-carousel-control-btn" fm-action="slidePrev">❮</span>
<span class="fm-carousel-control-btn" fm-action="slideNext">❯</span>
</div>
</div>
</div>
`;
const templateCarrouselCard = /*html*/ `
<div class="fm-carousel-of-awards-with-redemption-cell fm-fade fm-carousel-hidden">
<div class="fm-carrousel-img-frame">
<img src="%cardImage">
</div>
<div class="fm-carousel-of-awards-with-redemption-coupon-details">
<span title>%couponName%</span>
<span couponPoints>%couponPoints%</span>
</div>
<div class="fm-button-container" fm-action="redeemAward" data-award='%awardData%'>
<span>Resgatar</span>
</div>
</div>
`;
const createCardImage = (listOfImages) => {
listOfImages.forEach((card) => {
const awardData = JSON.stringify({
id: card.id,
name: card.name,
points: card.point,
categoryAwardId: card.categoryAwardId,
});
const cardTemplate = templateCarrouselCard
.replace("%cardImage", card.image)
.replace("%couponName%", card.name)
.replace("%couponPoints%", `${card.point} pontos`)
.replace("%awardData%", awardData);
section.querySelector(".carousel-inner-container").insertAdjacentHTML("beforeend", cardTemplate);
// Evento para abrir o modal de CPF
section.querySelectorAll("[fm-action='redeemAward']").forEach((btn) => {
btn.addEventListener("click", (e) => {
const award = JSON.parse(e.target.closest("[fm-action='redeemAward']").dataset.award);
openCpfModal(award);
});
});
showSlides(slideIndex);
});
};
function openCpfModal(award) {
const modal = document.querySelector("#cpf-modal");
modal.style.display = "flex";
document.body.style.overflow = "hidden";
const confirmButton = modal.querySelector("#confirm-redeem");
const cpfInput = modal.querySelector("#cpf-input");
modal.querySelector("#award-name").textContent = award.name;
modal.querySelector("#award-points").textContent = `${award.points} pontos`;
const errorMsg = document.createElement("div"); // Para mensagens de erro
errorMsg.style.color = "red";
errorMsg.style.marginTop = "5px";
cpfInput.parentNode.insertBefore(errorMsg, confirmButton);
// Adiciona máscara de CPF/CNPJ
cpfInput.addEventListener("input", (e) => {
let value = e.target.value.replace(/\D/g, ""); // Remove tudo que não for número
if (value.length <= 11) {
// CPF: 000.000.000-00
value = value.replace(/^(\d{3})(\d)/, "$1.$2");
value = value.replace(/^(\d{3})\.(\d{3})(\d)/, "$1.$2.$3");
value = value.replace(/\.(\d{3})(\d)/, ".$1-$2");
} else {
// CNPJ: 00.000.000/0000-00
value = value.replace(/^(\d{2})(\d)/, "$1.$2");
value = value.replace(/^(\d{2})\.(\d{3})(\d)/, "$1.$2.$3");
value = value.replace(/\.(\d{3})(\d)/, ".$1/$2");
value = value.replace(/(\d{4})(\d)/, "$1-$2");
}
e.target.value = value;
});
confirmButton.onclick = async () => {
const cpf = cpfInput.value.replace(/\D/g, ""); // Limpa apenas números
errorMsg.textContent = ""; // Limpa erros anteriores
if (!cpf || (cpf.length !== 11 && cpf.length !== 14)) {
errorMsg.textContent = "Por favor, insira um CPF ou CNPJ válido.";
return;
}
confirmButton.disabled = true;
confirmButton.textContent = "Aguarde...";
confirmButton.style.backgroundColor = "#ccc";
confirmButton.style.cursor = "not-allowed";
try {
const response = await LoyalJS.public.services().redeemPoints({
document: cpf,
awardId: award.id,
cashback: false,
points: award.points,
categoryAwardId: award.categoryAwardId,
validMember: true,
type: 18,
shortDescription: "Resgate",
partner: window.LoyalJS.settings.partnerId,
accountManager: cpf,
withReturn: false,
});
if (response.body.success) {
modal.querySelector(".modal-content").innerHTML = `
<span id="close-modal" class="close">×</span>
<img src="https://cdn.fidelizarmais.com/files/production/6223cfa9-54ec-4072-a27e-b500f68f40dd/landing-page/assets/imgs/icone-8.png"/>
<h2>Resgate Concluído</h2>
<p>${response.body.data.message}</p>
<button id="copy-coupon">Copiar Cupom</button>
`;
const copyButton = modal.querySelector("#copy-coupon");
copyButton.addEventListener("click", () => {
navigator.clipboard.writeText(response.body.data.couponCode);
closeModal();
});
modal.querySelector("#close-modal").onclick = closeModal;
} else {
errorMsg.textContent = response.body.message || "Erro ao resgatar o prêmio.";
}
} catch (error) {
console.error(error);
errorMsg.textContent = "Erro ao realizar o resgate. Tente novamente.";
} finally {
confirmButton.disabled = false;
confirmButton.textContent = "Confirmar";
confirmButton.style.backgroundColor = "";
confirmButton.style.cursor = "pointer";
}
};
modal.querySelector("#close-modal").onclick = closeModal;
}
function closeModal() {
const modal = document.querySelector("#cpf-modal");
modal.style.display = "none";
document.body.style.overflow = ""; // Restaura o scroll da página
}
function createCpfModal() {
const modal = document.createElement("div");
modal.id = "cpf-modal";
modal.style.display = "none";
modal.innerHTML = `
<div class="modal-content">
<span id="close-modal" class="close">×</span>
<img src="https://cdn.fidelizarmais.com/files/production/6223cfa9-54ec-4072-a27e-b500f68f40dd/landing-page/assets/imgs/icone-8.png"/>
<h2>Confirmar Resgate</h2>
<p>Ao inserir o seu <strong>CPF</strong> ou <strong>CNPJ</strong> e selecionar a opção confirmar abaixo você ira realizar o resgate do <strong>Cupom de <span id="award-name"></span></strong> por <strong><span id="award-points">.</span></strong></p>
<input id="cpf-input" type="text" placeholder="CPF ou CPNJ" />
<button id="confirm-redeem">Confirmar</button>
</div>
`;
document.body.appendChild(modal);
}
function plusSlides(n) {
const totalSlides = document.querySelectorAll(".fm-carousel-of-awards-with-redemption-cell").length;
const slidesToShow = getVisibleSlides();
// Ajusta o índice respeitando os limites
if (slideIndex + n < 0) {
slideIndex = 0;
} else if (slideIndex + n > totalSlides - slidesToShow) {
slideIndex = totalSlides - slidesToShow;
} else {
slideIndex += n;
}
showSlides(slideIndex);
updateNavigationButtons();
}
function showSlides(index) {
const slides = document.querySelectorAll(".fm-carousel-of-awards-with-redemption-cell");
const slidesToShow = getVisibleSlides();
slides.forEach(slide => slide.classList.add("fm-carousel-hidden"));
for (let i = index; i < index + slidesToShow; i++) {
if (slides[i]) slides[i].classList.remove("fm-carousel-hidden");
}
}
function updateNavigationButtons() {
const prevBtn = document.querySelector('[fm-action="slidePrev"]');
const nextBtn = document.querySelector('[fm-action="slideNext"]');
const totalSlides = document.querySelectorAll(".fm-carousel-of-awards-with-redemption-cell").length;
const slidesToShow = getVisibleSlides();
prevBtn.style.opacity = slideIndex <= 0 ? "0.5" : "1";
prevBtn.style.pointerEvents = slideIndex <= 0 ? "none" : "auto";
nextBtn.style.opacity = slideIndex >= totalSlides - slidesToShow ? "0.5" : "1";
nextBtn.style.pointerEvents = slideIndex >= totalSlides - slidesToShow ? "none" : "auto";
}
function getVisibleSlides() {
return window.innerWidth > 1000 ? 4 : window.innerWidth > 768 ? 3 : 2;
}
const css = () => {
updateFmTemplateCss(/*css*/
`
.fm-carousel-control-btn {
opacity: 1;
transition: opacity 0.3s ease;
}
.fm-carousel-control-btn[style*="none"] {
cursor: not-allowed;
}
.fm-carousel-of-awards-with-redemption{
width: 100%;
background: var(--fm-primary-light-color);
}
.fm-carousel-of-awards-with-redemption-inner-container{
padding:45px 0;
}
.fm-carousel-of-awards-with-redemption .fm-carousel-of-awards-with-redemption-inner-title{
font-size: 32px;
margin: 0;
font-weight: bold;
text-align: center;
}
.fm-carousel-of-awards-with-redemption .fm-carousel-of-awards-with-redemption-inner-subtitle{
font-size: 1.1rem;
color: var(--fm-secondary-color);
}
.fm-carousel-of-awards-with-redemption .fm-carousel-of-awards-with-redemption-header {
display: flex;
align-items: center;
margin-bottom: 15px;
flex-direction: column;
justify-content: center;
}
.fm-carousel-of-awards-with-redemption .fm-carousel-of-awards-with-redemption-coupon-details{
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
gap: 5px;
margin-top: 10px;
}
.fm-carousel-of-awards-with-redemption-coupon-details span[title],
.fm-carousel-of-awards-with-redemption-coupon-details span[couponPoints]{
margin:0 5px;
}
.fm-carousel-of-awards-with-redemption-coupon-details span[couponPoints]{
font-weight: bold;
}
.fm-carousel-of-awards-with-redemption .fm-button-container{
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
right: 0;
width: 85%;
background: var(--fm-primary-button-color);
color: var(--fm-primary-button-text-color);
border-radius: var(--fm-base-border-radius);
margin: 10px auto;
padding: 10px;
}
.fm-carousel-of-awards-with-redemption .fm-carousel-hidden,
.fm-carousel-of-awards-with-redemption.fm-carrousel-hidden {
display: none;
}
.fm-carousel-of-awards-with-redemption .carousel-inner-container {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
@media (max-width: 768px) {
.fm-carousel-of-awards-with-redemption .carousel-inner-container {
overflow: hidden;
width: 100%;
}
.fm-carousel-of-awards-with-redemption .fm-carousel-of-awards-with-redemption-inner-title {
font-size: 28px;
}
.fm-carousel-of-awards-with-redemption
.carousel-inner-container .fm-carousel-of-awards-with-redemption-cell {
margin: 0 5px !important;
}
}
.fm-carousel-of-awards-with-redemption .fm-carousel-control .fm-carousel-control-btn {
padding: 2px 12px;
cursor: pointer;
background: var(--fm-secondary-button-color);
color: var(--fm-secondary-button-text-color);
border-radius: 50%;
transition: all 0.6s ease;
position: absolute;
margin: 0 2%;
}
.fm-carousel-of-awards-with-redemption .fm-carousel-control .fm-carousel-control-btn[fm-action="slidePrev"] {
left: 0;
}
.fm-carousel-of-awards-with-redemption .fm-carousel-control .fm-carousel-control-btn[fm-action="slideNext"] {
right: 0;
}
.fm-carousel-of-awards-with-redemption
.carousel-inner-container .fm-carousel-of-awards-with-redemption-cell {
margin: 0 15px;
padding: 15px;
background: var(--fm-card-primary-background);
border-radius: var(--fm-base-border-radius);
}
.fm-carousel-of-awards-with-redemption .carousel-inner-container
.fm-carousel-of-awards-with-redemption-cell img {
width: 100%;
height: 100%;
object-fit: cover;
}
.fm-carousel-of-awards-with-redemption .carousel-inner-container
.fm-carousel-of-awards-with-redemption-cell .fm-carrousel-img-frame {
width: 300px;
height: 300px;
border-radius: var(--fm-base-border-radius);
transition: all .3s ease;
overflow: hidden;
}
@media (max-width: 1100px) {
.fm-carousel-of-awards-with-redemption
.carousel-inner-container .fm-carousel-of-awards-with-redemption-cell .fm-carrousel-img-frame {
width: 100%;
height: 200px;
}
}
@media (max-width: 768px) {
.fm-carousel-of-awards-with-redemption
.carousel-inner-container .fm-carousel-of-awards-with-redemption-cell .fm-carrousel-img-frame {
width: 150px;
}
}
/* Fading animation */
.fm-fade {
animation-name: fm-fade-key;
animation-duration: 1.5s;
}
@keyframes fm-fade-key {
from {
opacity: .4
}
to {
opacity: 1
}
}
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5); /* Fundo semi-transparente */
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 8px;
text-align: center;
width: 90%;
max-width: 400px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2);
position: relative;
animation: fadeIn 0.3s ease-in-out;
}
.modal-content p {
text-align: justify;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.close {
position: absolute;
top: 10px;
right: 10px;
font-size: 20px;
cursor: pointer;
color:
transition: color 0.2s;
}
.close:hover {
color:
}
width: calc(100% - 40px);
max-width: 300px;
padding: 10px;
font-size: 1rem;
border: 1px solid
border-radius: 5px;
margin-top: 10px;
}
background:
color: white;
border: none;
border-radius: 5px;
padding: 12px 20px;
font-size: 1rem;
cursor: pointer;
transition: background 0.3s;
margin-top: 15px;
}
background:rgb(40, 173, 250);
}
@media (max-width: 768px) {
.modal-content {
padding: 15px;
}
font-size: 0.9rem;
padding: 8px;
}
font-size: 0.9rem;
padding: 10px 15px;
}
}
`
);
};