362 lines
10 KiB
JavaScript
362 lines
10 KiB
JavaScript
// src/views/Concept/hooks/useConceptEvents.js
|
||
// 概念中心页面事件追踪 Hook
|
||
|
||
import { useCallback, useEffect } from 'react';
|
||
import { usePostHogTrack } from '../../../hooks/usePostHogRedux';
|
||
import { RETENTION_EVENTS, REVENUE_EVENTS } from '../../../lib/constants';
|
||
import { logger } from '../../../utils/logger';
|
||
|
||
/**
|
||
* 概念中心事件追踪 Hook
|
||
* @param {Object} options - 配置选项
|
||
* @param {Function} options.navigate - 路由导航函数
|
||
* @returns {Object} 事件追踪处理函数集合
|
||
*/
|
||
export const useConceptEvents = ({ navigate } = {}) => {
|
||
const { track } = usePostHogTrack();
|
||
|
||
// 🎯 页面浏览事件 - 页面加载时触发
|
||
useEffect(() => {
|
||
track(RETENTION_EVENTS.CONCEPT_PAGE_VIEWED, {
|
||
timestamp: new Date().toISOString(),
|
||
});
|
||
logger.debug('useConceptEvents', '📊 Concept Page Viewed');
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪概念列表数据查看
|
||
* @param {Array} concepts - 概念列表
|
||
* @param {Object} filters - 当前筛选条件
|
||
*/
|
||
const trackConceptListViewed = useCallback((concepts, filters = {}) => {
|
||
track(RETENTION_EVENTS.CONCEPT_LIST_VIEWED, {
|
||
concept_count: concepts.length,
|
||
sort_by: filters.sortBy,
|
||
view_mode: filters.viewMode,
|
||
has_search_query: !!filters.searchQuery,
|
||
selected_date: filters.selectedDate,
|
||
page: filters.page,
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '📋 Concept List Viewed', {
|
||
count: concepts.length,
|
||
filters,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪搜索开始
|
||
*/
|
||
const trackSearchInitiated = useCallback(() => {
|
||
track(RETENTION_EVENTS.SEARCH_INITIATED, {
|
||
context: 'concept_center',
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '🔍 Search Initiated');
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪搜索查询提交
|
||
* @param {string} query - 搜索查询词
|
||
* @param {number} resultCount - 搜索结果数量
|
||
*/
|
||
const trackSearchQuerySubmitted = useCallback((query, resultCount = 0) => {
|
||
if (!query) return;
|
||
|
||
track(RETENTION_EVENTS.SEARCH_QUERY_SUBMITTED, {
|
||
query,
|
||
category: 'concept',
|
||
result_count: resultCount,
|
||
has_results: resultCount > 0,
|
||
});
|
||
|
||
// 如果没有搜索结果,额外追踪
|
||
if (resultCount === 0) {
|
||
track(RETENTION_EVENTS.SEARCH_NO_RESULTS, {
|
||
query,
|
||
context: 'concept_center',
|
||
});
|
||
}
|
||
|
||
logger.debug('useConceptEvents', '🔍 Search Query Submitted', {
|
||
query,
|
||
resultCount,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪排序方式变化
|
||
* @param {string} sortBy - 新的排序方式
|
||
* @param {string} previousSortBy - 之前的排序方式
|
||
*/
|
||
const trackSortChanged = useCallback((sortBy, previousSortBy = null) => {
|
||
track(RETENTION_EVENTS.SEARCH_FILTER_APPLIED, {
|
||
filter_type: 'sort',
|
||
filter_value: sortBy,
|
||
previous_value: previousSortBy,
|
||
context: 'concept_center',
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '🔄 Sort Changed', {
|
||
sortBy,
|
||
previousSortBy,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪视图模式切换
|
||
* @param {string} viewMode - 新的视图模式 (grid/list)
|
||
* @param {string} previousViewMode - 之前的视图模式
|
||
*/
|
||
const trackViewModeChanged = useCallback((viewMode, previousViewMode = null) => {
|
||
track(RETENTION_EVENTS.SEARCH_FILTER_APPLIED, {
|
||
filter_type: 'view_mode',
|
||
filter_value: viewMode,
|
||
previous_value: previousViewMode,
|
||
context: 'concept_center',
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '👁️ View Mode Changed', {
|
||
viewMode,
|
||
previousViewMode,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪日期选择变化
|
||
* @param {string} newDate - 新选择的日期
|
||
* @param {string} previousDate - 之前的日期
|
||
* @param {string} selectionMethod - 选择方式 (today/yesterday/week_ago/month_ago/custom)
|
||
*/
|
||
const trackDateChanged = useCallback((newDate, previousDate = null, selectionMethod = 'custom') => {
|
||
track(RETENTION_EVENTS.SEARCH_FILTER_APPLIED, {
|
||
filter_type: 'date',
|
||
filter_value: newDate,
|
||
previous_value: previousDate,
|
||
selection_method: selectionMethod,
|
||
context: 'concept_center',
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '📅 Date Changed', {
|
||
newDate,
|
||
previousDate,
|
||
selectionMethod,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪分页变化
|
||
* @param {number} page - 新的页码
|
||
* @param {Object} filters - 当前筛选条件
|
||
*/
|
||
const trackPageChanged = useCallback((page, filters = {}) => {
|
||
track(RETENTION_EVENTS.CONCEPT_LIST_VIEWED, {
|
||
page,
|
||
sort_by: filters.sortBy,
|
||
view_mode: filters.viewMode,
|
||
has_search_query: !!filters.searchQuery,
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '📄 Page Changed', { page, filters });
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪概念卡片点击
|
||
* @param {Object} concept - 概念对象
|
||
* @param {number} position - 在列表中的位置
|
||
* @param {string} source - 来源 (list/stats_panel)
|
||
*/
|
||
const trackConceptClicked = useCallback((concept, position = 0, source = 'list') => {
|
||
track(RETENTION_EVENTS.CONCEPT_CLICKED, {
|
||
concept_name: concept.concept_name || concept.name,
|
||
concept_code: concept.concept_code || concept.code,
|
||
change_percent: concept.change_pct || concept.change_percent,
|
||
stock_count: concept.stock_count,
|
||
position,
|
||
source,
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '🎯 Concept Clicked', {
|
||
concept: concept.concept_name || concept.name,
|
||
position,
|
||
source,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪概念下的股票标签点击
|
||
* @param {Object} stock - 股票对象
|
||
* @param {string} conceptName - 所属概念名称
|
||
*/
|
||
const trackConceptStockClicked = useCallback((stock, conceptName) => {
|
||
track(RETENTION_EVENTS.CONCEPT_STOCK_CLICKED, {
|
||
stock_code: stock.code || stock.stock_code,
|
||
stock_name: stock.name || stock.stock_name,
|
||
concept_name: conceptName,
|
||
source: 'concept_center_tag',
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '🏷️ Concept Stock Tag Clicked', {
|
||
stock: stock.code || stock.stock_code,
|
||
concept: conceptName,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪概念详情查看(时间轴Modal)
|
||
* @param {string} conceptName - 概念名称
|
||
* @param {string} conceptId - 概念ID
|
||
*/
|
||
const trackConceptDetailViewed = useCallback((conceptName, conceptId) => {
|
||
track(RETENTION_EVENTS.CONCEPT_DETAIL_VIEWED, {
|
||
concept_name: conceptName,
|
||
concept_id: conceptId,
|
||
source: 'concept_center',
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '📊 Concept Detail Viewed', {
|
||
conceptName,
|
||
conceptId,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪股票详情Modal打开
|
||
* @param {string} stockCode - 股票代码
|
||
* @param {string} stockName - 股票名称
|
||
*/
|
||
const trackStockDetailViewed = useCallback((stockCode, stockName) => {
|
||
track(RETENTION_EVENTS.STOCK_DETAIL_VIEWED, {
|
||
stock_code: stockCode,
|
||
stock_name: stockName,
|
||
source: 'concept_center_modal',
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '👁️ Stock Detail Modal Opened', {
|
||
stockCode,
|
||
stockName,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪付费墙展示
|
||
* @param {string} feature - 需要付费的功能
|
||
* @param {string} requiredTier - 需要的订阅等级
|
||
*/
|
||
const trackPaywallShown = useCallback((feature, requiredTier = 'pro') => {
|
||
track(REVENUE_EVENTS.PAYWALL_SHOWN, {
|
||
feature,
|
||
required_tier: requiredTier,
|
||
page: 'concept_center',
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '🔒 Paywall Shown', {
|
||
feature,
|
||
requiredTier,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪升级按钮点击
|
||
* @param {string} feature - 触发升级的功能
|
||
* @param {string} targetTier - 目标订阅等级
|
||
*/
|
||
const trackUpgradeClicked = useCallback((feature, targetTier = 'pro') => {
|
||
track(REVENUE_EVENTS.PAYWALL_UPGRADE_CLICKED, {
|
||
feature,
|
||
target_tier: targetTier,
|
||
source_page: 'concept_center',
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '⬆️ Upgrade Button Clicked', {
|
||
feature,
|
||
targetTier,
|
||
});
|
||
}, [track]);
|
||
|
||
// ========== 别名函数 - 为保持向后兼容性 ==========
|
||
|
||
/**
|
||
* 追踪概念搜索(别名函数)
|
||
* @alias trackSearchQuerySubmitted
|
||
*/
|
||
const trackConceptSearched = useCallback((query, resultCount = 0) => {
|
||
return trackSearchQuerySubmitted(query, resultCount);
|
||
}, [trackSearchQuerySubmitted]);
|
||
|
||
/**
|
||
* 追踪筛选器应用(通用包装函数)
|
||
* @param {string} filterType - 筛选类型 (sort/date/view_mode)
|
||
* @param {any} filterValue - 筛选值
|
||
* @param {any} previousValue - 之前的值
|
||
*/
|
||
const trackFilterApplied = useCallback((filterType, filterValue, previousValue = null) => {
|
||
if (filterType === 'sort') {
|
||
return trackSortChanged(filterValue, previousValue);
|
||
} else if (filterType === 'date') {
|
||
return trackDateChanged(filterValue, previousValue);
|
||
} else if (filterType === 'view_mode') {
|
||
return trackViewModeChanged(filterValue, previousValue);
|
||
}
|
||
}, [trackSortChanged, trackDateChanged, trackViewModeChanged]);
|
||
|
||
/**
|
||
* 追踪概念股票列表查看
|
||
* @param {string} conceptName - 概念名称
|
||
* @param {number} stockCount - 股票数量
|
||
*/
|
||
const trackConceptStocksViewed = useCallback((conceptName, stockCount = 0) => {
|
||
track(RETENTION_EVENTS.CONCEPT_DETAIL_VIEWED, {
|
||
concept_name: conceptName,
|
||
stock_count: stockCount,
|
||
view_type: 'stocks_list',
|
||
source: 'concept_center',
|
||
});
|
||
|
||
logger.debug('useConceptEvents', '📈 Concept Stocks Viewed', {
|
||
conceptName,
|
||
stockCount,
|
||
});
|
||
}, [track]);
|
||
|
||
/**
|
||
* 追踪概念时间轴查看(别名函数)
|
||
* @alias trackConceptDetailViewed
|
||
*/
|
||
const trackConceptTimelineViewed = useCallback((conceptName, conceptId) => {
|
||
return trackConceptDetailViewed(conceptName, conceptId);
|
||
}, [trackConceptDetailViewed]);
|
||
|
||
/**
|
||
* 追踪分页变化(别名函数 - 不同时态)
|
||
* @alias trackPageChanged
|
||
*/
|
||
const trackPageChange = useCallback((page, filters = {}) => {
|
||
return trackPageChanged(page, filters);
|
||
}, [trackPageChanged]);
|
||
|
||
return {
|
||
// 原有函数
|
||
trackConceptListViewed,
|
||
trackSearchInitiated,
|
||
trackSearchQuerySubmitted,
|
||
trackSortChanged,
|
||
trackViewModeChanged,
|
||
trackDateChanged,
|
||
trackPageChanged,
|
||
trackConceptClicked,
|
||
trackConceptStockClicked,
|
||
trackConceptDetailViewed,
|
||
trackStockDetailViewed,
|
||
trackPaywallShown,
|
||
trackUpgradeClicked,
|
||
|
||
// 别名函数 - 为保持向后兼容性
|
||
trackConceptSearched,
|
||
trackFilterApplied,
|
||
trackConceptStocksViewed,
|
||
trackConceptTimelineViewed,
|
||
trackPageChange,
|
||
};
|
||
};
|