codigos presentes no FormCraft no WordPress
This commit is contained in:
Felipe de Moraes Gomes 2026-04-06 16:21:37 -03:00
commit f9ed9e6750
4 changed files with 1285 additions and 0 deletions

View File

@ -0,0 +1,125 @@
<div class="planos__container" id="planos-empresa">
<div class="planos-cards__container">
<div class="seller-card__container">
<div class="card-title__container">
<div class="card-title__number"><h1>100</h1></div>
<div class="card-title__text"><h1>MEGA</h1></div>
</div> <div class="card-description__container">
<div class="card-description__image">
<img src="https://sothis.com.br/wp-content/uploads/2025/11/Wifi-01.png" alt="Ícone do WiFi" width="35">
</div>
<div class="card-description__content"><span> Super WiFi + IP Fixo </span></div>
</div>
<div class="card-price__container">
<div class="card-price__money"><p>R$</p></div>
<div class="card-price__value"><p>149,</p></div>
<div class="card-price-small__container">
<div class="small-price"><p>90</p></div>
<div class="small-gap-time"><p>/mês</p></div>
</div>
</div>
<div class="card-plan-button__container">
<a href="#" id="btn-plano-100-mega">SELECIONAR PLANO</a>
</div>
</div>
<div class="seller-card__container">
<div class="card-title__container">
<div class="card-title__number"><h1>200</h1></div>
<div class="card-title__text"><h1>MEGA</h1></div>
</div> <div class="card-description__container">
<div class="card-description__image">
<img src="https://sothis.com.br/wp-content/uploads/2025/11/Wifi-01.png" alt="Ícone do WiFi" width="35">
</div>
<div class="card-description__content"><span> Super WiFi + IP Fixo </span></div>
</div> <div class="card-price__container">
<div class="card-price__money"><p>R$</p></div>
<div class="card-price__value"><p>159,</p></div>
<div class="card-price-small__container">
<div class="small-price"><p>80</p></div>
<div class="small-gap-time"><p>/mês</p></div>
</div>
</div>
<div class="card-plan-button__container">
<a href="#" id="btn-plano-200-mega">SELECIONAR PLANO</a>
</div>
</div>
<div class="out-card__container">
<div class="most-sell-card__text"><p>MAIS VENDIDO</p></div>
<div class="most-sell-card__container">
<div class="best-seller-card__container">
<div class="card-title__container">
<div class="card-title__number"><h1>500</h1></div>
<div class="card-title__text"><h1>MEGA</h1></div>
</div> <div class="card-description__container">
<div class="card-description__image">
<img src="https://sothis.com.br/wp-content/uploads/2025/11/Wifi-01.png" alt="Ícone do WiFi" width="35">
</div>
<div class="card-description__content">
<span> Super WiFi + IP Fixo </span>
</div>
</div>
<div class="card-price__container">
<div class="card-price__money"><p>R$</p></div>
<div class="card-price__value"><p>199,</p></div>
<div class="card-price-small__container">
<div class="small-price"><p>80</p></div>
<div class="small-gap-time"><p>/mês</p></div>
</div>
</div>
<div class="card-plan-button__container">
<a href="#" id="btn-plano-500-mega">SELECIONAR PLANO</a>
</div>
</div>
</div>
</div>
<div class="seller-card__container">
<div class="card-title__container">
<div class="card-title__number"><h1>700</h1></div>
<div class="card-title__text"><h1>MEGA</h1></div>
</div>
<div class="card-description__container">
<div class="card-description__image">
<img src="https://sothis.com.br/wp-content/uploads/2025/11/Wifi-01.png" alt="Ícone do WiFi" width="35">
</div>
<div class="card-description__content"><span> Super WiFi + IP Fixo </span></div>
</div>
<div class="card-price__container">
<div class="card-price__money"><p>R$</p></div>
<div class="card-price__value"><p>259,</p></div>
<div class="card-price-small__container">
<div class="small-price"><p>75</p></div>
<div class="small-gap-time"><p>/mês</p></div>
</div>
</div>
<div class="card-plan-button__container">
<a href="#" id="btn-plano-700-mega">SELECIONAR PLANO</a>
</div>
</div>
<div class="seller-card__container">
<div class="card-title__container">
<div class="card-title__number"><h1>1</h1></div>
<div class="card-title__text"><h1>GB</h1></div>
</div>
<div class="card-description__container">
<div class="card-description__image">
<img src="https://sothis.com.br/wp-content/uploads/2025/11/Wifi-01.png" alt="Ícone do WiFi" width="35">
</div>
<div class="card-description__content"><span> Super WiFi + IP Fixo </span></div>
</div>
<div class="card-price__container">
<div class="card-price__money"><p>R$</p></div>
<div class="card-price__value"><p>319,</p></div>
<div class="card-price-small__container">
<div class="small-price"><p>70</p></div>
<div class="small-gap-time"><p>/mês</p></div>
</div>
</div>
<div class="card-plan-button__container">
<a href="#" id="btn-plano-1-gb">SELECIONAR PLANO</a>
</div>
</div>
</div>
<div class="instalacao__container">
<p>A taxa de instalação para qualquer um dos planos é de R$299,90. Esses valores são referentes ao contrato de 12 meses.</p>
</div>
</div>

