/* artsol-calc.jsx — simuladores de economia Brasília · Neoenergia · estimativas conservadoras Dois cartões: Calculator (fotovoltaica) e CalculatorBanho (aquecimento de banho). Compartilham LeadForm, submitLead, buildWhatsAppURL e todo o CSS .calc*. */ const { useState, useMemo } = React; const TARIFF = 0.90; // R$/kWh residencial B1 Brasília (DF) const GEN_PER_KWP = 135; // kWh/kWp · mês (irradiação ~5.4 kWh/m²·dia) const COST_PER_KWP = 4500; // R$/kWp turn-key residencial /* aquecimento de banho */ const SHOWER_KW = 5.5; // chuveiro elétrico 220V comum, posição inverno const SOLAR_FRACTION = 0.85; // fração do ano coberta pelo sol em Brasília const BOILER_LOSS = 1.2; // boiler elétrico perde calor no reservatório const L_PER_PERSON = 90; // L/dia por pessoa — mesma base da tabela de especificações const L_PER_COLLECTOR = 170; // L de boiler por coletor const BOILER_SIZES = [200, 300, 400, 500, 600, 800, 1000]; const SHEETS_WEBHOOK = "https://script.google.com/macros/s/AKfycbxNKk-gZML7SNWjm9TCizMPVS63H-A730ifEb401F_xDYy1Lb3oomrHh-UHngWfaFn1pg/exec"; // colar aqui a URL do Apps Script após deploy function fmtBRL(n, opts = {}) { return n.toLocaleString("pt-BR", { style: "currency", currency: "BRL", maximumFractionDigits: opts.dec ?? 0, }); } function fmtN(n, dec = 1) { return n.toLocaleString("pt-BR", { maximumFractionDigits: dec, minimumFractionDigits: dec }); } function maskPhone(v) { const d = v.replace(/\D/g, "").slice(0, 11); if (d.length <= 2) return d.replace(/^(\d{0,2})/, "($1"); if (d.length <= 7) return d.replace(/^(\d{2})(\d{0,5})/, "($1) $2"); return d.replace(/^(\d{2})(\d{5})(\d{0,4})/, "($1) $2-$3"); } const WA_PHONE = "556133271000"; // ARTSOL WhatsApp const TYPE_LABEL = { casa: "Casa", apto: "Apartamento", comercio: "Comércio" }; const BANHO_TIPO_LABEL = { chuveiro: "Chuveiro elétrico", boiler: "Boiler elétrico" }; /* ── compartilhado pelos dois simuladores ────────────────────────────── */ /* cada simulador monta as próprias linhas de situacao/resumo — aqui só junta */ function buildWhatsAppURL({ solucao, situacao, resumo, lead, intent }) { const lines = [ intent === "proposta" ? `Olá ARTSOL! Quero receber uma proposta detalhada de ${solucao}:` : `Olá ARTSOL! Acabei de usar o simulador de ${solucao} no site e gostaria de falar com um especialista.`, "", ...(lead ? [ "— Meus dados —", `• Nome: ${lead.nome}`, `• E-mail: ${lead.email}`, `• WhatsApp: ${lead.whatsapp}`, "", ] : []), "— Minha situação —", ...situacao, "", "— Estimativa do simulador —", ...resumo, "", "Podem me ajudar com os próximos passos?", ]; return `https://api.whatsapp.com/send?phone=${WA_PHONE}&text=${encodeURIComponent(lines.join("\n"))}`; } /* gtag + Sheets + WhatsApp. O no-cors é fire-and-forget: não dá pra ler a resposta do Apps Script, então falha de rede não pode travar o lead. */ function submitLead({ lead, payload, wa, gtagParams }) { if (typeof gtag === "function") gtag("event", "generate_lead", gtagParams); if (SHEETS_WEBHOOK) { fetch(SHEETS_WEBHOOK, { method: "POST", mode: "no-cors", headers: { "Content-Type": "text/plain" }, body: JSON.stringify({ timestamp: new Date().toISOString(), ...lead, ...payload }), }).catch(() => {}); } window.open(wa, "_blank"); } function LeadForm({ onSubmit, onCancel }) { const [d, setD] = useState({ nome: "", email: "", whatsapp: "" }); const [err, setErr] = useState({}); function handle(e) { e.preventDefault(); const errors = { nome: !d.nome.trim(), email: !/\S+@\S+\.\S+/.test(d.email), whatsapp: d.whatsapp.replace(/\D/g, "").length < 10, }; setErr(errors); if (Object.values(errors).some(Boolean)) return; onSubmit(d); setD({ nome: "", email: "", whatsapp: "" }); setErr({}); } return (

Onde enviamos a proposta?

