1
- import type { CommerceSubscriptionItemResource } from '@clerk/types' ;
1
+ import type { CommercePlanResource , CommerceSubscriptionItemResource } from '@clerk/types' ;
2
2
import { useMemo } from 'react' ;
3
3
4
+ import { useProtect } from '@/ui/common/Gate' ;
4
5
import { ProfileSection } from '@/ui/elements/Section' ;
5
6
6
- import { useProtect } from '../../common' ;
7
7
import {
8
8
normalizeFormatted ,
9
9
useEnvironment ,
@@ -13,39 +13,42 @@ import {
13
13
useSubscription ,
14
14
} from '../../contexts' ;
15
15
import type { LocalizationKey } from '../../customizables' ;
16
- import {
17
- Button ,
18
- Col ,
19
- Flex ,
20
- Icon ,
21
- localizationKeys ,
22
- Span ,
23
- Table ,
24
- Tbody ,
25
- Td ,
26
- Text ,
27
- Th ,
28
- Thead ,
29
- Tr ,
30
- } from '../../customizables' ;
16
+ import { Col , Flex , Icon , localizationKeys , Span , Table , Tbody , Td , Text , Th , Thead , Tr } from '../../customizables' ;
31
17
import { ArrowsUpDown , CogFilled , Plans , Plus } from '../../icons' ;
32
18
import { useRouter } from '../../router' ;
33
19
import { SubscriptionBadge } from './badge' ;
34
20
21
+ const isFreePlan = ( plan : CommercePlanResource ) => ! plan . hasBaseFee ;
22
+
35
23
export function SubscriptionsList ( {
36
24
title,
37
- arrowButtonText,
38
- arrowButtonEmptyText,
25
+ switchPlansLabel,
26
+ newSubscriptionLabel,
27
+ manageSubscriptionLabel,
39
28
} : {
40
29
title : LocalizationKey ;
41
- arrowButtonText : LocalizationKey ;
42
- arrowButtonEmptyText : LocalizationKey ;
30
+ switchPlansLabel : LocalizationKey ;
31
+ newSubscriptionLabel : LocalizationKey ;
32
+ manageSubscriptionLabel : LocalizationKey ;
43
33
} ) {
44
34
const localizationRoot = useSubscriberTypeLocalizationRoot ( ) ;
45
35
const subscriberType = useSubscriberTypeContext ( ) ;
46
- const { subscriptionItems } = useSubscription ( ) ;
36
+ const { subscriptionItems, data : subscription } = useSubscription ( ) ;
37
+ const canManageBilling =
38
+ useProtect ( has => has ( { permission : 'org:sys_billing:manage' } ) ) || subscriberType === 'user' ;
47
39
const { navigate } = useRouter ( ) ;
48
40
const { commerceSettings } = useEnvironment ( ) ;
41
+ const { openSubscriptionDetails } = usePlansContext ( ) ;
42
+
43
+ const billingPlansExist =
44
+ ( commerceSettings . billing . user . hasPaidPlans && subscriberType === 'user' ) ||
45
+ ( commerceSettings . billing . organization . hasPaidPlans && subscriberType === 'organization' ) ;
46
+
47
+ const hasActiveFreePlan = useMemo ( ( ) => {
48
+ return subscriptionItems . some ( sub => isFreePlan ( sub . plan ) && sub . status === 'active' ) ;
49
+ } , [ subscriptionItems ] ) ;
50
+
51
+ const isManageButtonVisible = canManageBilling && ! ! subscription && ! hasActiveFreePlan ;
49
52
50
53
const sortedSubscriptions = useMemo (
51
54
( ) =>
@@ -88,11 +91,6 @@ export function SubscriptionsList({
88
91
`${ localizationRoot } .billingPage.subscriptionsListSection.tableHeader__startDate` ,
89
92
) }
90
93
/>
91
- < Th
92
- localizationKey = { localizationKeys (
93
- `${ localizationRoot } .billingPage.subscriptionsListSection.tableHeader__edit` ,
94
- ) }
95
- />
96
94
</ Tr >
97
95
</ Thead >
98
96
< Tbody >
@@ -107,35 +105,56 @@ export function SubscriptionsList({
107
105
</ Table >
108
106
) }
109
107
110
- { ( commerceSettings . billing . user . hasPaidPlans && subscriberType === 'user' ) ||
111
- ( commerceSettings . billing . organization . hasPaidPlans && subscriberType === 'organization' ) ? (
112
- < ProfileSection . ArrowButton
113
- id = 'subscriptionsList'
114
- textLocalizationKey = { subscriptionItems . length > 0 ? arrowButtonText : arrowButtonEmptyText }
115
- sx = { [
116
- t => ( {
117
- justifyContent : 'start' ,
118
- height : t . sizes . $8 ,
119
- } ) ,
120
- ] }
121
- leftIcon = { subscriptionItems . length > 0 ? ArrowsUpDown : Plus }
122
- leftIconSx = { t => ( {
123
- width : t . sizes . $4 ,
124
- height : t . sizes . $4 ,
125
- } ) }
126
- onClick = { ( ) => void navigate ( 'plans' ) }
127
- />
128
- ) : null }
108
+ < ProfileSection . ButtonGroup id = 'subscriptionsList' >
109
+ { billingPlansExist ? (
110
+ < ProfileSection . ArrowButton
111
+ id = 'subscriptionsList'
112
+ textLocalizationKey = { subscriptionItems . length > 0 ? switchPlansLabel : newSubscriptionLabel }
113
+ sx = { [
114
+ t => ( {
115
+ justifyContent : 'start' ,
116
+ height : t . sizes . $8 ,
117
+ width : isManageButtonVisible ? 'unset' : undefined ,
118
+ } ) ,
119
+ ] }
120
+ leftIcon = { subscriptionItems . length > 0 ? ArrowsUpDown : Plus }
121
+ rightIcon = { null }
122
+ leftIconSx = { t => ( {
123
+ width : t . sizes . $4 ,
124
+ height : t . sizes . $4 ,
125
+ } ) }
126
+ onClick = { ( ) => void navigate ( 'plans' ) }
127
+ />
128
+ ) : null }
129
+
130
+ { isManageButtonVisible ? (
131
+ < ProfileSection . ArrowButton
132
+ id = 'subscriptionsList'
133
+ textLocalizationKey = { manageSubscriptionLabel }
134
+ sx = { [
135
+ t => ( {
136
+ justifyContent : 'start' ,
137
+ height : t . sizes . $8 ,
138
+ width : 'unset' ,
139
+ } ) ,
140
+ ] }
141
+ rightIcon = { null }
142
+ leftIcon = { CogFilled }
143
+ leftIconSx = { t => ( {
144
+ width : t . sizes . $4 ,
145
+ height : t . sizes . $4 ,
146
+ } ) }
147
+ onClick = { event => openSubscriptionDetails ( event ) }
148
+ />
149
+ ) : null }
150
+ </ ProfileSection . ButtonGroup >
129
151
</ ProfileSection . Root >
130
152
) ;
131
153
}
132
154
133
155
function SubscriptionRow ( { subscription, length } : { subscription : CommerceSubscriptionItemResource ; length : number } ) {
134
- const subscriberType = useSubscriberTypeContext ( ) ;
135
- const canManageBilling =
136
- useProtect ( has => has ( { permission : 'org:sys_billing:manage' } ) ) || subscriberType === 'user' ;
137
156
const fee = subscription . planPeriod === 'annual' ? subscription . plan . annualFee : subscription . plan . fee ;
138
- const { captionForSubscription, openSubscriptionDetails } = usePlansContext ( ) ;
157
+ const { captionForSubscription } = usePlansContext ( ) ;
139
158
140
159
const feeFormatted = useMemo ( ( ) => {
141
160
return normalizeFormatted ( fee . amountFormatted ) ;
@@ -204,32 +223,6 @@ function SubscriptionRow({ subscription, length }: { subscription: CommerceSubsc
204
223
) }
205
224
</ Text >
206
225
</ Td >
207
- < Td
208
- sx = { _ => ( {
209
- textAlign : 'right' ,
210
- } ) }
211
- >
212
- < Button
213
- aria-label = 'Manage subscription'
214
- onClick = { event => openSubscriptionDetails ( event ) }
215
- variant = 'bordered'
216
- colorScheme = 'secondary'
217
- isDisabled = { ! canManageBilling }
218
- sx = { t => ( {
219
- width : t . sizes . $6 ,
220
- height : t . sizes . $6 ,
221
- } ) }
222
- >
223
- < Icon
224
- icon = { CogFilled }
225
- sx = { t => ( {
226
- width : t . sizes . $4 ,
227
- height : t . sizes . $4 ,
228
- opacity : t . opacity . $inactive ,
229
- } ) }
230
- />
231
- </ Button >
232
- </ Td >
233
226
</ Tr >
234
227
) ;
235
228
}
0 commit comments