mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-17 22:07:52 +00:00
Implementando Rudderstack
This commit is contained in:
parent
6e9d847c77
commit
21f7aa7c40
@ -57,6 +57,12 @@ export function AudioUploader({
|
|||||||
as="span"
|
as="span"
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
className="cursor-pointer"
|
className="cursor-pointer"
|
||||||
|
trackingId="audio-upload-button"
|
||||||
|
trackingProperties={{
|
||||||
|
category: 'audio',
|
||||||
|
action: 'upload_click',
|
||||||
|
label: 'audio_uploader'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{isProcessing ? 'Processando...' : 'Enviar Áudio'}
|
{isProcessing ? 'Processando...' : 'Enviar Áudio'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { supabase } from '../../lib/supabase';
|
|||||||
import { useDataLayer } from '../../hooks/useDataLayer';
|
import { useDataLayer } from '../../hooks/useDataLayer';
|
||||||
import { useFormTracking } from '../../hooks/useFormTracking';
|
import { useFormTracking } from '../../hooks/useFormTracking';
|
||||||
import { Button } from '../ui/button';
|
import { Button } from '../ui/button';
|
||||||
|
import { useErrorTracking } from '../../hooks/useErrorTracking';
|
||||||
|
|
||||||
interface LoginFormProps {
|
interface LoginFormProps {
|
||||||
userType: 'school' | 'teacher' | 'student';
|
userType: 'school' | 'teacher' | 'student';
|
||||||
@ -39,6 +40,10 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
|||||||
formName: `${userType}-login`,
|
formName: `${userType}-login`,
|
||||||
category: 'auth'
|
category: 'auth'
|
||||||
});
|
});
|
||||||
|
const errorTracking = useErrorTracking({
|
||||||
|
category: 'auth',
|
||||||
|
userEmail: email
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
formTracking.trackFormStarted();
|
formTracking.trackFormStarted();
|
||||||
@ -60,13 +65,20 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
|||||||
console.log('Resposta do Supabase:', { data, error });
|
console.log('Resposta do Supabase:', { data, error });
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
|
errorTracking.trackApiError(error, '/auth/sign-in', 'POST', { email, userType });
|
||||||
formTracking.trackFormError('auth_error', error.message);
|
formTracking.trackFormError('auth_error', error.message);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.user) {
|
if (!data.user) {
|
||||||
|
const err = new Error('Usuário não encontrado');
|
||||||
|
errorTracking.trackError(err, {
|
||||||
|
componentName: 'LoginForm',
|
||||||
|
action: 'login_attempt',
|
||||||
|
metadata: { userType }
|
||||||
|
});
|
||||||
formTracking.trackFormError('user_not_found', 'Usuário não encontrado');
|
formTracking.trackFormError('user_not_found', 'Usuário não encontrado');
|
||||||
throw new Error('Usuário não encontrado');
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userRole = data.user.user_metadata.role;
|
const userRole = data.user.user_metadata.role;
|
||||||
@ -75,8 +87,17 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
|||||||
console.log('Role atual:', userRole);
|
console.log('Role atual:', userRole);
|
||||||
|
|
||||||
if (userRole !== userType) {
|
if (userRole !== userType) {
|
||||||
formTracking.trackFormError('invalid_role', `Este não é um login de ${userTypeLabels[userType]}`);
|
const err = new Error(`Este não é um login de ${userTypeLabels[userType]}`);
|
||||||
throw new Error(`Este não é um login de ${userTypeLabels[userType]}`);
|
errorTracking.trackError(err, {
|
||||||
|
componentName: 'LoginForm',
|
||||||
|
action: 'role_validation',
|
||||||
|
metadata: {
|
||||||
|
expectedRole: userType,
|
||||||
|
actualRole: userRole
|
||||||
|
}
|
||||||
|
});
|
||||||
|
formTracking.trackFormError('invalid_role', err.message);
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
formTracking.trackFormSubmitted(true, {
|
formTracking.trackFormSubmitted(true, {
|
||||||
@ -101,16 +122,14 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
|||||||
trackEvent('auth', 'login_success', 'form');
|
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) {
|
const errorMessage = err instanceof Error ? err.message : 'Email ou senha incorretos';
|
||||||
setError(err.message);
|
setError(errorMessage);
|
||||||
} else {
|
|
||||||
setError('Email ou senha incorretos');
|
|
||||||
}
|
|
||||||
formTracking.trackFormSubmitted(false, {
|
formTracking.trackFormSubmitted(false, {
|
||||||
error_type: err instanceof Error ? 'validation_error' : 'unknown_error',
|
error_type: err instanceof Error ? 'validation_error' : 'unknown_error',
|
||||||
error_message: err instanceof Error ? err.message : 'Email ou senha incorretos'
|
error_message: errorMessage
|
||||||
});
|
});
|
||||||
trackEvent('auth', 'login_error', err.message);
|
trackEvent('auth', 'login_error', errorMessage);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
|
|||||||
114
src/hooks/useErrorTracking.ts
Normal file
114
src/hooks/useErrorTracking.ts
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
import * as Sentry from '@sentry/react';
|
||||||
|
import { useRudderstack } from './useRudderstack';
|
||||||
|
|
||||||
|
interface ErrorTrackingOptions {
|
||||||
|
category?: string;
|
||||||
|
userId?: string;
|
||||||
|
userEmail?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useErrorTracking(options: ErrorTrackingOptions = {}) {
|
||||||
|
const { track } = useRudderstack();
|
||||||
|
const { category = 'error', userId, userEmail } = options;
|
||||||
|
|
||||||
|
const trackError = (
|
||||||
|
error: Error,
|
||||||
|
context?: {
|
||||||
|
componentName?: string;
|
||||||
|
action?: string;
|
||||||
|
metadata?: Record<string, any>;
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
// 1. Rastreia no Sentry primeiro (para debug técnico)
|
||||||
|
Sentry.withScope((scope) => {
|
||||||
|
// Adiciona contexto do usuário
|
||||||
|
if (userId) scope.setUser({ id: userId, email: userEmail });
|
||||||
|
|
||||||
|
// Adiciona contexto do erro
|
||||||
|
if (context?.componentName) scope.setTag('component', context.componentName);
|
||||||
|
if (context?.action) scope.setTag('action', context.action);
|
||||||
|
if (context?.metadata) scope.setContext('metadata', context.metadata);
|
||||||
|
|
||||||
|
// Captura o erro
|
||||||
|
Sentry.captureException(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Rastreia no Rudderstack (para analytics)
|
||||||
|
track('error_occurred', {
|
||||||
|
category,
|
||||||
|
error_name: error.name,
|
||||||
|
error_message: error.message,
|
||||||
|
error_stack: error.stack,
|
||||||
|
component: context?.componentName,
|
||||||
|
action: context?.action,
|
||||||
|
...context?.metadata,
|
||||||
|
// Informações do ambiente
|
||||||
|
url: window.location.href,
|
||||||
|
user_agent: navigator.userAgent,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const trackErrorBoundary = (
|
||||||
|
error: Error,
|
||||||
|
componentStack: string,
|
||||||
|
componentName: string
|
||||||
|
) => {
|
||||||
|
// 1. Rastreia no Sentry
|
||||||
|
Sentry.withScope((scope) => {
|
||||||
|
if (userId) scope.setUser({ id: userId, email: userEmail });
|
||||||
|
scope.setTag('component', componentName);
|
||||||
|
scope.setTag('error_type', 'react_error_boundary');
|
||||||
|
scope.setExtra('componentStack', componentStack);
|
||||||
|
Sentry.captureException(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Rastreia no Rudderstack
|
||||||
|
track('error_boundary_triggered', {
|
||||||
|
category,
|
||||||
|
error_name: error.name,
|
||||||
|
error_message: error.message,
|
||||||
|
component_name: componentName,
|
||||||
|
component_stack: componentStack,
|
||||||
|
url: window.location.href,
|
||||||
|
user_agent: navigator.userAgent,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const trackApiError = (
|
||||||
|
error: any,
|
||||||
|
endpoint: string,
|
||||||
|
method: string,
|
||||||
|
requestData?: any
|
||||||
|
) => {
|
||||||
|
// 1. Rastreia no Sentry
|
||||||
|
Sentry.withScope((scope) => {
|
||||||
|
if (userId) scope.setUser({ id: userId, email: userEmail });
|
||||||
|
scope.setTag('error_type', 'api_error');
|
||||||
|
scope.setTag('endpoint', endpoint);
|
||||||
|
scope.setTag('method', method);
|
||||||
|
scope.setContext('request', { data: requestData });
|
||||||
|
Sentry.captureException(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 2. Rastreia no Rudderstack
|
||||||
|
track('api_error_occurred', {
|
||||||
|
category,
|
||||||
|
endpoint,
|
||||||
|
method,
|
||||||
|
error_name: error.name,
|
||||||
|
error_message: error.message,
|
||||||
|
status_code: error.status || error.statusCode,
|
||||||
|
request_data: requestData,
|
||||||
|
url: window.location.href,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
trackError,
|
||||||
|
trackErrorBoundary,
|
||||||
|
trackApiError,
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user