feat: 权限引导能力测试

This commit is contained in:
zdl
2025-10-22 15:23:36 +08:00
parent 433a982a20
commit a9fee411ea
3 changed files with 316 additions and 2 deletions

View File

@@ -12,7 +12,8 @@
*/
import React, { createContext, useContext, useState, useEffect, useCallback, useRef } from 'react';
import { useToast, Box, HStack, Text, Button, CloseButton } from '@chakra-ui/react';
import { useToast, Box, HStack, Text, Button, CloseButton, VStack, Icon } from '@chakra-ui/react';
import { BellIcon } from '@chakra-ui/icons';
import { logger } from '../utils/logger';
import socket, { SOCKET_TYPE } from '../services/socket';
import notificationSound from '../assets/sounds/notification.wav';
@@ -20,6 +21,7 @@ import { browserNotificationService } from '../services/browserNotificationServi
import { notificationMetricsService } from '../services/notificationMetricsService';
import { notificationHistoryService } from '../services/notificationHistoryService';
import { PRIORITY_LEVELS, NOTIFICATION_CONFIG, NOTIFICATION_TYPES } from '../constants/notificationTypes';
import { usePermissionGuide, GUIDE_TYPES } from '../hooks/usePermissionGuide';
// 连接状态枚举
const CONNECTION_STATUS = {
@@ -59,6 +61,9 @@ export const NotificationProvider = ({ children }) => {
const audioRef = useRef(null);
const reconnectedTimerRef = useRef(null); // 用于自动消失 RECONNECTED 状态
// ⚡ 使用权限引导管理 Hook
const { shouldShowGuide, markGuideAsShown } = usePermissionGuide();
// 初始化音频
useEffect(() => {
try {
@@ -160,6 +165,127 @@ export const NotificationProvider = ({ children }) => {
return permission;
}, [toast]);
/**
* ⚡ 显示权限引导(通用方法)
* @param {string} guideType - 引导类型
* @param {object} options - 引导选项
*/
const showPermissionGuide = useCallback((guideType, options = {}) => {
// 检查是否应该显示引导
if (!shouldShowGuide(guideType)) {
logger.debug('NotificationContext', 'Guide already shown, skipping', { guideType });
return;
}
// 检查权限状态:只在未授权时显示引导
if (browserPermission === 'granted') {
logger.debug('NotificationContext', 'Permission already granted, skipping guide', { guideType });
return;
}
// 默认选项
const {
title = '开启桌面通知',
description = '及时接收重要事件和股票提醒',
icon = true,
duration = 10000,
} = options;
// 显示引导 Toast
const toastId = `permission-guide-${guideType}`;
if (!toast.isActive(toastId)) {
toast({
id: toastId,
duration,
render: ({ onClose }) => (
<Box
p={4}
bg="blue.500"
color="white"
borderRadius="md"
boxShadow="lg"
maxW="400px"
>
<VStack spacing={3} align="stretch">
{icon && (
<HStack spacing={2}>
<Icon as={BellIcon} boxSize={5} />
<Text fontWeight="bold" fontSize="md">
{title}
</Text>
</HStack>
)}
<Text fontSize="sm" opacity={0.9}>
{description}
</Text>
<HStack spacing={2} justify="flex-end">
<Button
size="sm"
variant="ghost"
colorScheme="whiteAlpha"
onClick={() => {
onClose();
markGuideAsShown(guideType);
}}
>
稍后再说
</Button>
<Button
size="sm"
colorScheme="whiteAlpha"
bg="whiteAlpha.300"
_hover={{ bg: 'whiteAlpha.400' }}
onClick={async () => {
onClose();
markGuideAsShown(guideType);
await requestBrowserPermission();
}}
>
立即开启
</Button>
</HStack>
</VStack>
</Box>
),
});
logger.info('NotificationContext', 'Permission guide shown', { guideType });
}
}, [toast, shouldShowGuide, markGuideAsShown, browserPermission, requestBrowserPermission]);
/**
* ⚡ 显示欢迎引导(登录后)
*/
const showWelcomeGuide = useCallback(() => {
showPermissionGuide(GUIDE_TYPES.WELCOME, {
title: '🎉 欢迎使用价值前沿',
description: '开启桌面通知,第一时间接收重要投资事件和股票提醒',
duration: 12000,
});
}, [showPermissionGuide]);
/**
* ⚡ 显示社区功能引导
*/
const showCommunityGuide = useCallback(() => {
showPermissionGuide(GUIDE_TYPES.COMMUNITY, {
title: '关注感兴趣的事件',
description: '开启通知后,您关注的事件有新动态时会第一时间提醒您',
duration: 10000,
});
}, [showPermissionGuide]);
/**
* ⚡ 显示首次关注引导
*/
const showFirstFollowGuide = useCallback(() => {
showPermissionGuide(GUIDE_TYPES.FIRST_FOLLOW, {
title: '关注成功',
description: '开启桌面通知,事件有更新时我们会及时提醒您',
duration: 8000,
});
}, [showPermissionGuide]);
/**
* 发送浏览器通知
*/
@@ -626,6 +752,10 @@ export const NotificationProvider = ({ children }) => {
requestBrowserPermission,
trackNotificationClick,
retryConnection,
// ⚡ 新增:权限引导方法
showWelcomeGuide,
showCommunityGuide,
showFirstFollowGuide,
};
return (