Files
portifolio-evandrodevbr/app/layout.tsx
T
Evandro Fonseca Junior c9b057b674 feat(analytics): update Google Analytics integration and improve fetch interception
- Refactored Google Analytics proxy routes in the Next.js configuration to enhance fallback handling.
- Improved fetch interception logic in the RootLayout component for more robust handling of Google Analytics requests, including support for `sendBeacon`.
- Updated the analytics script source to align with new API routes for better tracking accuracy.
2026-01-20 21:10:39 -03:00

279 lines
9.6 KiB
TypeScript

import type { Metadata, Viewport } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import Script from "next/script";
// Importação necessária para corrigir o erro de namespace e tipagem do children
import { ReactNode } from "react";
import "./globals.css";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
display: "swap",
adjustFontFallback: true,
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
display: "swap",
adjustFontFallback: true,
});
export const metadata: Metadata = {
title: "Evandro Fonseca Junior - Engenheiro Full-Stack | Next.js, React, Tauri Specialist",
description:
"Engenheiro Full-Stack especializado em Next.js, React, Angular, Node.js e Tauri. Desenvolvedor de sistemas web escaláveis, aplicações desktop e automação. Experiência em PostgreSQL, MySQL, computação em nuvem e IoT.",
keywords: [
"engenheiro full-stack",
"Next.js specialist",
"React developer",
"Tauri developer",
"Angular",
"Node.js",
"TypeScript",
"PostgreSQL",
"MySQL",
"computação em nuvem",
"IoT",
"automação",
"arquitetura de software",
"sistemas escaláveis",
],
authors: [{ name: "Evandro Fonseca Junior" }],
creator: "Evandro Fonseca Junior",
publisher: "Evandro Fonseca Junior",
formatDetection: {
email: false,
address: false,
telephone: false,
},
metadataBase: new URL("https://evandro.dev.br"),
alternates: {
canonical: "/",
},
openGraph: {
title: "Evandro Fonseca Junior - Engenheiro Full-Stack | Next.js, React, Tauri Specialist",
description:
"Engenheiro Full-Stack especializado em Next.js, React, Angular, Node.js e Tauri. Desenvolvedor de sistemas web escaláveis e aplicações desktop.",
url: "https://evandro.dev.br",
siteName: "Evandro Fonseca Junior",
locale: "pt_BR",
type: "website",
images: [
{
url: "/opengraph-image",
width: 1200,
height: 630,
alt: "Evandro Fonseca Junior - Engenheiro Full-Stack | Next.js, React, Tauri Specialist",
},
],
},
twitter: {
card: "summary_large_image",
title: "Evandro Fonseca Junior - Engenheiro Full-Stack | Next.js, React, Tauri Specialist",
description:
"Engenheiro Full-Stack especializado em Next.js, React, Angular, Node.js e Tauri. Desenvolvedor de sistemas web escaláveis e aplicações desktop.",
creator: "@evandrodevbr",
images: ["/opengraph-image"],
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
"max-video-preview": -1,
"max-image-preview": "large",
"max-snippet": -1,
},
},
};
export const viewport: Viewport = {
themeColor: "#000000",
width: "device-width",
initialScale: 1,
maximumScale: 5,
};
// Interface tipada corretamente
interface RootLayoutProps {
children: ReactNode;
}
export default function RootLayout({ children }: Readonly<RootLayoutProps>) {
const jsonLd = {
"@context": "https://schema.org",
"@type": "ProfilePage",
"mainEntity": {
"@type": "Person",
"name": "Evandro Fonseca Junior",
"alternateName": "Evandro.dev",
"jobTitle": "Engenheiro de Software Full-Stack",
"url": "https://evandro.dev.br",
"sameAs": [
"https://github.com/evandrodevbr",
"https://www.linkedin.com/in/evandro-fonseca-junior-0969aa1b0/",
],
"knowsAbout": [
"Software Engineering",
"Next.js",
"React",
"Angular",
"Node.js",
"TypeScript",
"Tauri",
"System Architecture",
"Cloud Computing",
"IoT",
"Automation",
"PostgreSQL",
"MySQL",
],
"worksFor": {
"@type": "Organization",
"name": "Freelancer / Consultor Independente",
},
"description":
"Engenheiro de software especializado em arquitetura web moderna, automação e sistemas de alta performance. Experiência em Next.js, React, Angular, Node.js e desenvolvimento de aplicações desktop com Tauri.",
},
};
return (
<html lang="pt-BR">
<head>
{/* Preconnect to external origins for better performance */}
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossOrigin="anonymous"
/>
<link rel="preconnect" href="https://wa.me" />
<link rel="preconnect" href="https://www.linkedin.com" />
<link rel="preconnect" href="https://github.com" />
{/* DNS prefetch for additional performance */}
<link rel="dns-prefetch" href="//fonts.googleapis.com" />
<link rel="dns-prefetch" href="//fonts.gstatic.com" />
<link rel="dns-prefetch" href="//wa.me" />
<link rel="dns-prefetch" href="//www.linkedin.com" />
<link rel="dns-prefetch" href="//github.com" />
{/* SEO and Crawling */}
<link rel="canonical" href="https://evandro.dev.br" />
{/* Theme color for mobile browsers */}
<meta name="msapplication-TileColor" content="#000000" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta
name="apple-mobile-web-app-status-bar-style"
content="black-translucent"
/>
<meta name="apple-mobile-web-app-title" content="Evandro.dev" />
{/* Performance hints */}
<link rel="preload" href="/edev.jpeg" as="image" />
</head>
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{children}
<Script
src="/analytics/api/script.js"
data-site-id="1"
data-debounce="100"
data-replay-mask-text-selectors='["#user-name", "#user-email", "#user-phone", "input[type=email]", "input[type=tel]", "textarea"]'
data-replay-block-class="rr-block"
data-replay-ignore-class="rr-ignore"
strategy="afterInteractive"
data-session-replay="true"
data-track-errors="true"
/>
{/* Google Analytics - Interceptor para bypass de adblocker */}
<Script
id="google-analytics-proxy-interceptor"
strategy="beforeInteractive"
dangerouslySetInnerHTML={{
__html: `
(function() {
// Interceptar fetch - método mais robusto
const originalFetch = window.fetch;
window.fetch = function(url, options) {
if (typeof url === 'string') {
// Interceptar google-analytics.com/g/collect
if (url.includes('google-analytics.com/g/collect')) {
const urlObj = new URL(url);
url = '/api/metrics' + urlObj.search;
}
// Interceptar outros endpoints do google-analytics.com
else if (url.includes('google-analytics.com')) {
url = url.replace(/https?:\\/\\/[^\\/]*google-analytics\\.com/g, '/api/metrics');
}
}
return originalFetch.call(this, url, options);
};
// Interceptar XMLHttpRequest
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
if (typeof url === 'string') {
if (url.includes('google-analytics.com/g/collect')) {
const urlObj = new URL(url);
url = '/api/metrics' + urlObj.search;
}
else if (url.includes('google-analytics.com')) {
url = url.replace(/https?:\\/\\/[^\\/]*google-analytics\\.com/g, '/api/metrics');
}
}
return originalOpen.call(this, method, url, ...rest);
};
// Interceptar sendBeacon (método usado pelo GA4)
const originalSendBeacon = navigator.sendBeacon;
navigator.sendBeacon = function(url, data) {
if (typeof url === 'string') {
if (url.includes('google-analytics.com/g/collect')) {
const urlObj = new URL(url);
return originalSendBeacon.call(this, '/api/metrics' + urlObj.search, data);
}
else if (url.includes('google-analytics.com')) {
url = url.replace(/https?:\\/\\/[^\\/]*google-analytics\\.com/g, '/api/metrics');
}
}
return originalSendBeacon.call(this, url, data);
};
})();
`,
}}
/>
{/* Google Analytics - Script principal via proxy */}
<Script
src="/api/gtm/G-QTT9QT0T3S"
strategy="afterInteractive"
async
/>
{/* Google Analytics - Inicialização */}
<Script
id="google-analytics-init"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-QTT9QT0T3S', {
// Forçar uso de fetch em vez de imagem beacon
transport_type: 'fetch'
});
`,
}}
/>
</body>
</html>
);
}