feat: Community 页面 PostHog 事件追踪完成
Custom Hook 集成(useEventFilters.js) 页面组件追踪
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
import { useState, useCallback } from 'react';
|
import { useState, useCallback } from 'react';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import { logger } from '../../../utils/logger';
|
import { logger } from '../../../utils/logger';
|
||||||
|
import { usePostHogTrack } from '../../../hooks/usePostHogRedux';
|
||||||
|
import { RETENTION_EVENTS } from '../../../lib/constants';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 事件筛选逻辑 Hook
|
* 事件筛选逻辑 Hook
|
||||||
@@ -15,6 +17,7 @@ import { logger } from '../../../utils/logger';
|
|||||||
*/
|
*/
|
||||||
export const useEventFilters = ({ navigate, onEventClick, eventTimelineRef } = {}) => {
|
export const useEventFilters = ({ navigate, onEventClick, eventTimelineRef } = {}) => {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
const { track } = usePostHogTrack(); // PostHog 追踪
|
||||||
|
|
||||||
// 筛选参数状态 - 初始化时从URL读取,之后只用本地状态
|
// 筛选参数状态 - 初始化时从URL读取,之后只用本地状态
|
||||||
const [filters, setFilters] = useState(() => {
|
const [filters, setFilters] = useState(() => {
|
||||||
@@ -35,12 +38,68 @@ export const useEventFilters = ({ navigate, onEventClick, eventTimelineRef } = {
|
|||||||
oldFilters: filters,
|
oldFilters: filters,
|
||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 🎯 PostHog 追踪:搜索查询
|
||||||
|
if (newFilters.q !== filters.q && newFilters.q) {
|
||||||
|
track(RETENTION_EVENTS.SEARCH_QUERY_SUBMITTED, {
|
||||||
|
query: newFilters.q,
|
||||||
|
category: 'news',
|
||||||
|
previous_query: filters.q || null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🎯 PostHog 追踪:排序变化
|
||||||
|
if (newFilters.sort !== filters.sort) {
|
||||||
|
track(RETENTION_EVENTS.SEARCH_FILTER_APPLIED, {
|
||||||
|
filter_type: 'sort',
|
||||||
|
filter_value: newFilters.sort,
|
||||||
|
previous_value: filters.sort,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🎯 PostHog 追踪:重要性筛选
|
||||||
|
if (newFilters.importance !== filters.importance) {
|
||||||
|
track(RETENTION_EVENTS.SEARCH_FILTER_APPLIED, {
|
||||||
|
filter_type: 'importance',
|
||||||
|
filter_value: newFilters.importance,
|
||||||
|
previous_value: filters.importance,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🎯 PostHog 追踪:时间范围筛选
|
||||||
|
if (newFilters.date_range !== filters.date_range && newFilters.date_range) {
|
||||||
|
track(RETENTION_EVENTS.SEARCH_FILTER_APPLIED, {
|
||||||
|
filter_type: 'date_range',
|
||||||
|
filter_value: newFilters.date_range,
|
||||||
|
previous_value: filters.date_range || null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🎯 PostHog 追踪:行业筛选
|
||||||
|
if (newFilters.industry_code !== filters.industry_code && newFilters.industry_code) {
|
||||||
|
track(RETENTION_EVENTS.SEARCH_FILTER_APPLIED, {
|
||||||
|
filter_type: 'industry',
|
||||||
|
filter_value: newFilters.industry_code,
|
||||||
|
previous_value: filters.industry_code || null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setFilters(newFilters);
|
setFilters(newFilters);
|
||||||
logger.debug('useEventFilters', '✅ setFilters 已调用 (React异步更新中...)');
|
logger.debug('useEventFilters', '✅ setFilters 已调用 (React异步更新中...)');
|
||||||
}, [filters]);
|
}, [filters, track]);
|
||||||
|
|
||||||
// 处理分页变化
|
// 处理分页变化
|
||||||
const handlePageChange = useCallback((page) => {
|
const handlePageChange = useCallback((page) => {
|
||||||
|
// 🎯 PostHog 追踪:翻页
|
||||||
|
track(RETENTION_EVENTS.NEWS_LIST_VIEWED, {
|
||||||
|
page,
|
||||||
|
filters: {
|
||||||
|
sort: filters.sort,
|
||||||
|
importance: filters.importance,
|
||||||
|
has_query: !!filters.q,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
// 保持现有筛选条件,只更新页码
|
// 保持现有筛选条件,只更新页码
|
||||||
updateFilters({ ...filters, page });
|
updateFilters({ ...filters, page });
|
||||||
|
|
||||||
@@ -53,21 +112,37 @@ export const useEventFilters = ({ navigate, onEventClick, eventTimelineRef } = {
|
|||||||
});
|
});
|
||||||
}, 100); // 延迟100ms,确保DOM更新
|
}, 100); // 延迟100ms,确保DOM更新
|
||||||
}
|
}
|
||||||
}, [filters, updateFilters, eventTimelineRef]);
|
}, [filters, updateFilters, eventTimelineRef, track]);
|
||||||
|
|
||||||
// 处理事件点击
|
// 处理事件点击
|
||||||
const handleEventClick = useCallback((event) => {
|
const handleEventClick = useCallback((event) => {
|
||||||
|
// 🎯 PostHog 追踪:新闻事件点击
|
||||||
|
track(RETENTION_EVENTS.NEWS_ARTICLE_CLICKED, {
|
||||||
|
event_id: event.id || event.event_id,
|
||||||
|
event_title: event.title,
|
||||||
|
importance: event.importance,
|
||||||
|
source: 'community_page',
|
||||||
|
has_stocks: !!(event.related_stocks && event.related_stocks.length > 0),
|
||||||
|
has_concepts: !!(event.related_concepts && event.related_concepts.length > 0),
|
||||||
|
});
|
||||||
|
|
||||||
if (onEventClick) {
|
if (onEventClick) {
|
||||||
onEventClick(event);
|
onEventClick(event);
|
||||||
}
|
}
|
||||||
}, [onEventClick]);
|
}, [onEventClick, track]);
|
||||||
|
|
||||||
// 处理查看详情
|
// 处理查看详情
|
||||||
const handleViewDetail = useCallback((eventId) => {
|
const handleViewDetail = useCallback((eventId) => {
|
||||||
|
// 🎯 PostHog 追踪:查看详情
|
||||||
|
track(RETENTION_EVENTS.NEWS_DETAIL_OPENED, {
|
||||||
|
event_id: eventId,
|
||||||
|
source: 'community_page',
|
||||||
|
});
|
||||||
|
|
||||||
if (navigate) {
|
if (navigate) {
|
||||||
navigate(`/event-detail/${eventId}`);
|
navigate(`/event-detail/${eventId}`);
|
||||||
}
|
}
|
||||||
}, [navigate]);
|
}, [navigate, track]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filters,
|
filters,
|
||||||
|
|||||||
@@ -20,12 +20,15 @@ import { useEventFilters } from './hooks/useEventFilters';
|
|||||||
|
|
||||||
import { logger } from '../../utils/logger';
|
import { logger } from '../../utils/logger';
|
||||||
import { useNotification } from '../../contexts/NotificationContext';
|
import { useNotification } from '../../contexts/NotificationContext';
|
||||||
|
import { usePostHogTrack } from '../../hooks/usePostHogRedux';
|
||||||
|
import { RETENTION_EVENTS } from '../../lib/constants';
|
||||||
|
|
||||||
// 导航栏已由 MainLayout 提供,无需在此导入
|
// 导航栏已由 MainLayout 提供,无需在此导入
|
||||||
|
|
||||||
const Community = () => {
|
const Community = () => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
const { track } = usePostHogTrack(); // PostHog 追踪
|
||||||
|
|
||||||
// Redux状态
|
// Redux状态
|
||||||
const { popularKeywords, hotEvents } = useSelector(state => state.communityData);
|
const { popularKeywords, hotEvents } = useSelector(state => state.communityData);
|
||||||
@@ -59,6 +62,15 @@ const Community = () => {
|
|||||||
dispatch(fetchHotEvents());
|
dispatch(fetchHotEvents());
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
|
// 🎯 PostHog 追踪:页面浏览
|
||||||
|
useEffect(() => {
|
||||||
|
track(RETENTION_EVENTS.COMMUNITY_PAGE_VIEWED, {
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
has_hot_events: hotEvents && hotEvents.length > 0,
|
||||||
|
has_keywords: popularKeywords && popularKeywords.length > 0,
|
||||||
|
});
|
||||||
|
}, [track]); // 只在组件挂载时执行一次
|
||||||
|
|
||||||
// ⚡ 首次访问社区时,延迟显示权限引导
|
// ⚡ 首次访问社区时,延迟显示权限引导
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (showCommunityGuide) {
|
if (showCommunityGuide) {
|
||||||
|
|||||||
Reference in New Issue
Block a user