veza/apps/web/src/services/analyticsService.ts
senke 6310298e80 monitoring: implement Monitor 3 - set up user analytics tracking
- Implemented analyticsService.recordEvent() method
- Uses backend /analytics/events endpoint for event tracking
- Fails silently to avoid disrupting user experience
- Logs events in development mode for debugging
- Error tracking already handled by Sentry (Monitor 5)
- Components can track feature usage via analyticsService.recordEvent()
- Complete user analytics system for tracking feature usage and interactions
2026-01-16 14:28:50 +01:00

91 lines
2.9 KiB
TypeScript

/**
* Monitor 3: User Analytics Service
* Tracks feature usage and user interactions
*/
import { apiClient } from './api/client';
import { logger } from '@/utils/logger';
const MOCK_GLOBAL_STATS = {
total_users: 12500,
total_tracks: 3420,
total_plays: 1205430,
total_revenue: 14250.5,
followers: 24500,
profile_views: 45200,
trends: { plays: 8.2, revenue: 12.5, followers: 2.1, views: -2.4 },
sparklines: {
plays: [40, 35, 50, 60, 55, 70, 80, 75, 90],
revenue: [10, 12, 15, 14, 18, 20, 22, 25, 28],
followers: [20, 21, 21, 22, 22, 23, 23, 24, 24],
views: [50, 48, 45, 42, 40, 43, 41, 40, 38],
},
};
const TOP_TRACKS = [
{ id: 't1', title: 'Neon Nights', plays: 15420, change: 12, revenue: 145.5 },
{ id: 't2', title: 'Cyber City', plays: 12100, change: -5, revenue: 98.2 },
{ id: 't3', title: 'System Failure', plays: 8500, change: 24, revenue: 65.0 },
{ id: 't4', title: 'Mainframe', plays: 6200, change: 8, revenue: 42.1 },
];
export const analyticsService = {
/**
* Monitor 3: Record a user analytics event
* Tracks feature usage and user interactions
* @param eventName - Name of the event (e.g., 'feature_used', 'button_clicked')
* @param payload - Optional event data (e.g., { feature: 'search', query: '...' })
*/
recordEvent: async (eventName: string, payload?: Record<string, unknown>) => {
try {
// Send event to backend analytics endpoint
await apiClient.post('/analytics/events', {
event_name: eventName,
payload: payload || {},
});
// Log in development for debugging
if (import.meta.env.DEV) {
logger.debug('[Analytics] Event recorded', {
event_name: eventName,
payload,
});
}
} catch (error) {
// Don't throw errors for analytics - fail silently to avoid disrupting user experience
// Log error for debugging in development
if (import.meta.env.DEV) {
logger.warn('[Analytics] Failed to record event', {
event_name: eventName,
error: error instanceof Error ? error.message : String(error),
});
}
// In production, silently fail to avoid disrupting UX
}
},
getGlobalStats: async (_range: string = '30d') => {
await new Promise((resolve) => setTimeout(resolve, 600));
return MOCK_GLOBAL_STATS;
},
getTopTracks: async (_range: string = '30d') => {
await new Promise((resolve) => setTimeout(resolve, 500));
return TOP_TRACKS;
},
getTrafficSources: async () => {
await new Promise((resolve) => setTimeout(resolve, 400));
return [
{ label: 'Direct', val: 45, color: 'bg-kodo-cyan' },
{ label: 'Social Media', val: 30, color: 'bg-kodo-magenta' },
{ label: 'Search', val: 15, color: 'bg-kodo-lime' },
{ label: 'Referral', val: 10, color: 'bg-kodo-gold' },
];
},
getDeviceBreakdown: async () => {
await new Promise((resolve) => setTimeout(resolve, 400));
return { mobile: 65, desktop: 35 };
},
};