@@ -7,13 +7,15 @@ import {
77 MenuItem ,
88 Skeleton ,
99 Spinner ,
10- Text
10+ Text ,
11+ Divider
1112} from '@chakra-ui/react' ;
1213import { FunctionComponent } from 'react' ;
1314import { toDate , VerticalDotsIcon16 , MenuButtonIcon } from 'src/shared' ;
1415import { observer } from 'mobx-react-lite' ;
1516import { SubscriptionsStore } from 'src/features/billing' ;
1617import { useNavigate } from 'react-router-dom' ;
18+ import { Subscription } from '../model/interfaces/subscription' ;
1719
1820interface SubscriptionListProps {
1921 subscriptionsStore : SubscriptionsStore ;
@@ -22,24 +24,81 @@ interface SubscriptionListProps {
2224 hasSubscriptions ?: boolean ;
2325}
2426
27+ interface SubscriptionListItemProps {
28+ subscription ?: Subscription ;
29+ }
30+
31+ const SubscriptionListItem : FunctionComponent < SubscriptionListItemProps > = ( { subscription } ) => {
32+ const navigate = useNavigate ( ) ;
33+
34+ return (
35+ < Flex justify = "space-between" py = "1" gap = "4" >
36+ < Flex flexDirection = "column" flex = "1" >
37+ { subscription ? (
38+ < >
39+ < Text fontSize = "md" fontWeight = "semibold" >
40+ { subscription . plan }
41+ </ Text >
42+ < Text fontSize = "sm" color = "text.secondary" >
43+ { subscription . interval }
44+ { subscription . renewsDate && ` · Renews ${ toDate ( subscription . renewsDate ) } ` }
45+ </ Text >
46+ </ >
47+ ) : (
48+ < >
49+ < Skeleton h = "5" w = "150px" />
50+ < Skeleton h = "4" w = "200px" />
51+ </ >
52+ ) }
53+ </ Flex >
54+ < Box gap = "1" >
55+ { subscription ? (
56+ < Flex align = "center" >
57+ < Text fontSize = "md" fontWeight = "semibold" >
58+ { subscription . price . stringCurrencyAmount }
59+ </ Text >
60+ < Menu placement = "bottom-end" >
61+ < MenuButtonIcon
62+ aria-label = "options"
63+ icon = { < VerticalDotsIcon16 /> }
64+ ml = "2"
65+ />
66+ < MenuList w = "132px" >
67+ < MenuItem onClick = { ( ) => navigate ( '/tonapi/pricing' ) } >
68+ < Text textStyle = "label2" > Change plan</ Text >
69+ </ MenuItem >
70+ </ MenuList >
71+ </ Menu >
72+ </ Flex >
73+ ) : (
74+ < >
75+ < Skeleton h = "5" w = "80px" />
76+ < Box w = "24px" />
77+ </ >
78+ ) }
79+ </ Box >
80+ </ Flex >
81+ ) ;
82+ } ;
83+
2584const SubscriptionList : FunctionComponent < SubscriptionListProps > = ( {
2685 subscriptionsStore,
27- isLoading = subscriptionsStore . subscriptionsLoading ,
28- hasEverLoaded = false ,
29- hasSubscriptions = subscriptionsStore . subscriptions . length > 0 ,
3086 ...props
3187} ) => {
32- const navigate = useNavigate ( ) ;
88+ const isLoading = subscriptionsStore . subscriptionsLoading ;
3389
3490 // First load - show Spinner
35- if ( ! hasEverLoaded && isLoading ) {
91+ if ( isLoading ) {
3692 return (
3793 < Center h = "96px" >
3894 < Spinner />
3995 </ Center >
4096 ) ;
4197 }
4298
99+ const { liteproxy, restApi } = subscriptionsStore . subscriptions ;
100+ const hasSubscriptions = Boolean ( liteproxy || restApi ) ;
101+
43102 // No data and not loading - show Empty message
44103 if ( ! isLoading && ! hasSubscriptions ) {
45104 return (
@@ -52,63 +111,9 @@ const SubscriptionList: FunctionComponent<SubscriptionListProps> = ({
52111 // Card list with data or skeleton
53112 return (
54113 < Box minH = "100px" { ...props } >
55- { isLoading && hasEverLoaded
56- ? // Show skeleton while loading if data has been loaded before
57- Array . from ( { length : 1 } ) . map ( ( _ , index ) => (
58- < Flex
59- key = { index }
60- align = "center"
61- justify = "space-between"
62- py = "2"
63- gap = "4"
64- >
65- < Flex flexDirection = "column" gap = "1" flex = "1" >
66- < Skeleton h = "5" w = "150px" />
67- < Skeleton h = "4" w = "200px" />
68- </ Flex >
69- < Flex align = "center" gap = "4" flexShrink = { 0 } >
70- < Skeleton h = "5" w = "80px" />
71- < Box w = "24px" />
72- </ Flex >
73- </ Flex >
74- ) )
75- : // Show real data
76- subscriptionsStore . subscriptions . map ( subscription => (
77- < Flex
78- key = { subscription . id }
79- align = "center"
80- justify = "space-between"
81- py = "2"
82- gap = "4"
83- >
84- < Flex flexDirection = "column" gap = "1" flex = "1" >
85- < Text fontSize = "md" fontWeight = "semibold" >
86- { subscription . plan }
87- </ Text >
88- < Text fontSize = "sm" color = "text.secondary" >
89- { subscription . interval } · { subscription . renewsDate && `Renews ${ toDate ( subscription . renewsDate ) } ` }
90- </ Text >
91- </ Flex >
92- < Flex align = "center" gap = "4" flexShrink = { 0 } >
93- < Text fontSize = "md" fontWeight = "semibold" >
94- { subscription . price . stringCurrencyAmount }
95- </ Text >
96- < Menu placement = "bottom-end" >
97- < MenuButtonIcon
98- aria-label = "options"
99- icon = { < VerticalDotsIcon16 /> }
100- />
101- < MenuList w = "132px" >
102- < MenuItem
103- onClick = { ( ) => navigate ( '/tonapi/pricing' ) }
104- >
105- < Text textStyle = "label2" > Change plan</ Text >
106- </ MenuItem >
107- </ MenuList >
108- </ Menu >
109- </ Flex >
110- </ Flex >
111- ) ) }
114+ < SubscriptionListItem subscription = { ! isLoading && restApi ? restApi : undefined } />
115+ < Divider />
116+ < SubscriptionListItem subscription = { ! isLoading && liteproxy ? liteproxy : undefined } />
112117 </ Box >
113118 ) ;
114119} ;
0 commit comments