View File

@ -0,0 +1,124 @@
<div class="planos__container" id="planos-residencial">
<div class="planos-cards__container">
<div class="seller-card__container">
<div class="card-title__container">
<div class="card-title__number"><h1>100</h1></div>
<div class="card-title__text"><h1>MEGA</h1></div>
</div>
<div class="card-description__container">
<div class="card-description__image">
<img src="https://sothis.com.br/wp-content/uploads/2025/11/Wifi-01.png" alt="Ícone do WiFi" width="35">
</div>
<div class="card-description__content"><span> Super WiFi </span></div>
</div> <div class="card-price__container">
<div class="card-price__money"><p>R$</p></div>
<div class="card-price__value"><p>69,</p></div>
<div class="card-price-small__container">
<div class="small-price"><p>90</p></div>
<div class="small-gap-time"><p>/mês</p></div>
</div>
</div>
<div class="card-plan-button__container">
<a href="#" id="btn-plano-100-mega">SELECIONAR PLANO</a>
</div>
</div>
<div class="seller-card__container">
<div class="card-title__container">
<div class="card-title__number"><h1>200</h1></div>
<div class="card-title__text"><h1>MEGA</h1></div>
</div> <div class="card-description__container">
<div class="card-description__image">
<img src="https://sothis.com.br/wp-content/uploads/2025/11/Wifi-01.png" alt="Ícone do WiFi" width="35">
</div>
<div class="card-description__content"><span> Super WiFi </span></div>
</div>
<div class="card-price__container">
<div class="card-price__money"><p>R$</p></div>
<div class="card-price__value"><p>79,</p></div>
<div class="card-price-small__container">
<div class="small-price"><p>90</p></div>
<div class="small-gap-time"><p>/mês</p></div>
</div>
</div>
<div class="card-plan-button__container">
<a href="#" id="btn-plano-200-mega">SELECIONAR PLANO</a>
</div> </div> <div class="out-card__container">
<div class="most-sell-card__text"><p>MAIS VENDIDO</p></div>
<div class="most-sell-card__container">
<div class="best-seller-card__container">
<div class="card-title__container">
<div class="card-title__number"><h1>500</h1></div>
<div class="card-title__text"><h1>MEGA</h1></div>
</div> <div class="card-description__container">
<div class="card-description__image">
<img src="https://sothis.com.br/wp-content/uploads/2025/11/Wifi-01.png" alt="Ícone do WiFi" width="35">
</div>
<div class="card-description__content">
<span> Super WiFi </span>
</div>
</div>
<div class="card-price__container">
<div class="card-price__money"><p>R$</p></div>
<div class="card-price__value"><p>119,</p></div>
<div class="card-price-small__container">
<div class="small-price"><p>90</p></div>
<div class="small-gap-time"><p>/mês</p></div>
</div>
</div>
<div class="card-plan-button__container">
<a href="#" id="btn-plano-500-mega">SELECIONAR PLANO</a>
</div>
</div>
</div>
</div>
<div class="seller-card__container">
<div class="card-title__container">
<div class="card-title__number"><h1>700</h1></div>
<div class="card-title__text"><h1>MEGA</h1></div>
</div>
<div class="card-description__container">
<div class="card-description__image">
<img src="https://sothis.com.br/wp-content/uploads/2025/11/Wifi-01.png" alt="Ícone do WiFi" width="35">
</div>
<div class="card-description__content"><span> Super WiFi </span></div>
</div>
<div class="card-price__container">
<div class="card-price__money"><p>R$</p></div>
<div class="card-price__value"><p>179,</p></div>
<div class="card-price-small__container">
<div class="small-price"><p>85</p></div>
<div class="small-gap-time"><p>/mês</p></div>
</div>
</div>
<div class="card-plan-button__container">
<a href="#" id="btn-plano-700-mega">SELECIONAR PLANO</a>
</div>
</div>
<div class="seller-card__container">
<div class="card-title__container">
<div class="card-title__number"><h1>1</h1></div>
<div class="card-title__text"><h1>GB</h1></div>
</div>
<div class="card-description__container">
<div class="card-description__image">
<img src="https://sothis.com.br/wp-content/uploads/2025/11/Wifi-01.png" alt="Ícone do WiFi" width="35">
</div>
<div class="card-description__content"><span> Super WiFi </span></div>
</div>
<div class="card-price__container">
<div class="card-price__money"><p>R$</p></div>
<div class="card-price__value"><p>239,</p></div>
<div class="card-price-small__container">
<div class="small-price"><p>80</p></div>
<div class="small-gap-time"><p>/mês</p></div>
</div>
</div>
<div class="card-plan-button__container">
<a href="#" id="btn-plano-1-gb">SELECIONAR PLANO</a>
</div>
</div>
</div>
<div class="instalacao__container">
<p>A taxa de instalação para qualquer um dos planos é de R$299,90. Esses valores são referentes ao contrato de 12 meses.</p>
</div>
</div>

