@@ -28,7 +28,6 @@ import { LineItems } from '@/ui/elements/LineItems';
2828import { SubscriberTypeContext , usePlansContext , useSubscriberTypeContext , useSubscriptions } from '../../contexts' ;
2929import type { LocalizationKey } from '../../customizables' ;
3030import {
31- Badge ,
3231 Button ,
3332 Col ,
3433 descriptors ,
@@ -39,6 +38,7 @@ import {
3938 Text ,
4039 useLocalizations ,
4140} from '../../customizables' ;
41+ import { SubscriptionBadge } from '../Subscriptions/badge' ;
4242
4343// We cannot derive the state of confrimation modal from the existance subscription, as it will make the animation laggy when the confimation closes.
4444const SubscriptionForCancellationContext = React . createContext < {
@@ -68,12 +68,14 @@ export const SubscriptionDetails = (props: __internal_SubscriptionDetailsProps)
6868type UseGuessableSubscriptionResult < Or extends 'throw' | undefined = undefined > = Or extends 'throw'
6969 ? {
7070 upcomingSubscription ?: CommerceSubscriptionResource ;
71- activeSubscription : CommerceSubscriptionResource ;
71+ pastDueSubscription ?: CommerceSubscriptionResource ;
72+ activeSubscription ?: CommerceSubscriptionResource ;
7273 anySubscription : CommerceSubscriptionResource ;
7374 isLoading : boolean ;
7475 }
7576 : {
7677 upcomingSubscription ?: CommerceSubscriptionResource ;
78+ pastDueSubscription ?: CommerceSubscriptionResource ;
7779 activeSubscription ?: CommerceSubscriptionResource ;
7880 anySubscription ?: CommerceSubscriptionResource ;
7981 isLoading : boolean ;
@@ -85,15 +87,17 @@ function useGuessableSubscription<Or extends 'throw' | undefined = undefined>(op
8587 const { data : subscriptions , isLoading } = useSubscriptions ( ) ;
8688 const activeSubscription = subscriptions ?. find ( sub => sub . status === 'active' ) ;
8789 const upcomingSubscription = subscriptions ?. find ( sub => sub . status === 'upcoming' ) ;
90+ const pastDueSubscription = subscriptions ?. find ( sub => sub . status === 'past_due' ) ;
8891
89- if ( options ?. or === 'throw' && ! activeSubscription ) {
90- throw new Error ( 'No active subscription found' ) ;
92+ if ( options ?. or === 'throw' && ! activeSubscription && ! pastDueSubscription ) {
93+ throw new Error ( 'No active or past due subscription found' ) ;
9194 }
9295
9396 return {
9497 upcomingSubscription,
98+ pastDueSubscription,
9599 activeSubscription : activeSubscription as any , // Type is correct due to the throw above
96- anySubscription : ( upcomingSubscription || activeSubscription ) as any ,
100+ anySubscription : ( upcomingSubscription || activeSubscription || pastDueSubscription ) as any ,
97101 isLoading,
98102 } ;
99103}
@@ -111,7 +115,7 @@ const SubscriptionDetailsInternal = (props: __internal_SubscriptionDetailsProps)
111115 } = usePlansContext ( ) ;
112116
113117 const { data : subscriptions , isLoading } = useSubscriptions ( ) ;
114- const { activeSubscription } = useGuessableSubscription ( ) ;
118+ const { activeSubscription, pastDueSubscription } = useGuessableSubscription ( ) ;
115119
116120 if ( isLoading ) {
117121 return (
@@ -123,7 +127,7 @@ const SubscriptionDetailsInternal = (props: __internal_SubscriptionDetailsProps)
123127 ) ;
124128 }
125129
126- if ( ! activeSubscription ) {
130+ if ( ! activeSubscription && ! pastDueSubscription ) {
127131 // Should never happen, since Free will always be active
128132 return null ;
129133 }
@@ -200,7 +204,7 @@ const SubscriptionDetailsFooter = withCardStateProvider(() => {
200204 } , [ subscription , setError , setLoading , subscriberType , organization ?. id , onSubscriptionCancel , setIsOpen , setIdle ] ) ;
201205
202206 // If either the active or upcoming subscription is the free plan, then a C1 cannot switch to a different period or cancel the plan
203- if ( isFreePlan ( anySubscription . plan ) ) {
207+ if ( isFreePlan ( anySubscription . plan ) || anySubscription . status === 'past_due' ) {
204208 return null ;
205209 }
206210
@@ -270,7 +274,9 @@ const SubscriptionDetailsFooter = withCardStateProvider(() => {
270274} ) ;
271275
272276function SubscriptionDetailsSummary ( ) {
273- const { anySubscription, activeSubscription, upcomingSubscription } = useGuessableSubscription ( { or : 'throw' } ) ;
277+ const { anySubscription, activeSubscription, upcomingSubscription } = useGuessableSubscription ( {
278+ or : 'throw' ,
279+ } ) ;
274280
275281 if ( ! activeSubscription ) {
276282 return null ;
@@ -326,10 +332,11 @@ const SubscriptionCardActions = ({ subscription }: { subscription: CommerceSubsc
326332 const canManageBilling = subscriberType === 'user' || canOrgManageBilling ;
327333
328334 const isSwitchable =
329- ( subscription . planPeriod === 'month' && subscription . plan . annualMonthlyAmount > 0 ) ||
330- subscription . planPeriod === 'annual' ;
335+ ( ( subscription . planPeriod === 'month' && subscription . plan . annualMonthlyAmount > 0 ) ||
336+ subscription . planPeriod === 'annual' ) &&
337+ subscription . status !== 'past_due' ;
331338 const isFree = isFreePlan ( subscription . plan ) ;
332- const isCancellable = subscription . canceledAtDate === null && ! isFree ;
339+ const isCancellable = subscription . canceledAtDate === null && ! isFree && subscription . status !== 'past_due' ;
333340 const isReSubscribable = subscription . canceledAtDate !== null && ! isFree ;
334341
335342 const openCheckout = useCallback (
@@ -425,7 +432,6 @@ const SubscriptionCardActions = ({ subscription }: { subscription: CommerceSubsc
425432
426433// New component for individual subscription cards
427434const SubscriptionCard = ( { subscription } : { subscription : CommerceSubscriptionResource } ) => {
428- const isActive = subscription . status === 'active' ;
429435 const { t } = useLocalizations ( ) ;
430436
431437 return (
@@ -471,10 +477,9 @@ const SubscriptionCard = ({ subscription }: { subscription: CommerceSubscription
471477 >
472478 { subscription . plan . name }
473479 </ Text >
474- < Badge
480+ < SubscriptionBadge
481+ subscription = { subscription }
475482 elementDescriptor = { descriptors . subscriptionDetailsCardBadge }
476- colorScheme = { isActive ? 'secondary' : 'primary' }
477- localizationKey = { isActive ? localizationKeys ( 'badge__activePlan' ) : localizationKeys ( 'badge__upcomingPlan' ) }
478483 />
479484 </ Flex >
480485
@@ -501,7 +506,14 @@ const SubscriptionCard = ({ subscription }: { subscription: CommerceSubscription
501506 </ Flex >
502507 </ Col >
503508
504- { isActive ? (
509+ { subscription . pastDueAt ? (
510+ < DetailRow
511+ label = { localizationKeys ( 'commerce.subscriptionDetails.pastDueAt' ) }
512+ value = { formatDate ( subscription . pastDueAt ) }
513+ />
514+ ) : null }
515+
516+ { subscription . status === 'active' ? (
505517 < >
506518 < DetailRow
507519 label = { localizationKeys ( 'commerce.subscriptionDetails.subscribedOn' ) }
@@ -519,12 +531,14 @@ const SubscriptionCard = ({ subscription }: { subscription: CommerceSubscription
519531 />
520532 ) }
521533 </ >
522- ) : (
534+ ) : null }
535+
536+ { subscription . status === 'upcoming' ? (
523537 < DetailRow
524538 label = { localizationKeys ( 'commerce.subscriptionDetails.beginsOn' ) }
525539 value = { formatDate ( subscription . periodStartDate ) }
526540 />
527- ) }
541+ ) : null }
528542 </ Col >
529543 ) ;
530544} ;
0 commit comments