- 创建独立的会员服务模块 services/membership.ts,统一管理会员计划元数据和工具函数 - 新增 membershipSlice Redux状态管理,集中处理会员数据和状态 - 重构个人中心VIP会员卡片,支持动态显示会员计划和有效期 - 优化会员购买弹窗,使用统一的会员计划配置 - 改进会员数据获取流程,确保状态同步和一致性
133 lines
4.7 KiB
TypeScript
133 lines
4.7 KiB
TypeScript
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;
|
||
}
|