/**
=========================================================
Vision UI PRO React - v1.0.0
=========================================================
Product Page: https://www.creative-tim.com/product/vision-ui-dashboard-pro-react
Copyright 2021 Creative Tim (https://www.creative-tim.com/)
Design and Coded by Simmmple & Creative Tim
=========================================================
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Visionware.
*/
import React, { useEffect, useRef } from "react";
import { useDispatch } from 'react-redux';
import { useLocation } from 'react-router-dom';
// Routes
import AppRoutes from './routes';
// Providers
import AppProviders from './providers/AppProviders';
// Components
import GlobalComponents from './components/GlobalComponents';
// Hooks
import { useGlobalErrorHandler } from './hooks/useGlobalErrorHandler';
// Redux
import { initializePostHog } from './store/slices/posthogSlice';
// Utils
import { logger } from './utils/logger';
// PostHog 追踪
import { trackEvent, trackEventAsync } from '@lib/posthog';
// Contexts
import { useAuth } from '@contexts/AuthContext';
/**
* AppContent - 应用核心内容
* 负责 PostHog 初始化和渲染路由
*/
function AppContent() {
const dispatch = useDispatch();
const location = useLocation();
const { isAuthenticated } = useAuth();
// ✅ 使用 Ref 存储页面进入时间和路径(避免闭包问题)
const pageEnterTimeRef = useRef(Date.now());
const currentPathRef = useRef(location.pathname);
// 🎯 PostHog Redux 初始化
useEffect(() => {
dispatch(initializePostHog());
logger.info('App', 'PostHog Redux 初始化已触发');
}, [dispatch]);
// ✅ 首次访问追踪
useEffect(() => {
const hasVisited = localStorage.getItem('has_visited');
if (!hasVisited) {
const urlParams = new URLSearchParams(location.search);
// ⚡ 使用异步追踪,不阻塞页面渲染
trackEventAsync('first_visit', {
referrer: document.referrer || 'direct',
utm_source: urlParams.get('utm_source'),
utm_medium: urlParams.get('utm_medium'),
utm_campaign: urlParams.get('utm_campaign'),
landing_page: location.pathname,
timestamp: new Date().toISOString()
});
localStorage.setItem('has_visited', 'true');
}
}, [location.search, location.pathname]);
// ✅ 页面浏览时长追踪
useEffect(() => {
// 计算上一个页面的停留时长
const calculateAndTrackDuration = () => {
const exitTime = Date.now();
const duration = Math.round((exitTime - pageEnterTimeRef.current) / 1000); // 秒
// 只追踪停留时间 > 1 秒的页面(过滤快速跳转)
if (duration > 1) {
// ⚡ 使用异步追踪,不阻塞页面切换
trackEventAsync('page_view_duration', {
path: currentPathRef.current,
duration_seconds: duration,
is_authenticated: isAuthenticated,
timestamp: new Date().toISOString()
});
}
};
// 路由切换时追踪上一个页面的时长
if (currentPathRef.current !== location.pathname) {
calculateAndTrackDuration();
// 更新为新页面
currentPathRef.current = location.pathname;
pageEnterTimeRef.current = Date.now();
}
// 页面关闭/刷新时追踪时长
const handleBeforeUnload = () => {
calculateAndTrackDuration();
};
window.addEventListener('beforeunload', handleBeforeUnload);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
};
}, [location.pathname, isAuthenticated]);
return ;
}
/**
* App - 应用根组件
* 设置全局错误处理,提供 Provider 和全局组件
*/
export default function App() {
// 全局错误处理
useGlobalErrorHandler();
return (
);
}