1
1
import { useClerk } from '@clerk/shared/react' ;
2
- import type { __internal_PlanDetailsProps , CommercePlanResource , CommerceSubscriptionPlanPeriod } from '@clerk/types' ;
2
+ import type {
3
+ __internal_PlanDetailsProps ,
4
+ ClerkAPIResponseError ,
5
+ CommercePlanResource ,
6
+ CommerceSubscriptionPlanPeriod ,
7
+ } from '@clerk/types' ;
3
8
import * as React from 'react' ;
4
9
import { useMemo , useState } from 'react' ;
5
10
import useSWR from 'swr' ;
6
11
12
+ import { Alert } from '@/ui/elements/Alert' ;
7
13
import { Avatar } from '@/ui/elements/Avatar' ;
8
14
import { Drawer } from '@/ui/elements/Drawer' ;
9
15
import { Switch } from '@/ui/elements/Switch' ;
10
16
11
17
import { SubscriberTypeContext } from '../../contexts' ;
12
- import { Box , Col , descriptors , Flex , Heading , localizationKeys , Span , Spinner , Text } from '../../customizables' ;
18
+ import {
19
+ Box ,
20
+ Col ,
21
+ descriptors ,
22
+ Flex ,
23
+ Heading ,
24
+ localizationKeys ,
25
+ Span ,
26
+ Spinner ,
27
+ Text ,
28
+ useLocalizations ,
29
+ } from '../../customizables' ;
13
30
14
31
export const PlanDetails = ( props : __internal_PlanDetailsProps ) => {
15
32
return (
@@ -19,6 +36,39 @@ export const PlanDetails = (props: __internal_PlanDetailsProps) => {
19
36
) ;
20
37
} ;
21
38
39
+ const BodyFiller = ( { children } : { children : React . ReactNode } ) => {
40
+ return (
41
+ < Drawer . Body
42
+ sx = { t => ( {
43
+ display : 'flex' ,
44
+ flexDirection : 'column' ,
45
+ alignItems : 'center' ,
46
+ justifyContent : 'center' ,
47
+ flex : 1 ,
48
+ overflowY : 'auto' ,
49
+ padding : t . space . $4 ,
50
+ gap : t . space . $4 ,
51
+ } ) }
52
+ >
53
+ { children }
54
+ </ Drawer . Body >
55
+ ) ;
56
+ } ;
57
+
58
+ const PlanDetailsError = ( { error } : { error : ClerkAPIResponseError } ) => {
59
+ const { translateError } = useLocalizations ( ) ;
60
+ return (
61
+ < BodyFiller >
62
+ < Alert
63
+ variant = 'danger'
64
+ colorScheme = 'danger'
65
+ >
66
+ { translateError ( error . errors [ 0 ] ) }
67
+ </ Alert >
68
+ </ BodyFiller >
69
+ ) ;
70
+ } ;
71
+
22
72
const PlanDetailsInternal = ( {
23
73
planId,
24
74
plan : initialPlan ,
@@ -27,29 +77,34 @@ const PlanDetailsInternal = ({
27
77
const clerk = useClerk ( ) ;
28
78
const [ planPeriod , setPlanPeriod ] = useState < CommerceSubscriptionPlanPeriod > ( initialPlanPeriod ) ;
29
79
30
- const { data : plan , isLoading } = useSWR (
80
+ const {
81
+ data : plan ,
82
+ isLoading,
83
+ error,
84
+ } = useSWR < CommercePlanResource , ClerkAPIResponseError > (
31
85
planId || initialPlan ? { type : 'plan' , id : planId || initialPlan ?. id } : null ,
32
86
// @ts -expect-error we are handling it above
33
87
( ) => clerk . billing . getPlan ( { id : planId || initialPlan ?. id } ) ,
34
88
{
35
89
fallbackData : initialPlan ,
90
+ revalidateOnFocus : false ,
91
+ shouldRetryOnError : false ,
92
+ keepPreviousData : true ,
36
93
} ,
37
94
) ;
38
95
39
96
if ( isLoading && ! initialPlan ) {
40
97
return (
41
- < Flex
42
- justify = 'center'
43
- align = 'center'
44
- sx = { {
45
- height : '100%' ,
46
- } }
47
- >
98
+ < BodyFiller >
48
99
< Spinner />
49
- </ Flex >
100
+ </ BodyFiller >
50
101
) ;
51
102
}
52
103
104
+ if ( ! plan && error ) {
105
+ return < PlanDetailsError error = { error } /> ;
106
+ }
107
+
53
108
if ( ! plan ) {
54
109
return null ;
55
110
}
0 commit comments