mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-17 05:47:52 +00:00
Implementação do GTM
This commit is contained in:
parent
75d9d4635b
commit
1542572be4
39
src/components/analytics/GoogleTagManager.tsx
Normal file
39
src/components/analytics/GoogleTagManager.tsx
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface GoogleTagManagerProps {
|
||||||
|
gtmId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GoogleTagManager({ gtmId }: GoogleTagManagerProps) {
|
||||||
|
React.useEffect(() => {
|
||||||
|
// Carrega o script do GTM
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.innerHTML = `
|
||||||
|
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
|
||||||
|
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
|
||||||
|
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
|
||||||
|
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
|
||||||
|
})(window,document,'script','dataLayer','${gtmId}');
|
||||||
|
`;
|
||||||
|
document.head.appendChild(script);
|
||||||
|
|
||||||
|
// Adiciona o noscript iframe
|
||||||
|
const noscript = document.createElement('noscript');
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmId}`;
|
||||||
|
iframe.height = '0';
|
||||||
|
iframe.width = '0';
|
||||||
|
iframe.style.display = 'none';
|
||||||
|
iframe.style.visibility = 'hidden';
|
||||||
|
noscript.appendChild(iframe);
|
||||||
|
document.body.insertBefore(noscript, document.body.firstChild);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// Cleanup
|
||||||
|
document.head.removeChild(script);
|
||||||
|
document.body.removeChild(noscript);
|
||||||
|
};
|
||||||
|
}, [gtmId]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ import { LogIn, Eye, EyeOff, School, GraduationCap, User } from 'lucide-react';
|
|||||||
import { useAuth } from '../../hooks/useAuth';
|
import { useAuth } from '../../hooks/useAuth';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { supabase } from '../../lib/supabase';
|
import { supabase } from '../../lib/supabase';
|
||||||
|
import { useDataLayer } from '../../hooks/useDataLayer';
|
||||||
|
|
||||||
interface LoginFormProps {
|
interface LoginFormProps {
|
||||||
userType: 'school' | 'teacher' | 'student';
|
userType: 'school' | 'teacher' | 'student';
|
||||||
@ -30,6 +31,7 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { signIn } = useAuth();
|
const { signIn } = useAuth();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { trackEvent } = useDataLayer();
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -75,6 +77,7 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
|||||||
throw new Error('Tipo de usuário inválido');
|
throw new Error('Tipo de usuário inválido');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trackEvent('auth', 'login_success', 'form');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Erro no login:', err);
|
console.error('Erro no login:', err);
|
||||||
if (err instanceof Error) {
|
if (err instanceof Error) {
|
||||||
@ -82,6 +85,7 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
|||||||
} else {
|
} else {
|
||||||
setError('Email ou senha incorretos');
|
setError('Email ou senha incorretos');
|
||||||
}
|
}
|
||||||
|
trackEvent('auth', 'login_error', err.message);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
60
src/hooks/useDataLayer.ts
Normal file
60
src/hooks/useDataLayer.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
interface DataLayerEvent {
|
||||||
|
event: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
dataLayer: any[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDataLayer() {
|
||||||
|
// Inicializa o dataLayer se não existir
|
||||||
|
if (!window.dataLayer) {
|
||||||
|
window.dataLayer = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const push = (data: DataLayerEvent) => {
|
||||||
|
window.dataLayer.push(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const pageView = (path: string) => {
|
||||||
|
push({
|
||||||
|
event: 'pageview',
|
||||||
|
page: {
|
||||||
|
path,
|
||||||
|
title: document.title,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const trackEvent = (
|
||||||
|
category: string,
|
||||||
|
action: string,
|
||||||
|
label?: string,
|
||||||
|
value?: number
|
||||||
|
) => {
|
||||||
|
push({
|
||||||
|
event: 'track_event',
|
||||||
|
category,
|
||||||
|
action,
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const trackUserProperties = (properties: Record<string, any>) => {
|
||||||
|
push({
|
||||||
|
event: 'set_user_properties',
|
||||||
|
user_properties: properties,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
push,
|
||||||
|
pageView,
|
||||||
|
trackEvent,
|
||||||
|
trackUserProperties,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -5,8 +5,12 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|||||||
import * as Sentry from "@sentry/react";
|
import * as Sentry from "@sentry/react";
|
||||||
import { router } from './routes';
|
import { router } from './routes';
|
||||||
import { Toaster } from './components/ui/toaster';
|
import { Toaster } from './components/ui/toaster';
|
||||||
|
import { GoogleTagManager } from './components/analytics/GoogleTagManager';
|
||||||
import './index.css';
|
import './index.css';
|
||||||
|
|
||||||
|
// GTM ID - Substitua pelo seu ID real do GTM
|
||||||
|
const GTM_ID = import.meta.env.VITE_GTM_ID;
|
||||||
|
|
||||||
// Inicialização do Sentry
|
// Inicialização do Sentry
|
||||||
Sentry.init({
|
Sentry.init({
|
||||||
dsn: "https://6c15876055bf4a860c1b63a8e4e7ca65@o544400.ingest.us.sentry.io/4508626073092096",
|
dsn: "https://6c15876055bf4a860c1b63a8e4e7ca65@o544400.ingest.us.sentry.io/4508626073092096",
|
||||||
@ -49,6 +53,7 @@ const queryClient = new QueryClient({
|
|||||||
function Root() {
|
function Root() {
|
||||||
return (
|
return (
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
|
<GoogleTagManager gtmId={GTM_ID} />
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
<Toaster />
|
<Toaster />
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user