setD((p) => ({ ...p, nome: e.target.value }))} autoFocus /> {err.nome && Informe seu nome}
setD((p) => ({ ...p, email: e.target.value }))} /> {err.email && E-mail inválido}
setD((p) => ({ ...p, whatsapp: maskPhone(e.target.value) }))} /> {err.whatsapp && Número inválido}
); } /* ── FOTOVOLTAICA ────────────────────────────────────────────────────── */ function Calculator({ onSubmit }) { const [bill, setBill] = useState(620); const [type, setType] = useState("casa"); const [people, setPeople] = useState(4); const [leadStep, setLeadStep] = useState(false); const out = useMemo(() => { const monthlyKWh = bill / TARIFF; let coverage = 0.93; if (type === "apto") coverage = 0.7; if (type === "comercio") coverage = 0.85; const requiredKwp = (monthlyKWh / GEN_PER_KWP) * (coverage + 0.05); const systemCost = requiredKwp * COST_PER_KWP; const annualSavings = bill * 12 * coverage; const payback = annualSavings > 0 ? systemCost / annualSavings : 0; const savings25 = annualSavings * 25; const panels = Math.max(4, Math.ceil(requiredKwp / 0.55)); // ~550W painéis const co2 = monthlyKWh * 12 * 0.0817 / 1000; // tCO2/year approx return { monthlyKWh, requiredKwp, systemCost, annualSavings, payback, savings25, panels, co2, }; }, [bill, type, people]); const wa = (lead, intent) => buildWhatsAppURL({ solucao: "energia solar fotovoltaica", situacao: [ `• Tipo de imóvel: ${TYPE_LABEL[type] || type}`, `• Conta de luz / mês: ${fmtBRL(bill)}`, `• Pessoas em casa: ${people}`, ], resumo: [ `• Sistema sugerido: ${fmtN(out.requiredKwp, 1)} kWp (${out.panels} painéis)`, `• Economia estimada / ano: ${fmtBRL(out.annualSavings)}`, `• Tempo de retorno: ${fmtN(out.payback, 1)} anos`, `• Economia em 25 anos: ${fmtBRL(out.savings25)}`, ], lead, intent, }); function handleLead(lead) { submitLead({ lead, payload: { solucao: "fotovoltaica", conta_mes: bill, tipo: type, pessoas: people, sistema_kwp: fmtN(out.requiredKwp, 1), paineis: out.panels, economia_ano: Math.round(out.annualSavings), payback: fmtN(out.payback, 1), economia_25a: Math.round(out.savings25), }, wa: wa(lead, "proposta"), gtagParams: { method: "proposta_form", bill, property_type: type }, }); onSubmit?.(out); setLeadStep(false); } return (

Simulador de economia

ao vivo
Sua conta de luz / mês {fmtBRL(bill)}
setBill(+e.target.value)} aria-label="Conta de luz mensal" />
R$ 150 R$ 3.000
Tipo de imóvel
{[ ["casa", "Casa"], ["apto", "Apartamento"], ["comercio", "Comércio"], ].map(([k, l]) => ( ))}
Pessoas em casa {people}
{people}
Economia / ano
{fmtBRL(out.annualSavings)}
Tempo de retorno
{fmtN(out.payback, 1)} anos
Em 25 anos de operação
você economiza
{fmtBRL(out.savings25)}
Sistema sugerido {fmtN(out.requiredKwp, 1)} kWp · {out.panels} painéis
{!leadStep ? ( ) : ( setLeadStep(false)} /> )} { if (typeof gtag === "function") gtag("event", "generate_lead", { method: "especialista", bill, property_type: type }); }} > Falar com especialista no WhatsApp
Estimativa conservadora · sem compromisso · proposta personalizada após vistoria
); } /* ── AQUECIMENTO DE BANHO ────────────────────────────────────────────── */ /* pura de propósito: dá pra checar sem montar React (ver __testCalcBanho) */ function calcBanho({ pessoas, minutos, tipo }) { const perda = tipo === "boiler" ? BOILER_LOSS : 1; const kwhMes = SHOWER_KW * (minutos / 60) * pessoas * 30 * perda; const custoMes = kwhMes * TARIFF; const economiaMes = custoMes * SOLAR_FRACTION; // sobe pra próxima faixa comercial de boiler; acima de 1000 L é projeto sob medida const bruto = pessoas * L_PER_PERSON; const litros = BOILER_SIZES.find((v) => v >= bruto) || BOILER_SIZES[BOILER_SIZES.length - 1]; return { kwhMes, custoMes, custoAno: custoMes * 12, economiaMes, economiaAno: economiaMes * 12, economia10a: economiaMes * 12 * 10, litros, sobMedida: bruto > BOILER_SIZES[BOILER_SIZES.length - 1], coletores: Math.ceil(litros / L_PER_COLLECTOR), }; } function CalculatorBanho({ onSubmit }) { const [minutos, setMinutos] = useState(10); const [tipo, setTipo] = useState("chuveiro"); const [pessoas, setPessoas] = useState(4); const [leadStep, setLeadStep] = useState(false); const out = useMemo(() => calcBanho({ pessoas, minutos, tipo }), [pessoas, minutos, tipo]); const wa = (lead, intent) => buildWhatsAppURL({ solucao: "aquecimento solar para banho", situacao: [ `• Aquecimento hoje: ${BANHO_TIPO_LABEL[tipo] || tipo}`, `• Pessoas em casa: ${pessoas}`, `• Tempo de banho por pessoa: ${minutos} min/dia`, ], resumo: [ `• Gasto atual com banho: ${fmtBRL(out.custoMes)}/mês (${fmtN(out.kwhMes, 0)} kWh)`, `• Economia estimada / ano: ${fmtBRL(out.economiaAno)}`, `• Economia em 10 anos: ${fmtBRL(out.economia10a)}`, `• Sistema sugerido: ${out.coletores} coletores · boiler ${out.litros} L${out.sobMedida ? " (ou projeto sob medida)" : ""}`, ], lead, intent, }); function handleLead(lead) { submitLead({ lead, payload: { solucao: "aquecimento-banho", tipo, pessoas, minutos_banho: minutos, gasto_mes: Math.round(out.custoMes), economia_ano: Math.round(out.economiaAno), boiler_litros: out.litros, coletores: out.coletores, }, wa: wa(lead, "proposta"), gtagParams: { method: "proposta_form_banho", people: pessoas, heating_type: tipo }, }); onSubmit?.(out); setLeadStep(false); } return (

Quanto seu chuveiro custa

ao vivo
Tempo de banho por pessoa / dia {minutos} min
setMinutos(+e.target.value)} aria-label="Tempo de banho por pessoa por dia, em minutos" />
5 min 30 min
Aquecimento hoje
{[ ["chuveiro", "Chuveiro elétrico"], ["boiler", "Boiler elétrico"], ].map(([k, l]) => ( ))}
Pessoas em casa {pessoas}
{pessoas}
Economia / ano
{fmtBRL(out.economiaAno)}
Consumo evitado
{fmtN(out.kwhMes, 0)} kWh/mês
Em 10 anos de operação
você economiza
{fmtBRL(out.economia10a)}
Sistema sugerido {out.coletores} coletores · boiler {out.litros} L
{!leadStep ? ( ) : ( setLeadStep(false)} /> )} { if (typeof gtag === "function") gtag("event", "generate_lead", { method: "especialista_banho", people: pessoas, heating_type: tipo }); }} > Falar com especialista no WhatsApp
Base: chuveiro de 5.500 W · sol cobre ~85% do ano em Brasília · resistência de apoio nos dias frios. Preço sob medida após vistoria.
); } /* self-check da conta do banho — rodar no console: __testCalcBanho() */ function __testCalcBanho() { const ok = (c, m) => { if (!c) throw new Error("calcBanho: " + m); }; const a = calcBanho({ pessoas: 4, minutos: 10, tipo: "chuveiro" }); ok(Math.round(a.kwhMes) === 110, `4p/10min = 110 kWh, veio ${a.kwhMes}`); ok(Math.round(a.custoMes) === 99, `4p/10min = R$99/mês, veio ${a.custoMes}`); ok(a.litros === 400 && a.coletores === 3, `4p = boiler 400L/3 coletores, veio ${a.litros}/${a.coletores}`); const b = calcBanho({ pessoas: 4, minutos: 10, tipo: "boiler" }); ok(Math.round(b.kwhMes / a.kwhMes * 100) === 120, "boiler elétrico deve consumir 20% mais"); ok(calcBanho({ pessoas: 6, minutos: 10, tipo: "chuveiro" }).litros === 600, "6p = boiler 600L"); const t = calcBanho({ pessoas: 12, minutos: 10, tipo: "chuveiro" }); ok(t.litros === 1000 && t.coletores === 6 && t.sobMedida, "12p = teto 1000L/6 coletores + sob medida"); ok(calcBanho({ pessoas: 1, minutos: 10, tipo: "chuveiro" }).litros === 200, "1p = boiler mínimo 200L"); // economia nunca pode passar do gasto atual ok(a.economiaAno < a.custoAno, "economia não pode exceder o gasto atual"); return "calcBanho ok"; } Object.assign(window, { Calculator, CalculatorBanho, calcBanho, fmtBRL, fmtN, __testCalcBanho });