/* eslint-disable react-hooks/exhaustive-deps */ import CustomCheckBox from '@/components/ui/CheckBox'; import { USER_AGREEMENT_URL } from '@/constants/Agree'; // import { useAuth } from '@/contexts/AuthContext'; // import { UserApi } from '@/services'; import { log, logger } from '@/utils/logger'; import { captureMessage, captureMessageWithContext, capturePurchaseEvent, captureUserAction } from '@/utils/sentry.utils'; import { Toast as GlobalToast } from '@/utils/toast.utils'; import { MaterialIcons } from '@expo/vector-icons'; import { captureException } from '@sentry/react-native'; import React, { useEffect, useRef, useState } from 'react'; import { ActivityIndicator, Alert, Dimensions, Linking, Modal, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; import Purchases, { CustomerInfo, PurchasesStoreProduct } from 'react-native-purchases'; const { height } = Dimensions.get('window'); interface MembershipModalProps { visible: boolean; onClose?: () => void; onPurchaseSuccess?: () => void; } interface MembershipPlan { id: string; fallbackTitle: string; subtitle: string; type: 'weekly' | 'quarterly' | 'lifetime'; recommended?: boolean; } const DEFAULT_PLANS: MembershipPlan[] = [ { id: 'com.anonymous.digitalpilates.membership.lifetime', fallbackTitle: '终身会员', subtitle: '一次投入,终身健康陪伴', type: 'lifetime', recommended: true, }, { id: 'com.anonymous.digitalpilates.membership.quarter', fallbackTitle: '季度会员', subtitle: '3个月蜕变计划,见证身材变化', type: 'quarterly', }, { id: 'com.anonymous.digitalpilates.membership.weekly', fallbackTitle: '周会员', subtitle: '7天体验,开启健康第一步', type: 'weekly', }, ]; export function MembershipModal({ visible, onClose, onPurchaseSuccess }: MembershipModalProps) { const [selectedProduct, setSelectedProduct] = useState(null); const [loading, setLoading] = useState(false); const [restoring, setRestoring] = useState(false); // const { user } = useAuth() // const { refreshUserInfo } = useAuth(); const [products, setProducts] = useState([]); // 协议同意状态 - 只需要一个状态 const [agreementAccepted, setAgreementAccepted] = useState(false); // 保存监听器引用,用于移除监听器 const purchaseListenerRef = useRef<((customerInfo: CustomerInfo) => void) | null>(null); // 根据选中的产品生成tips内容 const getTipsContent = (product: PurchasesStoreProduct | null): string => { if (!product) return ''; const plan = DEFAULT_PLANS.find(item => item.id === product.identifier); if (!plan) { return ''; } switch (plan.type) { case 'lifetime': return '终身陪伴,见证您的每一次健康蜕变'; case 'quarterly': return '3个月科学计划,让健康成为生活习惯'; case 'weekly': return '7天体验期,感受专业健康指导的力量'; default: return ''; } }; // useEffect(() => { // if (user) { // captureMessage('用户已登录,开始初始化 Purchases'); // initPurchases(); // } // }, [user]); // 初始化只需要执行一次 // 单独的 useEffect 来处理购买监听器,依赖 visible 状态 useEffect(() => { if (visible) { setupPurchaseListener(); setAgreementAccepted(false); initPurchases(); } else { removePurchaseListener(); setProducts([]); setSelectedProduct(null); setAgreementAccepted(false); setLoading(false); setRestoring(false); } // 组件卸载时确保移除监听器 return () => { removePurchaseListener(); log.info('MembershipModal 购买监听器已清理'); }; }, [visible]); // 依赖 visible 状态 const initPurchases = async () => { capturePurchaseEvent('init', '开始获取会员产品套餐'); try { // 添加延迟,确保 RevenueCat SDK 完全初始化 await new Promise(resolve => setTimeout(resolve, 500)); const offerings = await Purchases.getOfferings(); log.info('获取产品套餐', { offerings }); logger.info('获取产品套餐成功', { currentOffering: offerings.current?.identifier || null, availablePackagesCount: offerings.current?.availablePackages.length || 0, allOfferingsCount: Object.keys(offerings.all).length, }); const packages = offerings.current?.availablePackages ?? []; if (packages.length === 0) { log.warn('没有找到可用的产品套餐', { hasCurrentOffering: offerings.current !== null, packagesLength: offerings.current?.availablePackages.length || 0, }); logger.info('没有找到可用的产品套餐', { hasCurrentOffering: offerings.current !== null, packagesLength: offerings.current?.availablePackages.length || 0, }); setProducts([]); setSelectedProduct(null); return; } const matchedProducts = packages .map(pkg => pkg.product) .filter(product => DEFAULT_PLANS.some(plan => plan.id === product.identifier)); const orderedProducts = DEFAULT_PLANS .map(plan => matchedProducts.find(product => product.identifier === plan.id)) .filter((product): product is PurchasesStoreProduct => Boolean(product)); const fallbackProducts = packages.map(pkg => pkg.product); const productsToUse = orderedProducts.length > 0 ? orderedProducts : fallbackProducts; log.info('productsToUse', productsToUse) setProducts(productsToUse); // 获取产品后,检查用户的购买记录并自动选中对应套餐 await checkAndSelectActivePlan(productsToUse); setSelectedProduct(current => current ?? (productsToUse[0] ?? null)); } catch (e: any) { // 安全地处理错误对象,避免循环引用 const errorData = { message: e?.message || '未知错误', code: e?.code || null, name: e?.name || 'Error', // 只包含基本的错误信息,避免可能的循环引用 }; log.error('获取产品套餐失败', { error: errorData }); captureException(e); capturePurchaseEvent('error', '获取产品套餐失败', errorData); // 设置空状态,避免界面卡在加载状态 setProducts([]); setSelectedProduct(null); } }; // 添加购买状态监听器 const setupPurchaseListener = () => { log.info('设置购买监听器', { visible }); // 如果已经有监听器,先移除 if (purchaseListenerRef.current) { removePurchaseListener(); } // 创建监听器函数 const listener = (customerInfo: CustomerInfo) => { log.info('购买状态变化监听器触发', { customerInfo, visible }); // 检查是否有有效的购买记录 const hasActiveEntitlements = Object.keys(customerInfo.entitlements.active).length > 0; const hasNonSubscriptionTransactions = customerInfo.nonSubscriptionTransactions.length > 0; const hasActiveSubscriptions = Object.keys(customerInfo.activeSubscriptions).length > 0; if (hasActiveEntitlements || hasNonSubscriptionTransactions || hasActiveSubscriptions) { capturePurchaseEvent('success', '监听到购买状态变化', { hasActiveEntitlements, hasNonSubscriptionTransactions, hasActiveSubscriptions, activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length, nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length, activeSubscriptionsCount: Object.keys(customerInfo.activeSubscriptions).length, modalVisible: visible }); log.info('检测到购买成功,准备刷新用户信息并关闭弹窗'); // 延迟一点时间,确保购买流程完全完成 setTimeout(async () => { // 刷新用户信息 // await refreshUserInfo(); // 调用购买成功回调 onPurchaseSuccess?.(); // 关闭弹窗 onClose?.(); // 显示成功提示 GlobalToast.show({ message: '会员开通成功', }); }, 1000); } }; // 保存监听器引用 purchaseListenerRef.current = listener; // 添加监听器 Purchases.addCustomerInfoUpdateListener(listener); log.info('购买监听器已添加'); }; // 移除购买状态监听器 const removePurchaseListener = () => { if (purchaseListenerRef.current) { log.info('移除购买监听器'); Purchases.removeCustomerInfoUpdateListener(purchaseListenerRef.current); purchaseListenerRef.current = null; log.info('购买监听器已移除'); } }; // 检查用户的购买记录并自动选中对应套餐 const checkAndSelectActivePlan = async (availableProducts: PurchasesStoreProduct[]) => { try { captureUserAction('开始检查用户购买记录'); // 获取用户的购买信息 const customerInfo = await Purchases.getCustomerInfo(); log.info('获取用户购买信息', { customerInfo }); // 记录详细的购买状态日志 captureMessageWithContext('获取用户购买信息成功', { activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length, nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length, activeSubscriptionsCount: Object.keys(customerInfo.activeSubscriptions).length, originalAppUserId: customerInfo.originalAppUserId, firstSeen: customerInfo.firstSeen, originalPurchaseDate: customerInfo.originalPurchaseDate, latestExpirationDate: customerInfo.latestExpirationDate }); // 查找激活的产品ID let activePurchasedProductIds: string[] = []; // 检查权益 Object.keys(customerInfo.entitlements.active).forEach(key => { const entitlement = customerInfo.entitlements.active[key]; activePurchasedProductIds.push(entitlement.productIdentifier); log.debug(`激活的权益: ${key}, 产品ID: ${entitlement.productIdentifier}`); }); // 检查非订阅购买(如终身会员) customerInfo.nonSubscriptionTransactions.forEach(transaction => { activePurchasedProductIds.push(transaction.productIdentifier); log.debug(`非订阅购买: ${transaction.productIdentifier}, 购买时间: ${transaction.purchaseDate}`); }); // 检查订阅 Object.keys(customerInfo.activeSubscriptions).forEach(productId => { activePurchasedProductIds.push(productId); log.debug(`激活的订阅: ${productId}`); }); // 去重 activePurchasedProductIds = [...new Set(activePurchasedProductIds)]; captureMessageWithContext('用户激活的产品列表', { activePurchasedProductIds, activePurchasedProductCount: activePurchasedProductIds.length }); if (activePurchasedProductIds.length > 0) { // 尝试在可用产品中找到匹配的产品 let selectedProduct: PurchasesStoreProduct | null = null; // 优先级:终身会员 > 季度会员 > 周会员 const priorityOrder = DEFAULT_PLANS.map(plan => plan.id); // 按照优先级查找 for (const priorityProductId of priorityOrder) { if (activePurchasedProductIds.includes(priorityProductId)) { selectedProduct = availableProducts.find(product => product.identifier === priorityProductId) || null; if (selectedProduct) { log.info(`找到优先级最高的激活产品: ${priorityProductId}`); break; } } } // 如果按优先级没找到,尝试找到任何匹配的产品 if (!selectedProduct) { for (const productId of activePurchasedProductIds) { selectedProduct = availableProducts.find(product => product.identifier === productId) || null; if (selectedProduct) { log.info(`找到匹配的激活产品: ${productId}`); break; } } } if (selectedProduct) { setSelectedProduct(selectedProduct); captureMessageWithContext('自动选中用户已购买的套餐', { selectedProductId: selectedProduct.identifier, selectedProductTitle: selectedProduct.title, selectedProductPrice: selectedProduct.price, allActivePurchasedProductIds: activePurchasedProductIds }); } else { captureMessageWithContext('未找到匹配的可用产品', { activePurchasedProductIds, availableProductIds: availableProducts.map(p => p.identifier) }); log.warn('用户有激活的购买记录,但没有找到匹配的可用产品', { activePurchasedProductIds, availableProductIds: availableProducts.map(p => p.identifier) }); } } else { captureMessageWithContext('用户没有激活的购买记录', { hasEntitlements: Object.keys(customerInfo.entitlements.active).length > 0, hasNonSubscriptions: customerInfo.nonSubscriptionTransactions.length > 0, hasActiveSubscriptions: Object.keys(customerInfo.activeSubscriptions).length > 0 }); log.info('用户没有激活的购买记录,使用默认选择逻辑'); setSelectedProduct(availableProducts[0] ?? null); } } catch (error: any) { // 安全地处理错误对象,避免循环引用 const errorData = { message: error?.message || '未知错误', code: error?.code || null, name: error?.name || 'Error', }; log.error('检查用户购买记录失败', { error: errorData }); captureException(error); captureMessageWithContext('检查用户购买记录失败', errorData); } }; const handlePurchase = async () => { // 验证是否已同意协议 if (!agreementAccepted) { Alert.alert( '请阅读并同意相关协议', '购买前需要同意用户协议、会员协议和自动续费协议', [ { text: '确定', style: 'default', } ] ); return; } // 验证是否选择了产品 if (!selectedProduct) { Alert.alert( '请选择会员套餐', '', [ { text: '确定', style: 'default', } ] ); return; } // 防止重复点击 if (loading) { return; } try { // 设置加载状态 setLoading(true); // 记录购买开始事件 capturePurchaseEvent('init', `开始购买: ${selectedProduct.identifier}`, { productIdentifier: selectedProduct.identifier, productTitle: selectedProduct.title, productPrice: selectedProduct.price }); // 执行购买 const { customerInfo, productIdentifier } = await Purchases.purchaseStoreProduct(selectedProduct); log.info('购买成功', { customerInfo, productIdentifier }); // 记录购买成功事件 capturePurchaseEvent('success', `购买成功: ${productIdentifier}`, { productIdentifier, hasActiveEntitlements: Object.keys(customerInfo.entitlements.active).length > 0, activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length, nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length, activeSubscriptionsCount: Object.keys(customerInfo.activeSubscriptions).length }); // 购买成功后,监听器会自动处理后续逻辑(刷新用户信息、关闭弹窗等) log.info('购买流程完成,等待监听器处理后续逻辑'); } catch (error: any) { captureException(error); // 记录购买失败事件 capturePurchaseEvent('error', `购买失败: ${error.message || '未知错误'}`, { errorCode: error.code || null, errorMessage: error.message || '未知错误', productIdentifier: selectedProduct.identifier }); // 处理不同类型的购买错误 if (error.code === 1 || error.code === 'USER_CANCELLED') { // 用户取消购买 GlobalToast.show({ message: '购买已取消', }); } else if (error.code === 'ITEM_ALREADY_OWNED' || error.code === 'PRODUCT_ALREADY_PURCHASED') { // 商品已拥有 GlobalToast.show({ message: '您已拥有此商品', }); } else if (error.code === 'NETWORK_ERROR') { // 网络错误 GlobalToast.show({ message: '网络连接失败', }); } else if (error.code === 'PAYMENT_PENDING') { // 支付待处理 GlobalToast.show({ message: '支付正在处理中', }); } else if (error.code === 'INVALID_CREDENTIALS') { // 凭据无效 GlobalToast.show({ message: '账户验证失败', }); } else { // 其他错误 GlobalToast.show({ message: '购买失败', }); } } finally { // 确保在所有情况下都重置加载状态 setLoading(false); log.info('购买流程结束,加载状态已重置'); } }; const handleRestore = async () => { // 防止重复点击 if (restoring || loading) { return; } try { setRestoring(true); captureUserAction('开始恢复购买'); // 恢复购买 const customerInfo = await Purchases.restorePurchases(); log.info('恢复购买结果', { customerInfo }); captureMessageWithContext('恢复购买结果', { activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length, nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length, activeSubscriptionsCount: Object.keys(customerInfo.activeSubscriptions).length, managementUrl: customerInfo.managementURL, originalAppUserId: customerInfo.originalAppUserId }); // 检查是否有有效的购买记录 const hasActiveEntitlements = Object.keys(customerInfo.entitlements.active).length > 0; const hasNonSubscriptionTransactions = customerInfo.nonSubscriptionTransactions.length > 0; const hasActiveSubscriptions = Object.keys(customerInfo.activeSubscriptions).length > 0; if (hasActiveEntitlements || hasNonSubscriptionTransactions || hasActiveSubscriptions) { // 检查具体的购买内容 let restoredProducts: string[] = []; // 检查权益 Object.keys(customerInfo.entitlements.active).forEach(key => { const entitlement = customerInfo.entitlements.active[key]; restoredProducts.push(entitlement.productIdentifier); }); // 检查非订阅购买(如终身会员) customerInfo.nonSubscriptionTransactions.forEach(transaction => { restoredProducts.push(transaction.productIdentifier); }); // 检查订阅 Object.keys(customerInfo.activeSubscriptions).forEach(productId => { restoredProducts.push(productId); }); log.info('恢复的产品', { restoredProducts }); capturePurchaseEvent('restore', '恢复购买成功', { restoredProducts, restoredProductsCount: restoredProducts.length }); try { // 调用后台服务接口进行票据匹配 captureUserAction('开始调用后台恢复购买接口'); // const restoreResponse = await UserApi.restorePurchase({ // customerInfo: { // originalAppUserId: customerInfo.originalAppUserId, // activeEntitlements: customerInfo.entitlements.active, // nonSubscriptionTransactions: customerInfo.nonSubscriptionTransactions, // activeSubscriptions: customerInfo.activeSubscriptions, // restoredProducts // } // }); // log.debug('后台恢复购买响应', { restoreResponse }); // captureMessageWithContext('后台恢复购买成功', { // responseData: restoreResponse, // restoredProductsCount: restoredProducts.length // }); // 刷新用户信息 // await refreshUserInfo(); // 调用购买成功回调 onPurchaseSuccess?.(); // 关闭弹窗 onClose?.(); GlobalToast.show({ message: '恢复购买成功', }); } catch (apiError: any) { // 安全地处理错误对象,避免循环引用 const errorData = { message: apiError?.message || '未知错误', code: apiError?.code || null, name: apiError?.name || 'Error', restoredProductsCount: restoredProducts.length }; log.error('后台恢复购买接口调用失败', { error: errorData }); captureException(apiError); captureMessageWithContext('后台恢复购买接口失败', errorData); // 即使后台接口失败,也显示恢复成功(因为 RevenueCat 已经确认有购买记录) // 但不关闭弹窗,让用户知道可能需要重试 GlobalToast.show({ message: '恢复购买部分失败', }); } } else { capturePurchaseEvent('restore', '没有找到购买记录', { hasActiveEntitlements, hasNonSubscriptionTransactions, hasActiveSubscriptions, activeEntitlementsCount: Object.keys(customerInfo.entitlements.active).length, nonSubscriptionTransactionsCount: customerInfo.nonSubscriptionTransactions.length, activeSubscriptionsCount: Object.keys(customerInfo.activeSubscriptions).length }); GlobalToast.show({ message: '没有找到购买记录', }); } } catch (error: any) { // 安全地处理错误对象,避免循环引用 const errorData = { message: error?.message || '未知错误', code: error?.code || null, name: error?.name || 'Error', }; log.error('恢复购买失败', { error: errorData }); captureException(error); // 记录恢复购买失败事件 capturePurchaseEvent('error', `恢复购买失败: ${errorData.message}`, errorData); // 处理特定的恢复购买错误 if (error.code === 'RESTORE_CANCELLED' || error.code === 'USER_CANCELLED') { GlobalToast.show({ message: '恢复购买已取消', }); } else if (error.code === 'NETWORK_ERROR') { GlobalToast.show({ message: '网络错误', }); } else if (error.code === 'INVALID_CREDENTIALS') { GlobalToast.show({ message: '账户验证失败', }); } else { GlobalToast.show({ message: '恢复购买失败', }); } } finally { // 确保在所有情况下都重置恢复状态 setRestoring(false); log.info('恢复购买流程结束,恢复状态已重置'); } }; const renderMembershipBenefits = () => ( 解锁全部健康功能 开启您的健康蜕变之旅 高级营养分析,精准卡路里计算 定制化减脂计划,科学体重管理 深度健康数据分析,洞察身体变化 {/* 皇冠图标 */} {/* */} ); const renderPlanCard = (product: PurchasesStoreProduct) => { const plan = DEFAULT_PLANS.find(p => p.id === product.identifier); if (!plan) { return null; } const isSelected = selectedProduct === product; const displayTitle = product.title || plan.fallbackTitle; const priceLabel = product.priceString || ''; return ( !loading && product && setSelectedProduct(product)} disabled={loading} activeOpacity={loading ? 1 : 0.8} accessible={true} accessibilityLabel={`${displayTitle} ${priceLabel}`} accessibilityHint={loading ? '购买进行中,无法切换套餐' : `选择${displayTitle}套餐`} accessibilityState={{ disabled: loading, selected: isSelected }} > {plan.recommended && ( 推荐 )} {displayTitle} {priceLabel || '--'} {plan.subtitle} ); }; return ( {/* 半透明背景 */} {/* 会员内容 */} {/* 关闭按钮 */} {/* × */} {/* 会员权益介绍 */} {renderMembershipBenefits()} {/* 会员套餐选择 */} {products.length === 0 && ( 暂未获取到会员商品,请在 RevenueCat 中配置 iOS 产品并同步到当前 Offering。 )} {products.map(renderPlanCard)} {/* 产品选择提示区域 */} {selectedProduct && ( {getTipsContent(selectedProduct)} )} {/* 协议同意区域 */} 我已阅读并同意 { Linking.openURL(USER_AGREEMENT_URL); captureMessage('click user agreement'); }}> 《用户协议》 | { // Linking.openURL(MEMBERSHIP_AGREEMENT_URL); captureMessage('click membership agreement'); }}> 《会员协议》 | { // Linking.openURL(AUTO_RENEWAL_AGREEMENT_URL); captureMessage('click auto renewal agreement'); }}> 《自动续费协议》 {/* 购买按钮 */} {loading ? ( 正在处理购买... ) : ( 开启健康蜕变 )} {/* 恢复购买按钮 */} {restoring ? ( 恢复中... ) : ( 恢复购买 )} ); } const styles = StyleSheet.create({ overlay: { flex: 1, justifyContent: 'flex-end', }, backdrop: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(0, 0, 0, 0.3)', }, modalContainer: { height: height * 0.6, backgroundColor: 'white', borderTopLeftRadius: 20, borderTopRightRadius: 20, overflow: 'hidden', }, modalContent: { flex: 1, paddingHorizontal: 20, paddingTop: 20, }, closeButton: { position: 'absolute', top: 0, right: 0, width: 30, height: 30, borderRadius: 15, backgroundColor: 'rgba(0, 0, 0, 0.1)', justifyContent: 'center', alignItems: 'center', zIndex: 1, }, closeButtonText: { fontSize: 18, color: '#666', fontWeight: '300', }, configurationNotice: { backgroundColor: '#FFF9E6', borderRadius: 12, padding: 16, marginTop: 30, marginBottom: 20, alignItems: 'center', borderWidth: 1, borderColor: '#FFE4B5', }, configurationText: { fontSize: 14, color: '#B8860B', textAlign: 'center', marginTop: 8, marginBottom: 12, }, configurationButton: { backgroundColor: '#FF9500', borderRadius: 8, paddingHorizontal: 16, paddingVertical: 8, }, configurationButtonText: { color: 'white', fontSize: 12, fontWeight: '600', }, benefitsContainer: { position: 'relative', backgroundColor: '#FFE7F9', borderRadius: 16, marginBottom: 30, padding: 20, }, benefitsTitleContainer: { alignItems: 'center', marginBottom: 20, }, benefitsTitle: { fontSize: 18, fontWeight: 'bold', color: '#333', marginBottom: 5, }, benefitsSubtitle: { fontSize: 14, color: '#666', textAlign: 'center', }, benefitsTitleBg: { width: 180, height: 20, marginBottom: 10, }, benefitItem: { flexDirection: 'row', alignItems: 'center', marginTop: 10, }, benefitText: { fontSize: 14, color: '#333', marginLeft: 8, fontWeight: '500', }, crownContainer: { position: 'absolute', top: 10, right: 10, width: 100, height: 100, justifyContent: 'center', alignItems: 'center', }, crownIcon: { width: 80, height: 80, resizeMode: 'contain', }, plansContainer: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 20, }, planCard: { flex: 1, marginHorizontal: 4, borderRadius: 12, borderWidth: 2, borderColor: '#E0E0E0', paddingVertical: 20, paddingHorizontal: 12, alignItems: 'center', position: 'relative', backgroundColor: 'white', }, selectedPlan: { borderColor: '#DF42D0', backgroundColor: '#FFF5FE', }, recommendedBadge: { position: 'absolute', top: -10, backgroundColor: '#7B2CBF', borderRadius: 10, paddingHorizontal: 12, paddingVertical: 4, }, recommendedText: { color: 'white', fontSize: 10, fontWeight: 'bold', }, planHeader: { alignItems: 'center', marginBottom: 8, }, planTitle: { fontSize: 16, fontWeight: '600', color: '#333', }, lifetimePlanTitle: { color: '#7B2CBF', }, quarterlyPlanTitle: { color: '#DF42D0', }, weeklyPlanTitle: { color: '#FF9500', }, planPricing: { alignItems: 'center', marginBottom: 8, }, planPrice: { fontSize: 24, fontWeight: 'bold', color: '#333', }, lifetimePlanPrice: { color: '#7B2CBF', }, quarterlyPlanPrice: { color: '#DF42D0', }, weeklyPlanPrice: { color: '#FF9500', }, planSubtitle: { fontSize: 12, color: '#666', textAlign: 'center', lineHeight: 16, }, purchaseButton: { backgroundColor: '#DF42D0', borderRadius: 25, height: 50, justifyContent: 'center', alignItems: 'center', marginBottom: 15, marginTop: 10, shadowColor: '#DF42D0', shadowOffset: { width: 0, height: 4, }, shadowOpacity: 0.3, shadowRadius: 8, elevation: 6, }, disabledButton: { backgroundColor: '#ccc', shadowOpacity: 0, elevation: 0, }, purchaseButtonText: { color: 'white', fontSize: 18, fontWeight: '600', }, restoreButton: { backgroundColor: 'transparent', borderRadius: 25, height: 50, justifyContent: 'center', alignItems: 'center', marginBottom: 20, }, restoreButtonText: { color: '#666', fontSize: 16, fontWeight: '500', }, disabledRestoreButton: { opacity: 0.5, }, restoreButtonContent: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }, restoreButtonLoader: { marginRight: 8, }, loadingContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }, loadingSpinner: { marginRight: 8, }, disabledPlanCard: { opacity: 0.5, }, agreementRow: { width: '100%', marginTop: 6, borderRadius: 12, display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }, agreementPrefix: { fontSize: 10, color: '#333', marginRight: 4, }, agreementLink: { fontSize: 10, color: '#E91E63', textDecorationLine: 'underline', fontWeight: '500', }, agreementSeparator: { fontSize: 10, color: '#666', marginHorizontal: 2, }, tipsContainer: { borderRadius: 8, }, tipsText: { fontSize: 12, color: '#666', lineHeight: 18, textAlign: 'center', }, });