Skip to content

Instantly share code, notes, and snippets.

@Santosl2
Created April 14, 2025 15:12
Show Gist options
  • Select an option

  • Save Santosl2/2c0cd8214e68394b07bff85289bfbb43 to your computer and use it in GitHub Desktop.

Select an option

Save Santosl2/2c0cd8214e68394b07bff85289bfbb43 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Formulário de Leads</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap"
rel="stylesheet"
/>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/vue-select@4.0.0-beta.6/dist/vue-select.umd.js"></script>
<link
rel="stylesheet"
href="https://unpkg.com/vue-select@latest/dist/vue-select.css"
/>
<style>
html,
body {
font-family: "Montserrat", sans-serif !important;
}
:root {
--vs-border-radius: 17px;
}
.rounded-custom,
.v-select {
border-radius: 17px;
}
.title-color {
color: #feb702 !important;
}
.loader {
border-top-color: transparent;
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
button {
all: unset;
border: none !important;
}
</style>
</head>
<body
class="bg-[#012030] flex justify-center items-center min-h-screen flex-1 w-full flex-col"
id="app"
>
<section id="section" class="w-full text-center space-y-10 px-5 py-4">
<div class="hidden">
<h1 class="text-4xl font-extrabold text-[#feb702]">
Formulário de Leads
</h1>
<p class="text-white">
Preencha os dados para buscar leads disponíveis
</p>
</div>
<div v-if="loadingInicial" class="text-center text-gray-500">
Carregando...
</div>
<form
v-if="!loadingInicial && !mostrarResultados"
@submit.prevent="buscarLeads"
class="px-6 border rounded-custom py-10 space-y-4 bg-white shadow"
>
<div
class="flex flex-col md:flex-row gap-10 md:items-start w-full mb-10"
>
<div class="form-group flex-1 text-left">
<label
for="estado"
class="block text-left font-semibold mb-2 text-gray-700 text-2xl"
>Estado</label
>
<v-select
v-model="estadoSelecionado"
required
:disabled="todoBrasil"
:options="Object.keys(estados)"
:close-on-select="false"
multiple
:placeholder="todoBrasil ? 'Todo o Brasil' : 'Selecione o(s) estado(s):'"
>
</v-select>
<small
class="text-red-500 font-bold"
v-if="estadoSelecionado.length >= 4"
>* No máximo 3 estados ou Todo o Brasil</small
>
<label class="flex mt-2 items-center space-x-2">
<input
type="checkbox"
v-model="todoBrasil"
@change="limparEstadosCidade"
class="form-checkbox size-3 text-blue-600 rounded-custom focus:ring-0 border-gray-300"
/>
<span class="text-gray-700 text-sm">Selecionar Brasil todo</span>
</label>
</div>
<div class="form-group flex-1 text-left">
<label
for="cidade"
class="block text-left text-2xl font-semibold text-gray-700 mb-2"
>Cidade</label
>
<v-select
v-model="cidadeSelecionada"
required
:disabled="todoBrasil || todosAsCidades"
:close-on-select="false"
multiple
taggable
:placeholder="todosAsCidades ? 'Todos as cidades do(s) Estados' : todoBrasil ? 'Todo o Brasil' : 'Escreva a(s) cidade(s):'"
>
<template #no-options="{ search, searching, loading }">
Escreva o nome da cidade e aperte enter para adicionar
</template>
</v-select>
<small
>Escreva o nome da cidade e aperte enter para adicionar</small
>
<label class="flex mt-2 items-center space-x-2">
<input
type="checkbox"
v-model="todosAsCidades"
@change="limparCidades"
:disabled="todoBrasil"
class="form-checkbox size-3 text-blue-600 rounded focus:ring-0 border-gray-300"
/>
<span class="text-gray-700 text-sm"
>Selecionar Todas as cidades do Estado(s)</span
>
</label>
</div>
</div>
<div class="form-group">
<div class="form-group flex-1 text-left">
<label
for="nichosNovos"
class="block text-left font-semibold mb-2 text-gray-700 text-2xl"
>Nichos</label
>
<v-select
required
:options='[
"Consorcio (Carro, Moto, Imóvel)",
"Plano de Saúde (PJ, PF)",
"FGTS",
"Seguros/Proteção Veicular",
"Direito/Advocacia",
"Empréstimo Consignado",
"Imóveis (Baixo, Médio e Alto Padrão)",
"Produtos e serviços femininos",
"Energia solar",
"B2B/ Empresas",
"Educação/Graduação",
"Clinicas/Consultorios",
"Outros",
]'
v-model="nichosNovosSelecionados"
:close-on-select="false"
multiple
:placeholder="'Selecione o(s) nicho(s):'"
>
</v-select>
<input
v-if="mostrarOutros"
type="text"
v-model="nichoCustomizado"
placeholder="Digite o nicho"
class="mt-2 p-2 border border-gray-300 rounded-custom w-full"
/>
</div>
</div>
<div class="h-5"></div>
<button
type="submit"
:disabled="mostrarOutros && !nichoCustomizado || carregandoLeads || estadoSelecionado.length >= 4 || !todoBrasil && (!estadoSelecionado || !todosAsCidades && !cidadeSelecionada)"
class="w-full bg-[#feb702] max-w-[180px] text-gray-800 font-semibold py-2 px-4 rounded-custom mt-10 justify-center flex items-center border-transparent disabled:opacity-70 m-auto disabled:cursor-not-allowed justify-center space-x-2 border-transparent"
>
<span
v-if="carregandoLeads"
class="loader mr-2 w-4 h-4 border-2 border-t-transparent border-white rounded-custom animate-spin"
></span>
<span>{{ carregandoLeads ? 'Buscando...' : 'Buscar Leads' }}</span>
</button>
</form>
<div v-if="mostrarResultados" class="mt-6">
<h2 class="text-2xl font-extrabold text-left text-[#feb702]">
Leads Disponíveis:
<span class="text-white font-medium"
>{{leadsDisponiveis.toLocaleString('pt-BR')}}</span
>
</h2>
<div class="text-white text-left mt-6">
<strong class="font-bold block text-left">
Estado(s) selecionados:
<span class="font-normal">
<template v-if="!todoBrasil">
{{estadoSelecionado.map(e => estados[e]).join(', ')}}</template
>
<template v-else> Todo o Brasil </template>
</span>
</strong>
<strong class="font-bold block"
>Cidade(s) selecionadas:
<span class="font-normal">
<template v-if="!todoBrasil && !todosAsCidades"
>{{cidadeSelecionada.join(', ')}}</template
>
<template v-if="todoBrasil"> Todo o Brasil </template>
<template v-if="todosAsCidades">
Todo as Cidades do Estado
</template>
</span></strong
>
</div>
<div class="mt-4 space-y-3">
<div
v-for="(produto, index) in produtos"
:key="produto.name"
:class="['p-4 border rounded-custom bg-gray-100 flex justify-between items-center', produto.maisVendido && 'border-green-500']"
>
<div class="text-left">
<div
v-if="produto.maisVendido"
class="block items-center rounded-custom border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 border-transparent bg-green-500 w-max text-white shadow hover:bg-green-500/80"
>
Mais vendido
</div>
<small class="text-gray-600"> {{ produto.name }} </small>
<h2 class="text-xl font-semibold text-left">
{{ String(produto?.quantity)?.replace('{disponiveis}',
leadsDisponiveis.toLocaleString('pt-BR')) }} leads
</h2>
<p class="text-lg">{{ moneyFormat(produto.price) }}</p>
</div>
<div class="flex space-x-2">
<button
@click="comprarProduto(produto)"
:class="['bg-[#feb702] border text-gray-800 rounded-custom py-3 px-4 rounded border-transparent transition-all', produto.maisVendido ? 'bg-green-500 text-white hover:bg-green-500/80' : 'hover:bg-transparent hover:border-[#feb702] ']"
>
Selecionar
</button>
</div>
</div>
</div>
<button
type="button"
@click="resetar"
class="w-full bg-[#feb702] text-gray-700 max-w-[180px] font-semibold py-2 px-4 rounded-custom mt-10 justify-center flex items-center border-transparent disabled:opacity-70 m-auto disabled:cursor-not-allowed justify-center space-x-2 border-transparent"
>
<span>Fazer nova busca</span>
</button>
</div>
</section>
<script type="module">
const { createApp, ref, computed } = Vue;
import { initializeApp } from "https://www.gstatic.com/firebasejs/11.0.1/firebase-app.js";
import {
getFirestore,
collection,
addDoc,
} from "https://www.gstatic.com/firebasejs/11.0.1/firebase-firestore.js";
const firebaseConfig = {
apiKey: "AIzaSyBL7akcVSjWN8qsJwanGy6xtvuwNGBXdwI",
authDomain: "traqueamento-banco-de-dados.firebaseapp.com",
projectId: "traqueamento-banco-de-dados",
storageBucket: "traqueamento-banco-de-dados.firebasestorage.app",
messagingSenderId: "473439299774",
appId: "1:473439299774:web:c0d38499c04b5c582456ef",
};
const firebase = initializeApp(firebaseConfig);
const db = getFirestore(firebase);
const collectionData = collection(db, "formulario-leads");
const urls = {
produto1: "https://pay.kiwify.com.br/QmHq9un",
produto2: "https://pay.kiwify.com.br/HTLhjNS",
produto3: "https://pay.kiwify.com.br/UJ1PoU2",
produto4: "https://pay.kiwify.com.br/3Qt0vAb",
};
const baseProdutos = [
{
name: "Pacote 1",
quantity: 500,
price: 77.9,
url: urls.produto1,
maisVendido: false,
},
{
name: "Pacote 2",
quantity: 1000,
price: 127.9,
url: urls.produto2,
maisVendido: false,
},
{
name: "Pacote 3",
quantity: 1500,
price: 137.9,
url: urls.produto3,
maisVendido: true,
},
];
const produtoCoringa = {
name: "Pacote 3",
quantity: 5000,
price: 347,
url: urls.produto4,
maisVendido: false,
};
const app = createApp({
setup() {
const loadingInicial = ref(true);
const carregandoLeads = ref(false);
const estadoSelecionado = ref("");
const cidadeSelecionada = ref("");
const todoBrasil = ref(false);
const todosAsCidades = ref(false);
const estados = ref({
AC: "Acre",
AL: "Alagoas",
AP: "Amapá",
AM: "Amazonas",
BA: "Bahia",
CE: "Ceará",
DF: "Distrito Federal",
ES: "Espírito Santo",
GO: "Goías",
MA: "Maranhão",
MT: "Mato Grosso",
MS: "Mato Grosso do Sul",
MG: "Minas Gerais",
PA: "Pará",
PB: "Paraíba",
PR: "Paraná",
PE: "Pernambuco",
PI: "Piauí",
RJ: "Rio de Janeiro",
RN: "Rio Grande do Norte",
RS: "Rio Grande do Sul",
RO: "Rondônia",
RR: "Roraíma",
SC: "Santa Catarina",
SP: "São Paulo",
SE: "Sergipe",
TO: "Tocantins",
});
const cidades = ref([]);
const leadsDisponiveis = ref(0);
const mostrarResultados = ref(false);
const nichosNovosSelecionados = ref([]);
const mostrarOutros = computed(() =>
nichosNovosSelecionados.value.includes("Outros")
);
const nichoCustomizado = ref("");
const nichos = [
"Consorcio (Carro, Moto, Imóvel)",
"Plano de Saúde (PJ, PF)",
"FGTS",
"Seguros/Proteção Veicular",
"Direito/Advocacia",
"Empréstimo Consignado",
"Imóveis (Baixo, Médio e Alto Padrão)",
"Produtos e serviços femininos",
"Energia solar",
"B2B/ Empresas",
"Educação/Graduação",
"Clinicas/Consultorios",
"Outros",
];
const produtos = ref([]);
const moneyFormat = (numero) => {
return new Intl.NumberFormat("pt-br", {
style: "currency",
currency: "BRL",
}).format(numero);
};
setTimeout(() => {
loadingInicial.value = false;
}, 1500);
const buscarLeads = (e) => {
carregandoLeads.value = true;
const selectedStateArr = Array.from(estadoSelecionado.value);
const selectedCitiesArr = Array.from(cidadeSelecionada.value);
addDoc(collectionData, {
nichos: Array.from(nichosNovosSelecionados.value),
nichoCustomizado: nichoCustomizado.value,
estadoSelecionado: selectedStateArr,
cidadeSelecionada: selectedCitiesArr,
uid: new Date().getTime(),
criadoEm: new Date(),
});
setTimeout(() => {
const max = Math.min(
estados.value.length || 6,
Math.max(selectedCitiesArr.length, selectedStateArr.length)
);
let customData = [...baseProdutos];
if (todoBrasil.value || todosAsCidades.value) {
customData = [
...customData,
{
...produtoCoringa,
},
];
}
let minLeads = 1667;
let maxLeads = 2420;
// todo o estado
if (todosAsCidades.value) {
minLeads = 6437;
maxLeads = 12349;
}
// todo o brasil
if (todoBrasil.value) {
minLeads = 6437;
maxLeads = 34599;
}
produtos.value = customData;
leadsDisponiveis.value =
Math.floor(Math.random() * (maxLeads - minLeads + 1)) +
minLeads;
mostrarResultados.value = true;
carregandoLeads.value = false;
const allPosForm = document.querySelectorAll("#posform");
allPosForm.forEach((el) => {
el.classList.add("show");
});
}, 7_000);
};
const comprarProduto = (produto) => {
if (produto.url) window.location.href = produto.url;
};
const limparCidades = () => {
cidadeSelecionada.value = "";
};
const limparEstadosCidade = () => {
limparCidades();
estadoSelecionado.value = "";
todosAsCidades.value = false;
};
const resetar = (produto) => {
limparEstadosCidade();
nichosNovosSelecionados.value = [];
mostrarOutros.value = false;
nichoCustomizado.value = "";
mostrarResultados.value = false;
};
return {
loadingInicial,
estadoSelecionado,
cidadeSelecionada,
estados,
cidades,
leadsDisponiveis,
mostrarResultados,
produtos,
carregandoLeads,
nichos,
todoBrasil,
todosAsCidades,
nichosNovosSelecionados,
mostrarOutros,
nichoCustomizado,
moneyFormat,
limparEstadosCidade,
limparCidades,
buscarLeads,
comprarProduto,
resetar,
};
},
});
app.component("v-select", window["vue-select"]);
app.mount("#app");
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment