import { useState, useEffect, useRef } from 'react' import { View, Text, StyleSheet, ScrollView, Pressable, StatusBar as RNStatusBar, Platform, useWindowDimensions, ActivityIndicator, } from 'react-native' import { StatusBar } from 'expo-status-bar' import { LinearGradient } from 'expo-linear-gradient' import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context' import { useRouter } from 'expo-router' import { useTranslation } from 'react-i18next' import { Image } from 'expo-image' import Carousel from 'react-native-reanimated-carousel' import Svg, { Path, Defs, LinearGradient as SvgLinearGradient, Stop } from 'react-native-svg' import { CheckIcon, LeftArrowIcon, OmitIcon, UncheckedIcon, TermsIcon, PrivacyIcon } from '@/components/icon' import { CheckMarkIcon } from '@/components/icon/checkMark' import PointsDrawer from '@/components/drawer/PointsDrawer' import Dropdown from '@/components/ui/dropdown' import GradientText from '@/components/GradientText' import { useMembership } from '@/hooks/use-membership' import { useActivates } from '@/hooks/use-activates' // 使用唯一 id 的 PointsIcon,避免与其他页面的图标 id 冲突 const MembershipPointsIcon = () => { const gradientId = 'paint0_linear_membership' return ( ) } type PlanType = 'plus' | 'pro' | 'plus-premium' interface Plan { id: PlanType name: string price: number recommended?: boolean points: number // 每月积分 currency: string // 货币类型 featureList: string[] // 功能列表(翻译 key) } // 货币符号转换函数 function toUnit(currency: string): string { switch (currency.toLowerCase()) { case 'hkd': return 'HK$' case 'cny': return '¥' default: return '$' } } export default function MembershipScreen() { const router = useRouter() const insets = useSafeAreaInsets() const { width: screenWidth } = useWindowDimensions() const [agreed, setAgreed] = useState(true) const [pointsDrawerVisible, setPointsDrawerVisible] = useState(false) const [isSubscribing, setIsSubscribing] = useState(false) const { t } = useTranslation() // 使用 useMembership hook const { creditPlans, creditBalance, selectedPlanIndex, setSelectedPlanIndex, isLoadingSubscriptions, isStripePricingLoading, createSubscription, upgradeSubscription, restoreSubscription, rechargeToken, activeAuthSubscription, hasActiveSubscription, stripePricingData, } = useMembership() // 使用 useActivates hook 获取广告数据 const { load: loadActivates, data: activatesData } = useActivates() // 映射 API 数据到 UI 格式 const plans: Plan[] = creditPlans.map((plan, index) => ({ id: `plan-${index}` as PlanType, name: plan.name, price: plan.amountInCents / 100, recommended: plan.popular, points: plan.credits, currency: plan.currency, featureList: plan.featureList, })) const selectedPlan = plans[selectedPlanIndex] || plans[0] // 下拉菜单选项 const menuOptions = [ { label: t('membership.terms'), value: 'terms' }, { label: t('membership.privacy'), value: 'privacy' }, ] // 处理菜单选择 const handleMenuSelect = (value: string) => { if (value === 'terms') { router.push('/terms') } else if (value === 'privacy') { router.push('/privacy') } } // 轮播图相关 - 使用动态广告数据 const activities = activatesData?.activities || [] const [currentImageIndex, setCurrentImageIndex] = useState(0) // 加载广告数据 useEffect(() => { loadActivates() }, []) // 处理订阅按钮点击 const handleSubscribe = async () => { if (!agreed || !selectedPlan) return const planData = creditPlans[selectedPlanIndex] if (!planData) return setIsSubscribing(true) try { if (hasActiveSubscription) { await upgradeSubscription({ credits: planData.credits }) } else if (activeAuthSubscription?.cancelAtPeriodEnd) { await restoreSubscription() } else { const pricingItem = stripePricingData?.pricing_table_items?.[selectedPlanIndex] if (pricingItem) { await createSubscription({ priceId: pricingItem.price_id, productId: pricingItem.product_id, }) } } } finally { setIsSubscribing(false) } } // 获取当前选中计划的信息 const currentPlan = selectedPlan // 计算进度条百分比:当前计划积分 / 最高计划积分 const maxPoints = plans.length > 0 ? Math.max(...plans.map(plan => plan.points)) : 1 const progressPercentage = currentPlan?.points ? (currentPlan.points / maxPoints) * 100 : 0 // 加载状态 if (isStripePricingLoading || creditPlans.length === 0) { return ( ) } return ( {/* 顶部导航栏 - 固定在顶部 */} router.back()} > setPointsDrawerVisible(true)} > {t('membership.myPoints')} {creditBalance} handleMenuSelect(value)} offsetTop={10} renderTrigger={(selectedOption, isOpen, toggle) => ( )} dropdownStyle={styles.menuDropdown} renderOption={(option, isSelected) => ( {option.value === 'terms' ? ( ) : ( )} {option.label} )} /> {/* 只在有广告数据时显示轮播图 */} {activities.length > 0 && ( <> ( router.push(item.link as any)} style={{ width: screenWidth, height: screenWidth / 1.1 }} > )} autoPlay autoPlayInterval={2000} loop onSnapToItem={(index) => setCurrentImageIndex(index)} enabled={false} windowSize={1} mode="parallax" /> {activities.map((_, index) => ( ))} )} {/* 订阅计划标题 */} {t('membership.subscriptionPlan')} {/* 订阅计划卡片 */} {plans.map((plan, index) => { const isSelected = selectedPlanIndex === index return ( 0 && styles.planCardSpacing, ]} onPress={() => setSelectedPlanIndex(index)} > {isSelected ? ( {plan.recommended && ( {t('membership.mostRecommended')} )} {plan.name} {toUnit(plan.currency)} {plan.price} {t('membership.perMonth')} ) : ( {plan.recommended && ( {t('membership.mostRecommended')} )} {plan.name} {toUnit(plan.currency)} {plan.price} {t('membership.perMonth')} )} ) })} {/* 卡片所属的信息 */} {/* 积分每月显示 */} {currentPlan.points.toLocaleString()} {t('membership.pointsPerMonth')} {t('membership.pointsAutoRenew')} {/* 功能列表 */} {currentPlan.featureList.map((featureKey, index) => { const translatedText = t(featureKey) // 如果没有对应的翻译键(翻译结果等于键本身),不展示该项 if (translatedText === featureKey) { return null } return ( {translatedText} ) })} {/* 固定在底部的订阅容器 */} {/* 立即开通按钮 */} {isLoadingSubscriptions || isStripePricingLoading || isSubscribing ? ( ) : ( {t('membership.subscribeNow')} )} {/* 协议复选框 */} setAgreed(!agreed)} > {agreed ? : } {t('membership.agreementText')}{' '} router.push('/terms')} > {t('membership.terms')} {t('membership.agreementAnd')} router.push('/privacy')} > {t('membership.privacy')} {/* 积分抽屉 */} setPointsDrawerVisible(false)} totalPoints={creditBalance} subscriptionPoints={0} topUpPoints={0} onRecharge={(amount) => rechargeToken(amount)} /> ) } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#090A0B', }, contentWrapper: { flex: 1, }, scrollView: { flex: 1, backgroundColor: '#090A0B', }, scrollContent: { backgroundColor: '#090A0B', flexGrow: 1, paddingTop: 56, // 为固定的导航栏留出空间 }, header: { position: 'absolute', top: 0, left: 0, right: 0, flexDirection: 'row', alignItems: 'center', paddingHorizontal: 12, paddingTop: 7, paddingBottom: 7, zIndex: 100, backgroundColor: 'transparent', }, imageContainer: { width: '100%', overflow: 'hidden', marginTop: -56, position: 'relative', }, membershipImage: { width: '100%', height: '100%', }, imageGradient: { position: 'absolute', bottom: -20, left: 0, right: 0, height: '30%', zIndex: 10, elevation: 10, }, dotsContainer: { position: 'absolute', bottom: 40, left: 16, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', gap: 4, zIndex: 20, elevation: 20, }, dot: { width: 4, height: 4, borderRadius: 100, backgroundColor: '#FFFFFF80', }, dotActive: { width: 10, height: 4, borderRadius: 100, backgroundColor: '#FFFFFF', }, backButton: { width: 32, height: 32, alignItems: 'center', justifyContent: 'center', borderRadius: 100, }, headerSpacer: { flex: 1, }, pointsPill: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 12, paddingVertical: 8, borderRadius: 100, backgroundColor: '#2A2A2A80', }, pointsLabel: { color: '#F5F5F5', fontSize: 11, fontWeight: '500', }, pointsValue: { color: '#F5F5F5', fontSize: 12, fontWeight: '500', }, sectionTitle: { textAlign: 'center', color: '#F5F5F5', fontSize: 24, fontWeight: '900', lineHeight: 32, marginBottom: 16, marginTop: 9, fontStyle: 'italic', }, plansContainer: { flexDirection: 'row', paddingHorizontal: 16, marginBottom: 16, }, planCardWrapper: { flex: 1, }, planCardGradient: { flex: 1, borderRadius: 12, padding: 2, }, planCardWrapperUnselected: { flex: 1, borderRadius: 12, padding: 2, backgroundColor: 'transparent', }, planCard: { flex: 1, paddingTop: 12, paddingBottom: 16, paddingHorizontal: 12, borderRadius: 12, backgroundColor: '#16181B', position: 'relative', overflow: 'hidden', }, planCardSpacing: { marginLeft: 12, }, recommendedBadge: { position: 'absolute', top: -3, right: -2, paddingHorizontal: 11, paddingBottom: 1, borderRadius: 4, backgroundColor: '#6851EB', borderTopRightRadius: 12, borderBottomRightRadius: 0, }, recommendedText: { color: '#F5F5F5', fontSize: 10, fontWeight: '500', }, planName: { color: '#F5F5F5', fontSize: 12, fontWeight: '500', marginBottom: 14, }, priceContainer: { flexDirection: 'row', alignItems: 'baseline', }, priceSymbol: { color: '#F5F5F5', fontSize: 12, fontWeight: '500', marginRight: 2, }, priceValue: { color: '#F5F5F5', fontSize: 24, fontWeight: '500', marginRight: 4, }, priceUnit: { color: '#ABABAB', fontSize: 12, fontWeight: '500', }, pointsMonthlyContainer: { marginHorizontal: 16, backgroundColor: '#191B1F', paddingHorizontal: 12, paddingVertical: 12, borderRadius: 12, marginBottom: 16, }, pointsMonthlyCard: { paddingHorizontal: 16, paddingVertical: 10, borderRadius: 10, backgroundColor: '#272A30', marginBottom: 24, }, pointsMonthlyHeader: { flexDirection: 'row', alignItems: 'center', marginBottom: 10, }, pointsMonthlyLabelWrapper: { marginLeft: 8, }, pointsMonthlyValue: { color: '#F5F5F5', fontSize: 13, fontWeight: '500', }, pointsMonthlyLabel: { color: '#F5F5F5', fontSize: 13, fontWeight: '500', }, progressBar: { width: '100%', height: 3, backgroundColor: '#484F5B', borderRadius: 10, marginBottom: 10, overflow: 'hidden', }, progressFill: { height: '100%', borderRadius: 2, }, pointsMonthlyNote: { color: '#CCCCCC', fontSize: 11, fontWeight: '400', }, featureItem: { flexDirection: 'row', alignItems: 'center', gap: 16, marginBottom: 12, }, featureText: { flex: 1, color: '#CCCCCC', fontSize: 12, fontWeight: '400', }, agreementContainer: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', marginTop: 8, marginBottom: 16, paddingVertical: 8, }, agreementTextWrapper: { marginLeft: 4, }, checkbox: { width: 20, height: 20, alignItems: 'center', justifyContent: 'center', padding: 4, }, agreementText: { color: '#CCCCCC', fontSize: 11, fontWeight: '400', }, agreementLink: { color: '#CCCCCC', }, subscribeContainer: { paddingTop: 8, alignItems: 'center', paddingHorizontal: 16, }, subscribeButtonPressable: { width: '100%', height: 48, borderRadius: 12, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', }, subscribeButton: { width: '100%', paddingVertical: 14, borderRadius: 12, alignItems: 'center', justifyContent: 'center', }, subscribeButtonDisabled: { opacity: 0.5, }, subscribeButtonText: { color: '#F5F5F5', fontSize: 16, fontWeight: '500', }, subscribeButtonText1: { color: '#0D0D0E', fontSize: 16, fontWeight: '500', }, settingsButtonContainer: { position: 'relative', }, settingsButton: { width: 32, height: 32, alignItems: 'center', justifyContent: 'center', backgroundColor: '#2A2A2A80', borderRadius: 100, }, pointsContainer: { flexDirection: 'row', alignItems: 'center', gap: 12, }, menuDropdown: { width: 180, minWidth: 180, borderRadius: 12, backgroundColor: '#2A2A2A80', paddingVertical: 4, right: 12, }, menuOption: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 2, gap: 8, }, menuOptionText: { color: '#F5F5F5', fontSize: 12, fontWeight: '400', flex: 1, }, loadingContainer: { justifyContent: 'center', alignItems: 'center', }, })