663
teste/index.js Normal file
View File

@ -0,0 +1,663 @@
function smoothScrollToElement(element, offset = 150, duration = 500) {
const rect = element.getBoundingClientRect();
const startY = window.pageYOffset || window.scrollY || 0;
// ✅ offset inteligente: se o elemento está abaixo mas o offset é grande demais,
// reduz o offset pra garantir que o targetY fique realmente abaixo do startY.
let effectiveOffset = offset;
const minGap = 20; // distância mínima que você quer manter do topo
if (rect.top > 0 && rect.top < offset + minGap) {
effectiveOffset = Math.max(0, rect.top - minGap);
}
let targetY = rect.top + startY - effectiveOffset;
if (targetY < 0) targetY = 0;
const distance = targetY - startY;
// ✅ se ainda ficou 0, mas o elemento está abaixo, força um scroll mínimo
if (distance === 0 && rect.top > 0) {
targetY = startY + rect.top - minGap;
}
const finalDistance = targetY - startY;
if (finalDistance === 0) return;
const startTime = performance.now();
const easeOutQuad = (t) => t * (2 - t);
function step(currentTime) {
const elapsed = currentTime - startTime;
const t = Math.min(1, elapsed / duration);
const easedT = easeOutQuad(t);
window.scrollTo(0, startY + finalDistance * easedT);
if (t < 1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
function isVisible(el) {
if (!el) return false;
const style = window.getComputedStyle(el);
const rect = el.getBoundingClientRect();
return (
style.display !== "none" &&
style.visibility !== "hidden" &&
rect.height > 0 &&
rect.width > 0
);
}
function scrollToAssinar({ offset = 250, duration = 500, tries = 40 } = {}) {
// ✅ seu wrapper real é .form-element-field8
// Tentamos pegar o botão dentro dele; se não achar, rola até o wrapper mesmo
const selector =
'.form-element-field8 button, .form-element-field8 input[type="button"], .form-element-field8 input[type="submit"], .form-element-field8';
let attempt = 0;
function tick() {
const el = document.querySelector(selector);
if (isVisible(el)) {
smoothScrollToElement(el, offset, duration);
return;
}
attempt++;
if (attempt < tries) requestAnimationFrame(tick);
else
console.warn(
"[scroll] Botão de assinar não encontrado/visível. Seletor:",
selector,
);
}
requestAnimationFrame(tick);
}
function scrollToPlanosById(id, offset = 220, duration = 500) {
const el = document.getElementById(id);
if (!el) {
console.warn('[scroll] nao encontrei id:', id);
return;
}
requestAnimationFrame(() => {
requestAnimationFrame(() => {
smoothScrollToElement(el, offset, duration);
setTimeout(() => smoothScrollToElement(el, offset, duration), 120);
setTimeout(() => smoothScrollToElement(el, offset, duration), 260);
});
});
}
const cepInput = document.querySelector('[name="field6[]"]');
const numeroInput = document.querySelector('[name="field7[]"]');
const nomeInput = document.querySelector('[name="field3[]"]');
const emailInput = document.querySelector('[name="field4"]');
const telefone = document.querySelector('[name="field5[]"]');
const logradouro = document.querySelector('[name="field20[]"]');
const temosBandaLargaTitle = document.querySelector(".form-element-field23");
const temosBandaLargaBox = document.querySelector(".form-element-field24");
const naoTemosBandaLargaTitle = document.querySelector(".form-element-field33");
const errorBox = document.querySelector(".form-element-field32");
let temosBandaLarga = false;
let error = false;
const dataPayload = {};
const digitsOnly = (s) => (s || "").replace(/\D/g, "");
let debounceT,
inflight,
lastKey,
reqSeq = 0;
let isProcessing = false;
let originalBtnText = "";
// limpa campo de endereço
function limpar() {
logradouro.value = "";
// esconder blocos de resultado caso estejam visíveis
if (temosBandaLargaTitle) temosBandaLargaTitle.style.display = "none";
if (temosBandaLargaBox) temosBandaLargaBox.style.display = "none";
if (naoTemosBandaLargaTitle) naoTemosBandaLargaTitle.style.display = "none";
if (errorBox) errorBox.style.display = "none";
}
function pronto() {
// preciso que todos os campos estejam preenchidos (Nome, Email, CEP e Número)
const cep = digitsOnly(cepInput?.value);
const n = (numeroInput?.value || "").trim();
const nome = (nomeInput?.value || "").trim();
const email = (emailInput?.value || "").trim();
return cep.length === 8 && n && nome && email;
}
// JSON da consulta da API:
// {
// bairro: address.bairro,
// cidade: address.localidade,
// estado: address.uf,
// logradouro: address.logradouro,
// naoDedicado: naoDedicado,
// dedicado: dedicado,
// }
async function consultarCep() {
if (!pronto()) {
limpar();
lastKey = null;
error = true;
return;
}
const cep = digitsOnly(cepInput.value);
const numero = numeroInput.value.trim();
const key = `${cep}|${numero}`;
if (key === lastKey) return; // dedupe
lastKey = key;
// cancela requisição anterior
if (inflight) inflight.abort();
inflight = new AbortController();
const mySeq = ++reqSeq; // marca ordem da requisição
try {
const res = await fetch("https://api.sothis.com.br/api/viabilidade", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
nome: nomeInput.value,
email: emailInput.value,
telefone: telefone.value,
cep,
numero,
}),
signal: inflight.signal,
});
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(data?.error || `HTTP ${res.status}`);
// evita aplicar resposta atrasada
if (mySeq !== reqSeq) return;
error = false; // sucesso
// preenche no formulário dados de endereço
logradouro.value = data.logradouro || "";
// armazena resultados em uma variavel global para uso posterior
temosBandaLarga = data.naoDedicado;
dataPayload.bairro = data.bairro;
dataPayload.cidade = data.cidade;
dataPayload.estado = data.estado;
dataPayload.logradouro = data.logradouro;
dataPayload.naoDedicado = data.naoDedicado;
dataPayload.dedicado = data.dedicado;
} catch (e) {
if (e.name === "AbortError") return;
if (mySeq !== reqSeq) return;
limpar();
lastKey = null; // permite tentar de novo
// TODO: mostrar bloco de erro pro usuário
console.error("Erro ao consultar viabilidade:", e);
error = true;
} finally {
if (mySeq === reqSeq) {
inflight = null;
}
}
}
// CACHE
(function () {
function initFormCache() {
const form = document.querySelector(".fc-form-23"); // ajuste se tiver mais de um formulário
console.log("FormCraft cache: init chamado. Form encontrado?", !!form);
if (!form) return;
form.addEventListener("submit", function () {
console.log("FormCraft cache: submit disparou");
const data = {};
const fields = form.querySelectorAll(
"input[name], select[name], textarea[name]",
);
// Além dos campos do formulário, preciso salvar o payload da consulta de viabilidade
data["viabilidade"] = dataPayload;
fields.forEach(function (field) {
const name = field.name;
if (!name) return;
if (field.type === "checkbox") {
if (!data[name]) data[name] = [];
if (field.checked) data[name].push(field.value);
} else if (field.type === "radio") {
if (field.checked) {
data[name] = field.value;
}
} else {
data[name] = field.value;
}
});
sessionStorage.setItem("formcraft_step1", JSON.stringify(data));
});
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", initFormCache);
} else {
initFormCache();
}
})();
// Função para consultar viabilidade ao clicar no botão
document.addEventListener("click", function (e) {
const btn = e.target.closest("#consulta-viabilidade");
const boxResultado = document.querySelector(".form-element-field23");
if (!btn) return;
e.preventDefault();
if (isProcessing) return;
isProcessing = true;
originalBtnText = btn.textContent;
btn.textContent = "Processando...";
btn.disabled = true;
consultarCep().finally(() => {
showResultField();
smoothScrollToElement(boxResultado, 150, 500);
setTimeout(() => {
isProcessing = false;
btn.textContent = originalBtnText;
btn.disabled = false;
}, 2000);
});
});
// FUNÇÃO BOTÃO CONSULTAR VIABILIDADE
function showResultField() {
console.log("Mostrando resultado de viabilidade.", {
temosBandaLarga,
error,
});
const temosBandaLargaTitle = document.querySelector(".form-element-field23");
const temosBandaLargaBox = document.querySelector(".form-element-field24");
const naoTemosBandaLargaTitle = document.querySelector(
".form-element-field33",
);
const errorBox = document.querySelector(".form-element-field32");
const camposNaoPreenchidos = document.querySelector(".form-element-field36");
// 1) some com todos os blocos
if (temosBandaLargaTitle) temosBandaLargaTitle.style.display = "none";
if (temosBandaLargaBox) temosBandaLargaBox.style.display = "none";
if (naoTemosBandaLargaTitle) naoTemosBandaLargaTitle.style.display = "none";
if (errorBox) errorBox.style.display = "none";
if (camposNaoPreenchidos) camposNaoPreenchidos.style.display = "none";
// 2) se campos não estiverem preenchidos, trata como erro
if (!pronto()) {
if (camposNaoPreenchidos) camposNaoPreenchidos.style.display = "block";
return;
}
// 3) erro de API / outro erro
if (error) {
if (errorBox) errorBox.style.display = "block";
return;
}
// 4) temos / não temos banda
if (temosBandaLarga) {
// TEMOS banda larga
if (temosBandaLargaTitle) temosBandaLargaTitle.style.display = "block";
if (temosBandaLargaBox) temosBandaLargaBox.style.display = "block";
} else {
// NÃO TEMOS banda larga
if (naoTemosBandaLargaTitle)
naoTemosBandaLargaTitle.style.display = "block";
}
}
function setPlanoSelecionadoTexto(planoLabel) {
const el = document.getElementById('plano-selecionado-msg');
if (!el) {
console.warn('[plano] #plano-selecionado-msg não encontrado');
return;
}
el.textContent = `Você selecionou o plano de: ${planoLabel}`;
}
function planoValueToLabel(value) {
const map = {
"100-mega": "100 Mega",
"200-mega": "200 Mega",
"500-mega": "500 Mega",
"700-mega": "700 Mega",
"1-gb": "1 Giga",
};
return map[value] || value;
}
// função genérica para selecionar o tipo de plano no FIELD30
function selecionarTipoPlano(tipo) {
// procura o input do FormCraft pelo name e pelo value
const input = document.querySelector(
'input[name="field30[]"][value="' + tipo + '"]',
);
if (!input) {
console.warn('Campo field30 com value="' + tipo + '" não encontrado');
return;
}
// marca o radio/checkbox
input.checked = true;
// dispara o evento "change" para o FormCraft reagir (lógica condicional, etc.)
const evt = new Event("change", { bubbles: true });
input.dispatchEvent(evt);
}
function selecionarPlano(plano) {
const input = document.querySelector(
'input[name="field31[]"][value="' + plano + '"]',
);
console.log("[plano] procurando field31", plano, "→", input);
if (!input) {
console.warn(
'[plano] Campo field31 com value="' + plano + '" não encontrado',
);
return;
}
input.checked = true;
const evt = new Event("change", { bubbles: true });
input.dispatchEvent(evt);
setPlanoSelecionadoTexto(planoValueToLabel(plano));
console.log("[plano] marcado e disparado change");
}
// listeners dos botões dos cards
document.addEventListener("click", function (e) {
// botão plano residência
const btnResidencia = e.target.closest("#btn-plano-residencia");
if (btnResidencia) {
e.preventDefault();
selecionarTipoPlano("plano-residencia");
document.querySelectorAll(".seller-card__container").forEach((card) => {
card.classList.remove("is-selected");
});
const card = btnResidencia.closest(".seller-card__container");
if (card) card.classList.add("is-selected");
scrollToPlanosById("planos-residencial", 220, 500);
return;
}
// botão plano empresa
const btnEmpresa = e.target.closest("#btn-plano-empresa");
if (btnEmpresa) {
e.preventDefault();
selecionarTipoPlano("plano-empresa");
document.querySelectorAll(".seller-card__container").forEach((card) => {
card.classList.remove("is-selected");
});
const card = btnEmpresa.closest(".seller-card__container");
if (card) card.classList.add("is-selected");
scrollToPlanosById("planos-empresa", 220, 500);
return;
}
const btnPlano100Mega = e.target.closest("#btn-plano-100-mega");
if (btnPlano100Mega) {
e.preventDefault();
selecionarPlano("100-mega");
document
.querySelectorAll(".seller-card__container, .out-card__container")
.forEach((el) => {
el.classList.remove("is-selected");
});
const card = btnPlano100Mega.closest(".seller-card__container");
if (card) card.classList.add("is-selected");
scrollToAssinar({ offset: 500, duration: 500 });
return;
}
const btnPlano200Mega = e.target.closest("#btn-plano-200-mega");
if (btnPlano200Mega) {
e.preventDefault();
selecionarPlano("200-mega");
document
.querySelectorAll(".seller-card__container, .out-card__container")
.forEach((el) => {
el.classList.remove("is-selected");
});
const card = btnPlano200Mega.closest(".seller-card__container");
if (card) card.classList.add("is-selected");
scrollToAssinar({ offset: 500, duration: 500 });
return;
}
const btnPlano500Mega = e.target.closest("#btn-plano-500-mega");
if (btnPlano500Mega) {
e.preventDefault();
selecionarPlano("500-mega");
document
.querySelectorAll(".seller-card__container, .out-card__container")
.forEach((el) => {
el.classList.remove("is-selected");
});
const card = btnPlano500Mega.closest(".out-card__container");
if (card) card.classList.add("is-selected");
scrollToAssinar({ offset: 500, duration: 500 });
return;
}
const btnPlano700Mega = e.target.closest("#btn-plano-700-mega");
if (btnPlano700Mega) {
e.preventDefault();
selecionarPlano("700-mega");
document
.querySelectorAll(".seller-card__container, .out-card__container")
.forEach((el) => {
el.classList.remove("is-selected");
});
const card = btnPlano700Mega.closest(".seller-card__container");
if (card) card.classList.add("is-selected");
scrollToAssinar({ offset: 500, duration: 500 });
return;
}
const btnPlano1Gb = e.target.closest("#btn-plano-1-gb");
if (btnPlano1Gb) {
e.preventDefault();
selecionarPlano("1-gb");
document
.querySelectorAll(".seller-card__container, .out-card__container")
.forEach((el) => {
el.classList.remove("is-selected");
});
const card = btnPlano1Gb.closest(".seller-card__container");
if (card) card.classList.add("is-selected");
scrollToAssinar({ offset: 500, duration: 500 });
return;
}
});
class FormCraftCEP {
constructor() {
// Inicializa a classe e define os conjuntos de campos
this.fieldSets = [
{
cepField: document.querySelector('[name="field6[]"]'),
ruaField: document.querySelector('[name="field20[]"]'),
},
];
this.fieldSets.forEach((set, index) => {
this.initializeFields(set, index);
});
}
initializeFields(set, index) {
const missingFields = [];
if (!set.cepField) missingFields.push("CEP");
if (!set.ruaField) missingFields.push("Rua");
if (missingFields.length > 0) {
console.error(
`Erro: Não foi possível localizar os seguintes campos do conjunto ${index + 1}: ${missingFields.join(", ")}`,
);
return;
}
// Adicionar evento ao campo de CEP
set.cepField.addEventListener("input", () => {
const valor = this.getCEPValue(set.cepField);
if (valor.length === 8) {
this.verificaCEP(valor, set);
}
});
}
getCEPValue(cepField) {
const rawValue = cepField.value.trim();
return rawValue.replace(/\D/g, "");
}
limpaFormularioCEP(set) {
set.ruaField.value = "";
}
meuCallback(conteudo, set) {
if (!("erro" in conteudo)) {
set.ruaField.value = conteudo.logradouro || "";
} else {
this.limpaFormularioCEP(set);
alert("CEP não encontrado.");
}
}
verificaCEP(valor, set) {
if (/^[0-9]{8}$/.test(valor)) {
this.pesquisaCEP(valor, set);
} else {
console.warn("CEP inválido:", valor);
}
}
pesquisaCEP(cep, set) {
set.ruaField.value = "...";
let script = document.createElement("script");
script.src = `https://viacep.com.br/ws/${cep}/json/?callback=formCraftCEPInstance.createCallback("${cep}", "${set.cepField.name}")`;
document.body.appendChild(script);
}
createCallback(cep, cepFieldName) {
const set = this.fieldSets.find(
(set) => set.cepField.name === cepFieldName,
);
return function (conteudo) {
formCraftCEPInstance.meuCallback(conteudo, set);
};
}
}
// Criar instância da classe e torná-la global
window.formCraftCEPInstance = new FormCraftCEP();
// Garantir que tela scrolle em caso de campo obrigatório sem preenchimento
(function scrollToFirstInvalidOnSubmit() {
const form = document.querySelector(".fc-form-23");
if (!form) return;
const OFFSET = 180; // ajuste conforme seu header/spacing
function scrollToInvalid() {
// pega o primeiro inválido nativo do HTML5
const invalid =
form.querySelector(":invalid") ||
form.querySelector("[aria-invalid='true']") ||
form.querySelector(".fc-error, .error, .has-error input, .has-error textarea, .has-error select");
if (!invalid) return;
// se for label/div, tenta ir no input dentro
const target = invalid.matches("input, select, textarea")
? invalid
: invalid.querySelector?.("input, select, textarea") || invalid;
// garante foco (ajuda o FormCraft e o usuário)
if (target.focus) target.focus({ preventScroll: true });
// dá um “respiro” pro layout e então rola certinho
requestAnimationFrame(() => {
requestAnimationFrame(() => {
smoothScrollToElement(target, OFFSET, 450);
});
});
}
// captura: roda antes dos handlers internos finalizarem
form.addEventListener(
"submit",
() => {
// espera o FormCraft marcar erros
setTimeout(scrollToInvalid, 50);
setTimeout(scrollToInvalid, 200);
},
true
);
// fallback: se o submit nem dispara, mas o clique foi no submit
form.addEventListener(
"click",
(e) => {
const btn = e.target.closest('button[type="submit"], input[type="submit"]');
if (!btn) return;
setTimeout(scrollToInvalid, 50);
setTimeout(scrollToInvalid, 200);
},
true
);
})();

