Tutorial – Crie uma Lista de Clientes com Botão para WhatsApp
Neste tutorial passo a passo, você aprenderá a transformar uma simples Planilha Google em um aplicativo de contatos funcional e interativo.
Vamos construir juntos uma página web que lê dinamicamente sua lista de clientes e, para cada um deles, adiciona um botão inteligente que inicia uma conversa no WhatsApp com um único clique. É a ferramenta ideal para agilizar seu contato com clientes e leads.
✅ Como estruturar uma planilha para servir como um banco de dados de contatos.
✅ A ler e processar dados da sua planilha usando Google Apps Script.
✅ Como construir uma interface web que se atualiza automaticamente a partir dos dados da planilha.
✅ A lógica para integrar um botão funcional que abre conversas no WhatsApp.
// =================================================================
// CONSTANTES GLOBAIS
// =================================================================
// Defina aqui o nome exato da aba que contém seus dados.
const NOME_DA_ABA = 'Clientes';
// =================================================================
// FUNÇÃO PRINCIPAL
// =================================================================
/**
* Função principal que é executada quando acessamos o link do nosso App.
* Ela serve a nossa página HTML.
*/
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('Index')
.setTitle('Lista de Contatos')
.addMetaTag('viewport', 'width=device-width, initial-scale=1'); // Essencial para mobile
}
// =================================================================
// FUNÇÕES PÚBLICAS (Expostas ao Front-end)
// =================================================================
/**
* Busca, processa e retorna a lista de clientes da planilha.
* @returns {Array<Object>} Uma lista de objetos, onde cada objeto representa um cliente.
*/
function getClientes() {
try {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(NOME_DA_ABA);
// Pega todos os dados da planilha, exceto a primeira linha (cabeçalho).
const data = sheet.getDataRange().getValues().slice(1);
const clientes = data.map(row => {
// Ignora linhas completamente vazias
if (row.join("").trim() === "") return null;
const telefoneOriginal = row[2]; // Coluna C
// Limpa o número de telefone, removendo tudo que não for dígito.
const telefoneLimpo = String(telefoneOriginal).replace(/\D/g, '');
return {
id: row[0], // Coluna A
nome: row[1], // Coluna B
telefone: telefoneOriginal,
status: row[3], // Coluna D
// Monta o link do WhatsApp, assumindo código de país 55 (Brasil).
// Se o número já tiver 55, não adiciona novamente.
whatsappLink: `https://wa.me/${telefoneLimpo.startsWith('55') ? telefoneLimpo : '55' + telefoneLimpo}`
};
}).filter(cliente => cliente !== null && cliente.status === 'Ativo'); // Filtra nulos e clientes inativos
return clientes;
} catch (e) {
Logger.log(e);
// Lança um erro que pode ser capturado pelo .withFailureHandler no front-end
throw new Error('Não foi possível buscar os clientes. Verifique o nome da aba e a estrutura da planilha.');
}
} <!DOCTYPE html>
<html>
<head>
<base target="_top">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
/* ----- VARIÁVEIS DE CORES E ESTILOS GLOBAIS ----- */
:root {
--cor-fundo: #f0f2f5;
--cor-container: #ffffff;
--cor-texto-principal: #333;
--cor-texto-secundario: #666;
--cor-borda: #e0e0e0;
--cor-sombra: rgba(0, 0, 0, 0.08);
--cor-whatsapp: #25D366;
--cor-whatsapp-hover: #128C7E;
--cor-busca-fundo: #f8f9fa;
}
/* ----- ESTILOS BASE ----- */
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: var(--cor-fundo);
margin: 0;
padding: 20px;
color: var(--cor-texto-principal);
}
/* ----- CONTAINER PRINCIPAL ----- */
.container {
max-width: 700px;
margin: 0 auto;
background-color: var(--cor-container);
border-radius: 12px;
box-shadow: 0 4px 12px var(--cor-sombra);
overflow: hidden;
}
/* ----- CABEÇALHO ----- */
header {
padding: 20px;
border-bottom: 1px solid var(--cor-borda);
}
h1 {
margin: 0;
font-size: 24px;
text-align: center;
}
/* ----- LISTA DE CLIENTES ----- */
main {
padding: 10px 20px 20px 20px;
}
#client-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.client-card {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
border: 1px solid var(--cor-borda);
border-radius: 8px;
transition: background-color 0.2s ease-in-out;
}
.client-card:hover {
background-color: #f9f9f9;
}
.client-name {
font-size: 18px;
font-weight: 500;
}
/* ----- BOTÃO WHATSAPP ----- */
.whatsapp-btn {
display: inline-flex;
align-items: center;
gap: 8px;
background-color: var(--cor-whatsapp);
color: white;
text-decoration: none;
padding: 8px 15px;
border-radius: 20px;
font-weight: bold;
font-size: 14px;
transition: background-color 0.2s ease-in-out;
white-space: nowrap; /* Impede que o texto quebre linha */
}
.whatsapp-btn:hover {
background-color: var(--cor-whatsapp-hover);
}
/* SVG do Ícone do WhatsApp */
.whatsapp-btn svg {
width: 18px;
height: 18px;
fill: currentColor;
}
/* ----- MENSAGENS DE ESTADO ----- */
.status-message {
text-align: center;
padding: 40px 20px;
color: var(--cor-texto-secundario);
font-size: 16px;
}
</style>
</head>
<body>
<div class="container">
<header>
<h1>Lista de Clientes</h1>
</header>
<main>
<div id="client-list">
<!-- Cards dos clientes serão inseridos aqui pelo JavaScript -->
<p id="status-message" class="status-message">Carregando contatos...</p>
</div>
</main>
</div>
<script>
// Variável global para armazenar todos os clientes após o carregamento inicial.
let allClients = [];
// Ícone do WhatsApp em formato SVG para ser usado no botão.
const whatsappIcon = `<svg viewBox="0 0 448 512"><path d="M380.9 97.1C339 55.1 283.2 32 223.9 32c-122.4 0-222 99.6-222 222 0 39.1 10.2 77.3 29.6 111L0 480l117.7-30.9c32.4 17.7 68.9 27 106.1 27h.1c122.3 0 224.1-99.6 224.1-222 0-59.3-25.2-115-67.1-157zM223.9 439.6c-38.2 0-73.7-11.8-103.6-32.5L100 417.8l-74.4 19.6 19.9-72.6-21.6-35.2c-19.4-31.6-30.1-68.2-30.1-106.3 0-110.7 90.3-201 201-201 53.1 0 102.7 20.7 141.4 59.4s59.4 88.3 59.4 141.4-90.3 201-201 201zM362.7 311.1c-3.3-1.6-19.5-9.6-22.5-10.7-3-1.1-5.2-1.6-7.4 1.6-2.2 3.2-8.5 10.7-10.4 12.9-1.9 2.2-3.8 2.5-7.1 1s-14.4-5.3-27.5-17.1c-10.2-9.2-17.1-20.5-19.1-24.1-2-3.6-.2-5.6 1.4-7.4 1.5-1.5 3.3-3.9 5-5.2s2.2-1.6 3.2-3.8c1.1-2.2.5-4.1-.2-5.6- .8-1.6-7.4-17.7-10.1-24.4s-5.5-5.6-7.4-5.7c-1.9-.1-4.1-.1-6.3-.1s-5.2 1.6-7.9 4.2c-2.7 2.6-10.4 10.1-10.4 24.6 0 14.5 10.7 28.5 12.1 30.5 1.4 2 20.9 32 50.7 44.9 7.2 3 12.9 4.9 16.9 6.2 9.3 3.1 17.7 2.6 24.4 1.6 7.4-1.2 22.5-9.2 25.7-18.1 3.1-8.8 3.1-16.3 2.2-18.1c-.9-1.8-3.1-2.9-6.3-4.5z"/></svg>`;
/**
* Função principal que é executada quando a página carrega.
*/
document.addEventListener('DOMContentLoaded', function() {
initializeApp();
document.getElementById('search-input').addEventListener('input', handleSearch);
});
/**
* Chama a função do back-end para buscar os dados dos clientes.
*/
function initializeApp() {
google.script.run
.withSuccessHandler(onDataLoaded)
.withFailureHandler(onDataError)
.getClientes();
}
/**
* Callback executada quando os dados são recebidos com sucesso.
* @param {Array<Object>} clients - A lista de clientes vinda do back-end.
*/
function onDataLoaded(clients) {
allClients = clients;
renderClientList(allClients);
}
/**
* Callback executada em caso de erro na busca de dados.
* @param {Error} error - O objeto de erro.
*/
function onDataError(error) {
const statusMessage = document.getElementById('status-message');
statusMessage.textContent = 'Erro ao carregar os dados: ' + error.message;
}
/**
* Renderiza a lista de clientes na tela.
* @param {Array<Object>} clientsToRender - A lista de clientes a ser exibida.
*/
function renderClientList(clientsToRender) {
const listContainer = document.getElementById('client-list');
listContainer.innerHTML = ''; // Limpa a lista antes de renderizar
if (clientsToRender.length === 0) {
listContainer.innerHTML = '<p class="status-message">Nenhum cliente encontrado.</p>';
return;
}
clientsToRender.forEach(client => {
const cardHTML = `
<div class="client-card">
<span class="client-name">${client.nome}</span>
<a href="${client.whatsappLink}" target="_blank" class="whatsapp-btn">
${whatsappIcon}
<span>Conversar</span>
</a>
</div>
`;
listContainer.innerHTML += cardHTML;
});
}
</script>
</body>
</html> Precisa de uma solução sob medida?
Nós usamos cookies para analisar o tráfego do site e melhorar sua experiência. Ao clicar em 'Aceitar', você concorda com o uso de ferramentas de estatística, conforme detalhado em nossa Política de Privacidade.