feat(home): prova no topo, contato sem atrito e conversão medida
Home mais curta (hero, vitrine de clientes, sobre, serviços, IA resumida, depoimentos e contato), faixa de clientes e telas reais no hero, sem números do GitHub. Barra de cookies fina, WhatsApp fixo no celular, formulário com e-mail opcional e alternativa por e-mail, página /ia, eventos de e-mail, redes e currículo e conversão do Ads opcional por variável. Rodapé em 3 colunas. Remove componentes órfãos (LighthouseMetrics, Skills, Experience, contagem do GitHub).
This commit is contained in:
1 parent
6e1022b58c
commit
8d07b8c6bb
60 files changed
+4392
-2124
No files matched your search
@@ -0,0 +1,166 @@
|
||||
import {
|
||||
GA_DISABLE_KEY,
|
||||
OPEN_COOKIE_PREFERENCES_EVENT,
|
||||
openCookiePreferences,
|
||||
trackCvDownload,
|
||||
trackEmailClick,
|
||||
trackSocialClick,
|
||||
trackWhatsAppOpen,
|
||||
} from "./analytics";
|
||||
|
||||
const CONSENT_KEY = "evandro.analytics-consent.v1";
|
||||
const ADS_LABEL = "NEXT_PUBLIC_GOOGLE_ADS_CONVERSION_LABEL";
|
||||
|
||||
const common = {
|
||||
send_to: "G-QTT9QT0T3S",
|
||||
page_path: "/",
|
||||
page_location: "https://evandro.dev.br/",
|
||||
page_referrer: "",
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
jest.replaceProperty(process.env, "NODE_ENV", "production");
|
||||
localStorage.setItem(CONSENT_KEY, "granted");
|
||||
delete window[GA_DISABLE_KEY];
|
||||
window.gtag = jest.fn();
|
||||
window.history.replaceState({}, "", "/");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
localStorage.clear();
|
||||
delete window.gtag;
|
||||
delete process.env[ADS_LABEL];
|
||||
});
|
||||
|
||||
describe("events", () => {
|
||||
it("sends email_click, social_click and cv_download with static labels only", () => {
|
||||
trackEmailClick({ placement: "footer" });
|
||||
trackSocialClick({ network: "linkedin" });
|
||||
trackCvDownload({ placement: "curriculo" });
|
||||
|
||||
expect(window.gtag).toHaveBeenNthCalledWith(1, "event", "email_click", {
|
||||
...common,
|
||||
placement: "footer",
|
||||
});
|
||||
expect(window.gtag).toHaveBeenNthCalledWith(2, "event", "social_click", {
|
||||
...common,
|
||||
network: "linkedin",
|
||||
});
|
||||
expect(window.gtag).toHaveBeenNthCalledWith(3, "event", "cv_download", {
|
||||
...common,
|
||||
placement: "curriculo",
|
||||
});
|
||||
expect(window.gtag).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it("reports the floating button as a whatsapp_open placement", () => {
|
||||
trackWhatsAppOpen({ service: "Contato", placement: "floating" });
|
||||
|
||||
expect(window.gtag).toHaveBeenCalledWith("event", "whatsapp_open", {
|
||||
...common,
|
||||
service: "Contato",
|
||||
placement: "floating",
|
||||
});
|
||||
});
|
||||
|
||||
it("knows the /ia page instead of lumping it into /other", () => {
|
||||
window.history.replaceState({}, "", "/ia?x=1#y");
|
||||
trackEmailClick({ placement: "ia" });
|
||||
|
||||
expect(window.gtag).toHaveBeenCalledWith(
|
||||
"event",
|
||||
"email_click",
|
||||
expect.objectContaining({
|
||||
page_path: "/ia",
|
||||
page_location: "https://evandro.dev.br/ia",
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
["without consent", () => localStorage.removeItem(CONSENT_KEY)],
|
||||
["after refusal", () => localStorage.setItem(CONSENT_KEY, "denied")],
|
||||
[
|
||||
"when GA is disabled",
|
||||
() => Object.assign(window, { [GA_DISABLE_KEY]: true }),
|
||||
],
|
||||
["when gtag is missing", () => delete window.gtag],
|
||||
])("sends nothing %s", (_label, arrange) => {
|
||||
process.env[ADS_LABEL] = "abc123";
|
||||
const gtag = window.gtag as jest.Mock;
|
||||
arrange();
|
||||
|
||||
trackWhatsAppOpen({ service: "Contato", placement: "floating" });
|
||||
trackEmailClick({ placement: "footer" });
|
||||
trackSocialClick({ network: "linkedin" });
|
||||
trackCvDownload({ placement: "curriculo" });
|
||||
|
||||
expect(gtag).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sends nothing outside production", () => {
|
||||
jest.replaceProperty(process.env, "NODE_ENV", "development");
|
||||
trackEmailClick({ placement: "footer" });
|
||||
expect(window.gtag).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("never throws when gtag fails", () => {
|
||||
window.gtag = jest.fn(() => {
|
||||
throw new Error("blocked");
|
||||
});
|
||||
expect(() => trackEmailClick({ placement: "footer" })).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Google Ads conversion", () => {
|
||||
it("is not sent without the conversion label", () => {
|
||||
trackWhatsAppOpen({ service: "Contato", placement: "floating" });
|
||||
trackEmailClick({ placement: "footer" });
|
||||
|
||||
expect(window.gtag).toHaveBeenCalledTimes(2);
|
||||
for (const [, name] of (window.gtag as jest.Mock).mock.calls) {
|
||||
expect(name).not.toBe("conversion");
|
||||
}
|
||||
});
|
||||
|
||||
it("goes out next to whatsapp_open and email_click when the label exists", () => {
|
||||
process.env[ADS_LABEL] = "abc123";
|
||||
|
||||
trackWhatsAppOpen({ service: "Contato", placement: "floating" });
|
||||
trackEmailClick({ placement: "footer" });
|
||||
|
||||
const calls = (window.gtag as jest.Mock).mock.calls;
|
||||
expect(calls.map(([, name]) => name)).toEqual([
|
||||
"whatsapp_open",
|
||||
"conversion",
|
||||
"email_click",
|
||||
"conversion",
|
||||
]);
|
||||
expect(calls[1]).toEqual([
|
||||
"event",
|
||||
"conversion",
|
||||
{ send_to: "AW-18432694647/abc123" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not turn social clicks or CV downloads into Ads conversions", () => {
|
||||
process.env[ADS_LABEL] = "abc123";
|
||||
|
||||
trackSocialClick({ network: "linkedin" });
|
||||
trackCvDownload({ placement: "curriculo" });
|
||||
|
||||
expect(window.gtag).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("cookie preferences", () => {
|
||||
it("asks the consent bar to reopen through a window event", () => {
|
||||
const listener = jest.fn();
|
||||
window.addEventListener(OPEN_COOKIE_PREFERENCES_EVENT, listener);
|
||||
openCookiePreferences();
|
||||
window.removeEventListener(OPEN_COOKIE_PREFERENCES_EVENT, listener);
|
||||
|
||||
expect(listener).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user