Files
digital-pilates/contexts/MembershipModalContext.tsx
richarjiang 7cd290d341 feat(membership): 重构会员系统架构并优化VIP卡片显示
- 创建独立的会员服务模块 services/membership.ts,统一管理会员计划元数据和工具函数
- 新增 membershipSlice Redux状态管理,集中处理会员数据和状态
- 重构个人中心VIP会员卡片,支持动态显示会员计划和有效期
- 优化会员购买弹窗,使用统一的会员计划配置
- 改进会员数据获取流程,确保状态同步和一致性
2025-10-29 16:08:58 +08:00

133 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import Purchases from 'react-native-purchases';
import { MembershipModal } from '@/components/model/MembershipModal';
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { fetchMembershipData } from '@/store/membershipSlice';
import { selectUserProfile } from '@/store/userSlice';
import { logger } from '@/utils/logger';
type MembershipModalOptions = {
onPurchaseSuccess?: () => void;
};
interface MembershipModalContextValue {
openMembershipModal: (options?: MembershipModalOptions) => void;
closeMembershipModal: () => void;
}
const MembershipModalContext = createContext<MembershipModalContextValue | null>(null);
export function MembershipModalProvider({ children }: { children: React.ReactNode }) {
const dispatch = useAppDispatch();
const [visible, setVisible] = useState(false);
const [pendingSuccessCallback, setPendingSuccessCallback] = useState<(() => void) | undefined>();
const [isInitialized, setIsInitialized] = useState(false);
// 获取用户信息用于RevenueCat用户标识
const userProfile = useAppSelector(selectUserProfile);
useEffect(() => {
// 直接使用生产环境的 API Key避免环境变量问题
const iosApiKey = 'appl_lmVvuLWFlXlrEsnvxMzTnKapqcc';
const initializeRevenueCat = async () => {
try {
// 检查是否已经配置过,避免重复配置
if (!isInitialized) {
// 如果有用户ID在配置时传入用户标识
const configOptions: any = { apiKey: iosApiKey };
if (userProfile?.id) {
configOptions.appUserID = userProfile.id;
logger.info('[MembershipModalProvider] RevenueCat SDK 初始化使用用户ID:', userProfile.id);
} else {
logger.info('[MembershipModalProvider] RevenueCat SDK 初始化未设置用户ID');
}
await Purchases.configure(configOptions);
setIsInitialized(true);
logger.info('[MembershipModalProvider] RevenueCat SDK 初始化成功');
dispatch(fetchMembershipData());
}
} catch (error) {
logger.error('[MembershipModalProvider] RevenueCat SDK 初始化失败:', error);
// 初始化失败时不阻止应用正常运行
}
};
initializeRevenueCat();
}, [dispatch, isInitialized, userProfile?.id]);
// 监听用户登录状态变化在用户登录后更新RevenueCat的用户标识
useEffect(() => {
const updateRevenueCatUser = async () => {
if (isInitialized && userProfile?.id) {
try {
// 检查当前RevenueCat的用户标识
const customerInfo = await Purchases.getCustomerInfo();
const currentAppUserID = customerInfo.originalAppUserId;
// 如果当前用户ID与RevenueCat中的用户ID不同则更新
if (currentAppUserID !== userProfile.id) {
console.log('[MembershipModalProvider] 更新RevenueCat用户标识:', userProfile.id);
await Purchases.logIn(userProfile.id);
}
dispatch(fetchMembershipData());
} catch (error) {
console.error('[MembershipModalProvider] 更新RevenueCat用户标识失败:', error);
}
} else if (isInitialized && !userProfile?.id) {
dispatch(fetchMembershipData());
}
};
updateRevenueCatUser();
}, [dispatch, userProfile?.id, isInitialized]);
const openMembershipModal = useCallback((options?: MembershipModalOptions) => {
setPendingSuccessCallback(() => options?.onPurchaseSuccess);
setVisible(true);
}, []);
const closeMembershipModal = useCallback(() => {
setVisible(false);
setPendingSuccessCallback(undefined);
}, []);
const handlePurchaseSuccess = useCallback(() => {
pendingSuccessCallback?.();
}, [pendingSuccessCallback]);
const contextValue = useMemo(
() => ({
openMembershipModal,
closeMembershipModal,
}),
[closeMembershipModal, openMembershipModal],
);
return (
<MembershipModalContext.Provider value={contextValue}>
{children}
<MembershipModal
visible={visible}
onClose={closeMembershipModal}
onPurchaseSuccess={handlePurchaseSuccess}
/>
</MembershipModalContext.Provider>
);
}
export function useMembershipModal(): MembershipModalContextValue {
const context = useContext(MembershipModalContext);
if (!context) {
logger.error('useMembershipModal must be used within a MembershipModalProvider');
// 抛出错误而不是返回 undefined确保类型安全
throw new Error('useMembershipModal must be used within a MembershipModalProvider');
}
return context;
}