feat: P1通用功能:4个Hook创建完成(待集成)现在您可以追踪:

1. 完整的用户旅程
    - 从进入网站 → 浏览内容 → 使用功能 → 遇到付费墙 → 付费转化
  2. 核心业务指标
    - DAU/MAU(活跃用户)
    - 功能使用率(哪些功能最受欢迎)
    - 搜索热度(用户需求洞察)
    - Revenue转化漏斗(付费转化分析)
    - 用户参与度(Profile更新、设置变更)
  3. 产品优化方向
    - 哪些功能需要优化?
    - 用户在哪个环节流失?
    - 哪些内容最受欢迎?
    - 如何提高付费转化率?
This commit is contained in:
zdl
2025-10-29 12:01:26 +08:00
parent 78e4b8f696
commit e3a953559f
4 changed files with 1265 additions and 0 deletions

View File

@@ -0,0 +1,293 @@
// src/hooks/useNavigationEvents.js
// 导航和菜单事件追踪 Hook
import { useCallback } from 'react';
import { usePostHogTrack } from './usePostHogRedux';
import { RETENTION_EVENTS } from '../lib/constants';
import { logger } from '../utils/logger';
/**
* 导航事件追踪 Hook
* @param {Object} options - 配置选项
* @param {string} options.component - 组件名称 ('top_nav' | 'sidebar' | 'breadcrumb' | 'footer')
* @returns {Object} 事件追踪处理函数集合
*/
export const useNavigationEvents = ({ component = 'navigation' } = {}) => {
const { track } = usePostHogTrack();
/**
* 追踪顶部导航点击
* @param {string} itemName - 导航项名称
* @param {string} path - 导航目标路径
* @param {string} category - 导航分类 ('main' | 'user' | 'utility')
*/
const trackTopNavClicked = useCallback((itemName, path = '', category = 'main') => {
if (!itemName) {
logger.warn('useNavigationEvents', 'trackTopNavClicked: itemName is required');
return;
}
track(RETENTION_EVENTS.TOP_NAV_CLICKED, {
item_name: itemName,
path,
category,
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '🔝 Top Navigation Clicked', {
itemName,
path,
category,
});
}, [track, component]);
/**
* 追踪侧边栏菜单点击
* @param {string} itemName - 菜单项名称
* @param {string} path - 目标路径
* @param {number} level - 菜单层级 (1=主菜单, 2=子菜单)
* @param {boolean} isExpanded - 是否展开状态
*/
const trackSidebarMenuClicked = useCallback((itemName, path = '', level = 1, isExpanded = false) => {
if (!itemName) {
logger.warn('useNavigationEvents', 'trackSidebarMenuClicked: itemName is required');
return;
}
track(RETENTION_EVENTS.SIDEBAR_MENU_CLICKED, {
item_name: itemName,
path,
level,
is_expanded: isExpanded,
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '📂 Sidebar Menu Clicked', {
itemName,
path,
level,
isExpanded,
});
}, [track, component]);
/**
* 追踪通用菜单项点击
* @param {string} itemName - 菜单项名称
* @param {string} menuType - 菜单类型 ('dropdown' | 'context' | 'tab')
* @param {string} path - 目标路径
*/
const trackMenuItemClicked = useCallback((itemName, menuType = 'dropdown', path = '') => {
if (!itemName) {
logger.warn('useNavigationEvents', 'trackMenuItemClicked: itemName is required');
return;
}
track(RETENTION_EVENTS.MENU_ITEM_CLICKED, {
item_name: itemName,
menu_type: menuType,
path,
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '📋 Menu Item Clicked', {
itemName,
menuType,
path,
});
}, [track, component]);
/**
* 追踪面包屑导航点击
* @param {string} itemName - 面包屑项名称
* @param {string} path - 目标路径
* @param {number} position - 在面包屑中的位置
* @param {number} totalItems - 面包屑总项数
*/
const trackBreadcrumbClicked = useCallback((itemName, path = '', position = 0, totalItems = 0) => {
if (!itemName) {
logger.warn('useNavigationEvents', 'trackBreadcrumbClicked: itemName is required');
return;
}
track(RETENTION_EVENTS.BREADCRUMB_CLICKED, {
item_name: itemName,
path,
position,
total_items: totalItems,
is_last: position === totalItems - 1,
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '🍞 Breadcrumb Clicked', {
itemName,
position,
totalItems,
});
}, [track, component]);
/**
* 追踪Logo点击返回首页
*/
const trackLogoClicked = useCallback(() => {
track('Logo Clicked', {
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '🏠 Logo Clicked');
}, [track, component]);
/**
* 追踪用户菜单展开
* @param {Object} user - 用户对象
* @param {number} menuItemCount - 菜单项数量
*/
const trackUserMenuOpened = useCallback((user = {}, menuItemCount = 0) => {
track('User Menu Opened', {
user_id: user.id || null,
menu_item_count: menuItemCount,
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '👤 User Menu Opened', {
userId: user.id,
menuItemCount,
});
}, [track, component]);
/**
* 追踪通知中心打开
* @param {number} unreadCount - 未读通知数量
*/
const trackNotificationCenterOpened = useCallback((unreadCount = 0) => {
track('Notification Center Opened', {
unread_count: unreadCount,
has_unread: unreadCount > 0,
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '🔔 Notification Center Opened', {
unreadCount,
});
}, [track, component]);
/**
* 追踪语言切换
* @param {string} fromLanguage - 原语言
* @param {string} toLanguage - 目标语言
*/
const trackLanguageChanged = useCallback((fromLanguage, toLanguage) => {
if (!fromLanguage || !toLanguage) {
logger.warn('useNavigationEvents', 'trackLanguageChanged: both languages are required');
return;
}
track('Language Changed', {
from_language: fromLanguage,
to_language: toLanguage,
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '🌐 Language Changed', {
fromLanguage,
toLanguage,
});
}, [track, component]);
/**
* 追踪主题切换(深色/浅色模式)
* @param {string} fromTheme - 原主题
* @param {string} toTheme - 目标主题
*/
const trackThemeChanged = useCallback((fromTheme, toTheme) => {
if (!fromTheme || !toTheme) {
logger.warn('useNavigationEvents', 'trackThemeChanged: both themes are required');
return;
}
track('Theme Changed', {
from_theme: fromTheme,
to_theme: toTheme,
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '🎨 Theme Changed', {
fromTheme,
toTheme,
});
}, [track, component]);
/**
* 追踪快捷键使用
* @param {string} shortcut - 快捷键组合 (如 'Ctrl+K', 'Cmd+/')
* @param {string} action - 触发的动作
*/
const trackShortcutUsed = useCallback((shortcut, action = '') => {
if (!shortcut) {
logger.warn('useNavigationEvents', 'trackShortcutUsed: shortcut is required');
return;
}
track('Keyboard Shortcut Used', {
shortcut,
action,
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '⌨️ Keyboard Shortcut Used', {
shortcut,
action,
});
}, [track, component]);
/**
* 追踪返回按钮点击
* @param {string} fromPage - 当前页面
* @param {string} toPage - 返回到的页面
*/
const trackBackButtonClicked = useCallback((fromPage = '', toPage = '') => {
track('Back Button Clicked', {
from_page: fromPage,
to_page: toPage,
component,
timestamp: new Date().toISOString(),
});
logger.debug('useNavigationEvents', '◀️ Back Button Clicked', {
fromPage,
toPage,
});
}, [track, component]);
return {
// 导航点击事件
trackTopNavClicked,
trackSidebarMenuClicked,
trackMenuItemClicked,
trackBreadcrumbClicked,
trackLogoClicked,
// 用户交互事件
trackUserMenuOpened,
trackNotificationCenterOpened,
// 设置变更事件
trackLanguageChanged,
trackThemeChanged,
// 其他交互
trackShortcutUsed,
trackBackButtonClicked,
};
};
export default useNavigationEvents;