373
teste/style.css Normal file
View File

@ -0,0 +1,373 @@
.button-viabilidade {
display: flex !important;
justify-content: center !important;
align-items: center !important;
padding: 9px 0px !important;
background-color: #31a3b5 !important;
color: white !important;
font-weight: bold !important;
border: none !important;
border-radius: 20px !important;
}
.button-viabilidade:hover {
background-color: #1d6570 !important;
}
.form-element-field24 {
margin-bottom: 250px;
}
.form-element-field25,
.form-element-field34 {
margin-bottom: 500px;
}
.form-element-field8 {
margin-bottom: 50px;
}
.form-element-field8 button {
padding: 9px 20px !important;
background-color: #31a3b5 !important;
color: white !important;
font-weight: bold !important;
border: none !important;
border-radius: 20px !important;
font-size: 12px !important;
}
.form-element-field32 span, .form-element-field33 span {
color:#dd3333 !important;
}
.banda-larga__container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 45px;
}
.banda-residencia__container, .banda-empresa__container {
display: flex;
flex-direction: column;
align-items: center;
width: 50%;
border: 1px solid gray;
border-radius: 20px;
height: 270px;
}
.banda-card__content {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
padding: 40px;
}
.banda__title > h3 {
margin-top: 0px;
font-size: 18px !important;
color: #234164 !important;
text-align: center;
}
.banda__content > p {
text-align: center;
line-height: 1.5em;
}
.banda-residencia__container > div > div.banda__content > p {
margin-top: 0px;
}
.banda-button__container {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.banda-button__container > a {
padding: 10px !important;
background-color: #31a3b5 !important;
color: white !important;
text-decoration: none !important;
width: 100% !important;
text-align: center !important;
border-radius: 5px !important;
}
.banda-button__container > a:hover {
background-color: #1d6570 !important;
}
.planos__container {
background-color: #dedede !important;
width: 100vw; /* largura da tela, não do form */
margin-left: calc(50% - 50vw); /* puxa pra esquerda até encostar na borda */
margin-right: calc(50% - 50vw); /* opcional, pra compensar do outro lado */
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
align-items: center !important;
padding: 40px 40px 200px 40px!important;
}
.planos-cards__container {
display: flex !important;
justify-content: center !important;
align-items: center !important;
gap: 25px !important;
}
.instalacao__container {
margin-top: 30px !important;
}
.out-card__container {
display: flex !important;
flex-direction: column !important;
transition: transform 0.5s ease;
}
.most-sell-card__text {
align-self: flex-end !important;
background-color: #1d3350 !important;
border-radius: 20px 20px 0px 0px !important;
}
.most-sell-card__text > p {
font-size: 10px !important;
padding: 0px 30px 0px 30px !important;
margin: 0px !important;
color: white !important;
}
.most-sell-card__container {
background-color: #1d3350 !important;
min-width: 230px !important;
height: 450px !important;
border-radius: 20px 0px 20px 20px !important;
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
align-items: center !important;
}
.seller-card__container {
background: radial-gradient(circle at 50% 50%,
#B00025 50%, /* intermediário */
#A70022 100%) !important; /* mais escuro nas bordas */
height: 450px !important;
min-width: 230px !important;
border-radius: 20px !important;
display: flex !important;
justify-content: center !important;
align-items: center !important;
flex-direction: column !important;
margin-top: 30px !important;
color: white !important;
transition: transform 0.5s ease;
}
.best-seller-card__container {
background: radial-gradient(circle at 50% 50%,
#B00025 50%, /* intermediário */
#A70022 100%) !important; /* mais escuro nas bordas */
width: 92% !important;
height: 95% !important;
border-radius: 15px !important;
color: white !important;
display: flex !important;
flex-direction: column !important;
align-items: center !important;
}
.card-title__container {
display: flex !important;
justify-content: center !important;
align-items: flex-end !important;
padding: 20px 0px 15px 0px !important;
font-family: "myriad-variable", sans-serif !important;
border-bottom: 1px solid white !important;
width: 90% !important;
}
.card-title__number > h1 {
padding: 0px !important;
margin: 0px !important;
font-size: 50px !important;
}
.card-title__text > h1 {
padding: 0px !important;
margin: 0px 0px 13px 3px !important;
font-size: 20px !important;
}
.card-description__container {
display: flex !important;
justify-content: center !important;
align-items: center !important;
border-bottom: 1px solid white !important;
width: 90% !important;
margin-top: 25px !important;
padding-bottom: 60px !important;
}
.card-description__content {
margin-left: 5px !important;
margin-bottom: 10px !important;
font-weight: 600 !important;
}
.card-price__container {
display: flex !important;
align-items: flex-end !important;
justify-content: flex-end !important;
margin-top: 20px !important;
}
.card-price__money {
align-self: flex-end !important;
margin-bottom: -5px !important;
}
.card-price__money > p {
height: 100% !important;
color: white !important;
font-weight: bold !important;
font-size: 24px !important;
}
.card-price__value {
align-self: flex-end !important;
}
.card-price__value > p {
height: 100% !important;
font-weight: bold !important;
font-size: 50px !important;
color: white !important;
}
.card-price-small__container {
display: flex !important;
flex-direction: column !important;
justify-content: center !important;
align-self: flex-end !important;
margin-bottom: -10px !important;
margin-left: 2.5px !important;
}
.small-price p {
height: 100% !important;
color: white !important;
font-weight: bold !important;
font-size: 24px !important;
}
.small-gap-time p {
height: 100% !important;
color: white !important;
font-size: 14px !important;
}
.card-plan-button__container {
margin-top: 30px !important;
width: 100% !important;
display: flex !important;
justify-content: center !important;
align-items: center !important;
}
.card-plan-button__container > a {
color: #A70022 !important;
text-decoration: none !important;
font-weight: bold !important;
font-size: 12px !important;
background-color: white !important;
padding: 8px 40px !important;
border-radius: 10px !important;
}
.card-plan-button__container > a:hover {
box-shadow: rgba(0, 0, 0, 0.35) 0px 5px 15px !important;
}
.most-sell-card__container > div > div.card-title__container {
margin-top: 25px !important;
}
.card-price__container div > p {
margin: 0px !important;
}
html .formcraft-css .fc-form .form-element .field-cover.customText-cover .small-gap-time > p, html .formcraft-css .fc-form .form-element .field-cover.customText-cover .small-price > p {
margin-top: 0 !important;
}
.is-selected {
transform: translateY(-15px);
}
.formcraft-icon {
margin-top: 2.5px !important;
}
.form-element-field22 p {
font-size: 12px !important;
}
#plano-selecionado-msg {
font-weight: bold !important;
text-align: center !important;
font-size: 20px !important
}
@media (max-width: 480px) {
.form-element-field22 {
margin-bottom: 25px;
}
.form-element-field33 {
margin-top: 40px;
}
.form-element-field24 {
margin-bottom: 630px;
}
.banda-larga__container {
flex-direction: column;
}
.banda-residencia__container,
.banda-empresa__container {
width: 100%;
height: fit-content;
}
.planos-cards__container {
flex-direction: column;
}
.form-element-field25,
.form-element-field34 {
margin-bottom: 2600px;
}
.instalacao__container > p {
text-align: center;
}
}