fix: bug
This commit is contained in:
188
hooks/use-membership.ts
Normal file
188
hooks/use-membership.ts
Normal file
@@ -0,0 +1,188 @@
|
||||
import { useState, useEffect, useMemo } from 'react'
|
||||
import { Linking, Alert } from 'react-native'
|
||||
|
||||
import { subscription, useSession } from '@/lib/auth'
|
||||
import type { SubscriptionListItem } from '@/lib/auth'
|
||||
|
||||
interface CreditPlan {
|
||||
amountInCents: number
|
||||
credits: number
|
||||
popular?: boolean
|
||||
}
|
||||
|
||||
export function useMembership() {
|
||||
const { data: session } = useSession()
|
||||
const [selectedPlanIndex, setSelectedPlanIndex] = useState(0)
|
||||
const [stripePricingData, setStripePricingData] = useState<any>(null)
|
||||
const [authSubscriptions, setAuthSubscriptions] = useState<any>(null)
|
||||
const [isStripePricingLoading, setIsStripePricingLoading] = useState(false)
|
||||
const [isLoadingSubscriptions, setIsLoadingSubscriptions] = useState(false)
|
||||
|
||||
const fetchStripePricing = async () => {
|
||||
setIsStripePricingLoading(true)
|
||||
const { data, error } = await subscription.plans({
|
||||
query: {
|
||||
id: process.env.EXPO_PUBLIC_STRIPE_PRICING_TABLE_ID || '',
|
||||
key: process.env.EXPO_PUBLIC_STRIPE_PRICING_TABLE_KEY || '',
|
||||
},
|
||||
})
|
||||
setIsStripePricingLoading(false)
|
||||
if (!error) setStripePricingData(data)
|
||||
}
|
||||
|
||||
const fetchAuthSubscriptions = async () => {
|
||||
if (!session?.user?.id) return
|
||||
setIsLoadingSubscriptions(true)
|
||||
const { data, error } = await subscription.list({
|
||||
query: { referenceId: session.user.id },
|
||||
})
|
||||
setIsLoadingSubscriptions(false)
|
||||
if (!error) setAuthSubscriptions(data)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchStripePricing()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (session?.user?.id) fetchAuthSubscriptions()
|
||||
}, [session?.user?.id])
|
||||
|
||||
const licensedSubscriptions = authSubscriptions?.filter((sub: SubscriptionListItem) => sub.type === 'licenced') || []
|
||||
const meteredSubscriptions = authSubscriptions?.filter((sub: SubscriptionListItem) => sub.type === 'metered') || []
|
||||
|
||||
const activeAuthSubscription = licensedSubscriptions.find(
|
||||
(sub: any) => sub.status === 'active' || sub.status === 'trialing'
|
||||
)
|
||||
|
||||
const hasActiveSubscription = !!(
|
||||
activeAuthSubscription &&
|
||||
activeAuthSubscription.cancelAtPeriodEnd === false &&
|
||||
activeAuthSubscription.status === 'active'
|
||||
)
|
||||
|
||||
const creditBalance = meteredSubscriptions?.[0]?.creditBalance?.remainingTokenBalance || 0
|
||||
|
||||
const creditPlans = useMemo((): CreditPlan[] => {
|
||||
if (!stripePricingData?.pricing_table_items) return []
|
||||
return stripePricingData.pricing_table_items
|
||||
.filter((item: any) => item.recurring?.interval === 'month')
|
||||
.map((item: any) => ({
|
||||
amountInCents: parseInt(item.amount),
|
||||
credits: parseInt(item.metadata?.grant_token || item.amount),
|
||||
popular: item.is_highlight || item.highlight_text === 'most_popular',
|
||||
}))
|
||||
}, [stripePricingData?.pricing_table_items])
|
||||
|
||||
const selectedPlan = creditPlans[selectedPlanIndex] || creditPlans[0]
|
||||
|
||||
const createSubscription = async ({ priceId, productId }: { priceId: string; productId: string }) => {
|
||||
const { data, error } = await subscription.create({
|
||||
priceId,
|
||||
productId,
|
||||
successUrl: `${process.env.EXPO_PUBLIC_APP_URL}/membership`,
|
||||
cancelUrl: `${process.env.EXPO_PUBLIC_APP_URL}/membership?canceled=true`,
|
||||
})
|
||||
if (error) {
|
||||
Alert.alert('错误', '订阅创建失败')
|
||||
return
|
||||
}
|
||||
if (data?.url) await Linking.openURL(data.url)
|
||||
}
|
||||
|
||||
const upgradeSubscription = async ({ credits }: { credits: number }) => {
|
||||
if (!activeAuthSubscription?.stripeSubscriptionId) {
|
||||
Alert.alert('错误', '未找到活跃订阅')
|
||||
return
|
||||
}
|
||||
const planIndex = creditPlans.findIndex(plan => plan.credits === credits)
|
||||
const planNames = stripePricingData?.pricing_table_items?.map((item: any) => item.product_name) || []
|
||||
const planName = planNames[planIndex] || 'basic'
|
||||
const { data, error } = await subscription.upgrade({
|
||||
plan: planName,
|
||||
subscriptionId: activeAuthSubscription.stripeSubscriptionId,
|
||||
successUrl: `${process.env.EXPO_PUBLIC_APP_URL}/membership`,
|
||||
cancelUrl: `${process.env.EXPO_PUBLIC_APP_URL}/membership?canceled=true`,
|
||||
})
|
||||
if (error) {
|
||||
Alert.alert('错误', '订阅升级失败')
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const restoreSubscription = async () => {
|
||||
if (!activeAuthSubscription) {
|
||||
Alert.alert('错误', '未找到可恢复的订阅')
|
||||
return
|
||||
}
|
||||
const { data, error } = await subscription.restore({
|
||||
subscriptionId: activeAuthSubscription.stripeSubscriptionId,
|
||||
referenceId: activeAuthSubscription.referenceId,
|
||||
})
|
||||
if (error) {
|
||||
Alert.alert('错误', '订阅恢复失败')
|
||||
return
|
||||
}
|
||||
Alert.alert('成功', '订阅已恢复')
|
||||
await fetchAuthSubscriptions()
|
||||
}
|
||||
|
||||
const cancelSubscription = async () => {
|
||||
if (!activeAuthSubscription) {
|
||||
Alert.alert('错误', '未找到活跃订阅')
|
||||
return
|
||||
}
|
||||
const { data, error } = await subscription.cancel({
|
||||
subscriptionId: activeAuthSubscription.stripeSubscriptionId,
|
||||
referenceId: activeAuthSubscription.referenceId,
|
||||
})
|
||||
if (error) {
|
||||
Alert.alert('错误', '订阅取消失败')
|
||||
return
|
||||
}
|
||||
Alert.alert('成功', '订阅已取消')
|
||||
await fetchAuthSubscriptions()
|
||||
}
|
||||
|
||||
const rechargeToken = async (amount: number) => {
|
||||
if (!amount || amount <= 0) {
|
||||
Alert.alert('错误', '充值金额无效')
|
||||
return
|
||||
}
|
||||
if (!meteredSubscriptions?.[0]?.priceId) {
|
||||
Alert.alert('错误', '定价数据不可用')
|
||||
return
|
||||
}
|
||||
const { data, error } = await subscription.credit.topup({
|
||||
amount,
|
||||
priceId: meteredSubscriptions[0].priceId,
|
||||
successUrl: `${process.env.EXPO_PUBLIC_APP_URL}/membership`,
|
||||
cancelUrl: `${process.env.EXPO_PUBLIC_APP_URL}/membership?canceled=true`,
|
||||
})
|
||||
if (error) {
|
||||
Alert.alert('错误', '充值失败')
|
||||
return
|
||||
}
|
||||
if (data?.url) await Linking.openURL(data.url)
|
||||
}
|
||||
|
||||
return {
|
||||
selectedPlanIndex,
|
||||
selectedPlan,
|
||||
creditPlans,
|
||||
stripePricingData,
|
||||
session,
|
||||
activeAuthSubscription,
|
||||
hasActiveSubscription,
|
||||
creditBalance,
|
||||
isLoadingSubscriptions,
|
||||
isStripePricingLoading,
|
||||
setSelectedPlanIndex,
|
||||
createSubscription,
|
||||
upgradeSubscription,
|
||||
restoreSubscription,
|
||||
cancelSubscription,
|
||||
rechargeToken,
|
||||
refetchAuthSubscriptions: fetchAuthSubscriptions,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user