mirror of
https://github.com/lucasrcsantana/story-generator.git
synced 2025-12-17 05:47:52 +00:00
Implementando Rudderstack
This commit is contained in:
parent
6e9d847c77
commit
21f7aa7c40
@ -57,6 +57,12 @@ export function AudioUploader({
|
||||
as="span"
|
||||
disabled={isProcessing}
|
||||
className="cursor-pointer"
|
||||
trackingId="audio-upload-button"
|
||||
trackingProperties={{
|
||||
category: 'audio',
|
||||
action: 'upload_click',
|
||||
label: 'audio_uploader'
|
||||
}}
|
||||
>
|
||||
{isProcessing ? 'Processando...' : 'Enviar Áudio'}
|
||||
</Button>
|
||||
|
||||
@ -6,6 +6,7 @@ import { supabase } from '../../lib/supabase';
|
||||
import { useDataLayer } from '../../hooks/useDataLayer';
|
||||
import { useFormTracking } from '../../hooks/useFormTracking';
|
||||
import { Button } from '../ui/button';
|
||||
import { useErrorTracking } from '../../hooks/useErrorTracking';
|
||||
|
||||
interface LoginFormProps {
|
||||
userType: 'school' | 'teacher' | 'student';
|
||||
@ -39,6 +40,10 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
||||
formName: `${userType}-login`,
|
||||
category: 'auth'
|
||||
});
|
||||
const errorTracking = useErrorTracking({
|
||||
category: 'auth',
|
||||
userEmail: email
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
formTracking.trackFormStarted();
|
||||
@ -60,13 +65,20 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
||||
console.log('Resposta do Supabase:', { data, error });
|
||||
|
||||
if (error) {
|
||||
errorTracking.trackApiError(error, '/auth/sign-in', 'POST', { email, userType });
|
||||
formTracking.trackFormError('auth_error', error.message);
|
||||
throw error;
|
||||
}
|
||||
|
||||
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');
|
||||
throw new Error('Usuário não encontrado');
|
||||
throw err;
|
||||
}
|
||||
|
||||
const userRole = data.user.user_metadata.role;
|
||||
@ -75,8 +87,17 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
||||
console.log('Role atual:', userRole);
|
||||
|
||||
if (userRole !== userType) {
|
||||
formTracking.trackFormError('invalid_role', `Este não é um login de ${userTypeLabels[userType]}`);
|
||||
throw new Error(`Este não é um login de ${userTypeLabels[userType]}`);
|
||||
const err = 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, {
|
||||
@ -101,16 +122,14 @@ export function LoginForm({ userType, onLogin, onRegisterClick }: LoginFormProps
|
||||
trackEvent('auth', 'login_success', 'form');
|
||||
} catch (err) {
|
||||
console.error('Erro no login:', err);
|
||||
if (err instanceof Error) {
|
||||
setError(err.message);
|
||||
} else {
|
||||
setError('Email ou senha incorretos');
|
||||
}
|
||||
const errorMessage = err instanceof Error ? err.message : 'Email ou senha incorretos';
|
||||
setError(errorMessage);
|
||||
|
||||
formTracking.trackFormSubmitted(false, {
|
||||
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 {
|
||||
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