veza/apps/web/src/components/views/analytics-view/useAnalyticsView.ts
senke 461fd9cf6a refactor(web): split AnalyticsView into analytics-view module
- types: AnalyticsViewProps, DateRangeKey, GlobalStats, TopTrackRow, TrafficSource, DeviceStats, ChartHoverData
- useAnalyticsView: dateRange, stats, topTracks, trafficSources, deviceStats, loading, hoveredData, handleExport
- AnalyticsViewHeader, AnalyticsViewKpiGrid, AnalyticsViewChart, AnalyticsViewOrigins, AnalyticsViewPlatforms, AnalyticsViewTopTracks, AnalyticsViewSkeleton
- Data via analyticsService; loading renders Skeleton
- text-[10px] -> text-xs, tracking-[0.2em] -> tracking-wide
- Stories: Default, Loading (Skeleton); decorator min-h-layout-page
- Re-export from AnalyticsView.tsx

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-06 18:33:42 +01:00

70 lines
2.5 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react';
import { useToast } from '@/components/feedback/ToastProvider';
import { analyticsService } from '@/services/analyticsService';
import { logger } from '@/utils/logger';
import type { DateRangeKey } from './types';
import type { GlobalStats, TopTrackRow, TrafficSource, DeviceStats, ChartHoverData } from './types';
export function useAnalyticsView(dateRangeInitial: DateRangeKey = '30d') {
const { addToast } = useToast();
const [dateRange, setDateRange] = useState<DateRangeKey>(dateRangeInitial);
const [stats, setStats] = useState<GlobalStats>({});
const [topTracks, setTopTracks] = useState<TopTrackRow[]>([]);
const [trafficSources, setTrafficSources] = useState<TrafficSource[]>([]);
const [deviceStats, setDeviceStats] = useState<DeviceStats>({ mobile: 0, desktop: 0 });
const [loading, setLoading] = useState(true);
const [hoveredData, setHoveredData] = useState<ChartHoverData | null>(null);
const fetchData = useCallback(async () => {
setLoading(true);
try {
const [global, tracks, sources, devices] = await Promise.all([
analyticsService.getGlobalStats(dateRange),
analyticsService.getTopTracks(dateRange),
analyticsService.getTrafficSources(),
analyticsService.getDeviceBreakdown(),
]);
setStats(global as GlobalStats);
setTopTracks((tracks as TopTrackRow[]) ?? []);
setTrafficSources((sources as TrafficSource[]) ?? []);
setDeviceStats((devices as DeviceStats) ?? { mobile: 0, desktop: 0 });
} catch (e) {
logger.error('Error loading analytics', { error: e });
} finally {
setLoading(false);
}
}, [dateRange]);
useEffect(() => {
fetchData();
}, [fetchData]);
const handleExport = useCallback(
(format: 'csv' | 'json') => {
addToast(`Building ${format.toUpperCase()} archive...`, 'info');
setTimeout(() => {
const blob = new Blob([JSON.stringify(stats, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `veza-analytics-${dateRange}-${new Date().toISOString().split('T')[0]}.${format}`;
a.click();
addToast('Data packet exported successfully', 'success');
}, 1500);
},
[stats, dateRange, addToast]
);
return {
dateRange,
setDateRange,
stats,
topTracks,
trafficSources,
deviceStats,
loading,
hoveredData,
setHoveredData,
handleExport,
};
}