@@ -13,8 +13,21 @@ import { useTranslation } from "react-i18next"
1313
1414import type { PaymentFeature , PaymentPlan } from "~/atoms/server-configs"
1515import { useIsPaymentEnabled , useServerConfigs } from "~/atoms/server-configs"
16+ import { followClient } from "~/lib/api-client"
1617import { subscription } from "~/lib/auth"
1718
19+ const APPLE_SUBSCRIPTION_MANAGEMENT_URL = "https://apps.apple.com/account/subscriptions"
20+
21+ type ActiveSubscription = {
22+ source : "stripe" | "apple" | null
23+ plan : string | null
24+ status : string | null
25+ productId : string | null
26+ periodEnd : string | null
27+ trialEnd : string | null
28+ canManage : boolean
29+ }
30+
1831const AI_MODEL_SELECTION_VALUE_LABELS = {
1932 none : {
2033 translationKey : "plan.featureValues.AI_MODEL_SELECTION.none" ,
@@ -94,25 +107,12 @@ const useUpgradePlan = ({ plan, annual }: { plan: string | undefined; annual: bo
94107const useActiveSubscription = ( ) => {
95108 const userId = useWhoami ( ) ?. id
96109 return useQuery ( {
97- queryKey : [ "activeSubscription " ] ,
110+ queryKey : [ "billingSubscription " ] ,
98111 queryFn : async ( ) => {
99- const { data } = await subscription . list ( )
100- // Find subscription: active, trialing, or canceled with valid period end
101- return data ?. find ( ( sub ) => {
102- if ( ! sub . stripeSubscriptionId ) return false
103-
104- // Active or trialing subscriptions
105- if ( sub . status === "active" || sub . status === "trialing" ) {
106- return true
107- }
108-
109- // Canceled subscriptions that haven't expired yet
110- if ( sub . status === "canceled" && sub . periodEnd ) {
111- return new Date ( sub . periodEnd ) > new Date ( )
112- }
113-
114- return false
115- } )
112+ const response = await followClient . request < { code : number ; data : ActiveSubscription } > (
113+ "/billing/subscription" ,
114+ )
115+ return response . data
116116 } ,
117117 enabled : ! ! userId ,
118118 } )
@@ -396,11 +396,13 @@ const PlanAction = ({
396396 const { t } = useTranslation ( "settings" )
397397 const { data : activeSubscription } = useActiveSubscription ( )
398398 const billingPortalMutation = useBillingPortal ( )
399- const canManageSubscription = ! ! activeSubscription ?. stripeSubscriptionId
399+ const canManageSubscription = ! ! activeSubscription ?. canManage
400+ const isAppleSubscription = activeSubscription ?. source === "apple"
400401
401402 // Determine subscription status info
402403 const isCanceled = activeSubscription ?. status === "canceled"
403- const periodEnd = activeSubscription ?. periodEnd ? new Date ( activeSubscription . periodEnd ) : null
404+ const periodEnd = activeSubscription ?. trialEnd ?? activeSubscription ?. periodEnd
405+ const effectivePeriodEnd = periodEnd ? new Date ( periodEnd ) : null
404406
405407 const getButtonConfig = ( ) => {
406408 switch ( actionType ) {
@@ -486,22 +488,22 @@ const PlanAction = ({
486488 < span >
487489 { isCanceled
488490 ? t ( "plan.canceled_expires" , {
489- date : periodEnd ?. toLocaleDateString ( undefined , {
491+ date : effectivePeriodEnd ?. toLocaleDateString ( undefined , {
490492 year : "numeric" ,
491493 month : "short" ,
492494 day : "numeric" ,
493495 } ) ,
494496 } )
495497 : activeSubscription ?. status === "trialing"
496498 ? t ( "plan.trial_ends" , {
497- date : periodEnd ?. toLocaleDateString ( undefined , {
499+ date : effectivePeriodEnd ?. toLocaleDateString ( undefined , {
498500 year : "numeric" ,
499501 month : "short" ,
500502 day : "numeric" ,
501503 } ) ,
502504 } )
503505 : t ( "plan.renews" , {
504- date : periodEnd ?. toLocaleDateString ( undefined , {
506+ date : effectivePeriodEnd ?. toLocaleDateString ( undefined , {
505507 year : "numeric" ,
506508 month : "short" ,
507509 day : "numeric" ,
@@ -519,7 +521,14 @@ const PlanAction = ({
519521 disabled = { buttonConfig . disabled }
520522 onClick = {
521523 actionType === "current" && canManageSubscription
522- ? ( ) => billingPortalMutation . mutate ( )
524+ ? ( ) => {
525+ if ( isAppleSubscription ) {
526+ window . open ( APPLE_SUBSCRIPTION_MANAGEMENT_URL , "_blank" )
527+ return
528+ }
529+
530+ billingPortalMutation . mutate ( )
531+ }
523532 : onSelect
524533 }
525534 isLoading = { isLoading || billingPortalMutation . isPending }
0 commit comments