feat(vip): 实现VIP服务权限控制和食物识别功能限制

- 添加VIP服务权限检查hook,支持免费使用次数限制
- 为食物识别功能添加登录验证和VIP权限检查
- 优化RevenueCat用户标识同步逻辑
- 修复会员购买状态检查的类型安全问题
- 为营养成分分析添加登录验证
This commit is contained in:
richarjiang
2025-10-29 09:44:30 +08:00
parent eaa7f7275c
commit fcf1be211f
5 changed files with 196 additions and 15 deletions

91
hooks/useVipService.ts Normal file
View File

@@ -0,0 +1,91 @@
import { useAppSelector } from '@/hooks/redux';
import { selectUserProfile } from '@/store/userSlice';
import { useCallback } from 'react';
/**
* 增值服务检查结果
*/
export interface VipServiceResult {
/** 是否可以使用服务 */
canUseService: boolean;
/** 是否是 VIP 用户 */
isVip: boolean;
/** 剩余免费使用次数 */
remainingFreeUsage: number;
/** 最大免费使用次数 */
maxFreeUsage: number;
/** 是否需要显示会员付费弹窗 */
shouldShowMembershipModal: boolean;
}
/**
* VIP 增值服务 Hook
* 用于检查用户是否可以使用增值服务
*/
export function useVipService() {
const userProfile = useAppSelector(selectUserProfile);
/**
* 检查用户是否可以使用增值服务
* @returns 检查结果
*/
const checkServiceAccess = useCallback((): VipServiceResult => {
const isVip = userProfile?.isVip ?? false;
const freeUsageCount = userProfile?.freeUsageCount ?? 0;
const maxUsageCount = userProfile?.maxUsageCount ?? 5;
console.log('userProfile', userProfile);
// VIP 用户可以使用所有服务
if (isVip) {
return {
canUseService: true,
isVip: true,
remainingFreeUsage: 0, // VIP 用户不关心免费次数
maxFreeUsage: 0,
shouldShowMembershipModal: false,
};
}
// 计算剩余免费使用次数
const canUseService = freeUsageCount > 0;
return {
canUseService,
isVip: false,
remainingFreeUsage: freeUsageCount,
maxFreeUsage: maxUsageCount,
shouldShowMembershipModal: !canUseService,
};
}, [userProfile]);
/**
* 检查并处理服务访问
* @param onAllowed 当允许使用时的回调函数
* @param onBlocked 当阻止使用时的回调函数(可选)
* @returns 是否可以继续使用服务
*/
const handleServiceAccess = useCallback((
onAllowed: () => void,
onBlocked?: () => void
): boolean => {
const result = checkServiceAccess();
if (result.canUseService) {
onAllowed();
return true;
} else {
onBlocked?.();
return false;
}
}, [checkServiceAccess]);
return {
checkServiceAccess,
handleServiceAccess,
isVip: userProfile?.isVip ?? false,
freeUsageCount: userProfile?.freeUsageCount ?? 0,
maxUsageCount: userProfile?.maxUsageCount ?? 5,
};
}