11import { isClaudeOAuthValid } from '@codebuff/sdk'
22import open from 'open'
3- import React , { useEffect } from 'react'
3+ import React , { useEffect , useMemo } from 'react'
44
55import { BottomBanner } from './bottom-banner'
66import { Button } from './button'
@@ -105,66 +105,22 @@ export const UsageBanner = ({ showTime }: { showTime: number }) => {
105105 const adCredits = activeData . balanceBreakdown ?. ad
106106 const renewalDate = activeData . next_quota_reset ? formatRenewalDate ( activeData . next_quota_reset ) : null
107107
108- const hasSubscription = subscriptionData ?. hasSubscription === true
109- const rateLimit = subscriptionData ?. rateLimit
110- const subscriptionInfo = subscriptionData ?. subscription
108+ const activeSubscription = subscriptionData ?. hasSubscription ? subscriptionData : null
109+ const { rateLimit, subscription : subscriptionInfo , displayName } = activeSubscription ?? { }
111110
112111 return (
113112 < BottomBanner
114113 borderColorKey = { isLoadingData ? 'muted' : colorLevel }
115114 onClose = { ( ) => setInputMode ( 'default' ) }
116115 >
117116 < box style = { { flexDirection : 'column' , gap : 0 } } >
118- { /* Strong subscription section - only show if subscribed */ }
119- { hasSubscription && (
120- < box style = { { flexDirection : 'column' , marginBottom : 1 } } >
121- < box style = { { flexDirection : 'row' , gap : 1 } } >
122- < text style = { { fg : theme . foreground } } >
123- 💪 { subscriptionData . displayName ?? 'Strong' } subscription
124- </ text >
125- { subscriptionInfo ?. tier && (
126- < text style = { { fg : theme . muted } } > ${ subscriptionInfo . tier } /mo</ text >
127- ) }
128- </ box >
129- { isSubscriptionLoading ? (
130- < text style = { { fg : theme . muted } } > Loading subscription data...</ text >
131- ) : rateLimit ? (
132- < box style = { { flexDirection : 'column' , gap : 0 } } >
133- { /* Block progress - always show for Strong subscription */ }
134- { ( ( ) => {
135- const blockPercent = rateLimit . blockLimit != null && rateLimit . blockUsed != null
136- ? Math . max ( 0 , 100 - Math . round ( ( rateLimit . blockUsed / rateLimit . blockLimit ) * 100 ) )
137- : 100
138- return (
139- < box style = { { flexDirection : 'row' , alignItems : 'center' , gap : 0 } } >
140- < text style = { { fg : theme . muted } } > 5-hour limit </ text >
141- < text style = { { fg : theme . muted } } > { `${ blockPercent } %` . padStart ( 4 ) } </ text >
142- < ProgressBar value = { blockPercent } width = { 12 } showPercentage = { false } />
143- < text style = { { fg : theme . muted } } >
144- { rateLimit . blockResetsAt
145- ? ` resets in ${ formatResetTime ( new Date ( rateLimit . blockResetsAt ) ) } `
146- : '' }
147- </ text >
148- </ box >
149- )
150- } ) ( ) }
151- { /* Weekly progress */ }
152- { ( ( ) => {
153- const weeklyPercent = 100 - rateLimit . weeklyPercentUsed
154- return (
155- < box style = { { flexDirection : 'row' , alignItems : 'center' , gap : 0 } } >
156- < text style = { { fg : theme . muted } } > Weekly limit </ text >
157- < text style = { { fg : theme . muted } } > { `${ weeklyPercent } %` . padStart ( 4 ) } </ text >
158- < ProgressBar value = { weeklyPercent } width = { 12 } showPercentage = { false } />
159- < text style = { { fg : theme . muted } } >
160- { ' ' } resets in { formatResetTimeLong ( rateLimit . weeklyResetsAt ) }
161- </ text >
162- </ box >
163- )
164- } ) ( ) }
165- </ box >
166- ) : null }
167- </ box >
117+ { activeSubscription && (
118+ < SubscriptionUsageSection
119+ displayName = { displayName }
120+ subscriptionInfo = { subscriptionInfo }
121+ rateLimit = { rateLimit }
122+ isLoading = { isSubscriptionLoading }
123+ />
168124 ) }
169125
170126 { /* Codebuff credits section - structured layout */ }
@@ -190,7 +146,7 @@ export const UsageBanner = ({ showTime }: { showTime: number }) => {
190146 { adCredits != null && adCredits > 0 && (
191147 < text style = { { fg : theme . muted } } > { `(${ adCredits } from ads)` } </ text >
192148 ) }
193- { ! hasSubscription && renewalDate && (
149+ { ! activeSubscription && renewalDate && (
194150 < >
195151 < text style = { { fg : theme . muted } } > · Renews:</ text >
196152 < text style = { { fg : theme . foreground } } > { renewalDate } </ text >
@@ -239,3 +195,69 @@ export const UsageBanner = ({ showTime }: { showTime: number }) => {
239195 </ BottomBanner >
240196 )
241197}
198+
199+ interface SubscriptionUsageSectionProps {
200+ displayName ?: string
201+ subscriptionInfo ?: { tier : number }
202+ rateLimit ?: {
203+ blockLimit ?: number
204+ blockUsed ?: number
205+ blockResetsAt ?: string
206+ weeklyPercentUsed : number
207+ weeklyResetsAt : string
208+ }
209+ isLoading : boolean
210+ }
211+
212+ const SubscriptionUsageSection : React . FC < SubscriptionUsageSectionProps > = ( {
213+ displayName,
214+ subscriptionInfo,
215+ rateLimit,
216+ isLoading,
217+ } ) => {
218+ const theme = useTheme ( )
219+
220+ const blockPercent = useMemo ( ( ) => {
221+ if ( rateLimit ?. blockLimit == null || rateLimit . blockUsed == null ) return 100
222+ return Math . max ( 0 , 100 - Math . round ( ( rateLimit . blockUsed / rateLimit . blockLimit ) * 100 ) )
223+ } , [ rateLimit ?. blockLimit , rateLimit ?. blockUsed ] )
224+
225+ const weeklyPercent = rateLimit ? 100 - rateLimit . weeklyPercentUsed : 100
226+
227+ return (
228+ < box style = { { flexDirection : 'column' , marginBottom : 1 } } >
229+ < box style = { { flexDirection : 'row' , gap : 1 } } >
230+ < text style = { { fg : theme . foreground } } >
231+ 💪 { displayName ?? 'Strong' } subscription
232+ </ text >
233+ { subscriptionInfo ?. tier && (
234+ < text style = { { fg : theme . muted } } > ${ subscriptionInfo . tier } /mo</ text >
235+ ) }
236+ </ box >
237+ { isLoading ? (
238+ < text style = { { fg : theme . muted } } > Loading subscription data...</ text >
239+ ) : rateLimit ? (
240+ < box style = { { flexDirection : 'column' , gap : 0 } } >
241+ < box style = { { flexDirection : 'row' , alignItems : 'center' , gap : 0 } } >
242+ < text style = { { fg : theme . muted } } > 5-hour limit </ text >
243+ < text style = { { fg : theme . muted } } > { `${ blockPercent } %` . padStart ( 4 ) } </ text >
244+ < ProgressBar value = { blockPercent } width = { 12 } showPercentage = { false } />
245+ < text style = { { fg : theme . muted } } >
246+ { rateLimit . blockResetsAt
247+ ? ` resets in ${ formatResetTime ( new Date ( rateLimit . blockResetsAt ) ) } `
248+ : '' }
249+ </ text >
250+ </ box >
251+ < box style = { { flexDirection : 'row' , alignItems : 'center' , gap : 0 } } >
252+ < text style = { { fg : theme . muted } } > Weekly limit </ text >
253+ < text style = { { fg : theme . muted } } > { `${ weeklyPercent } %` . padStart ( 4 ) } </ text >
254+ < ProgressBar value = { weeklyPercent } width = { 12 } showPercentage = { false } />
255+ < text style = { { fg : theme . muted } } >
256+ { ' ' } resets in { formatResetTimeLong ( rateLimit . weeklyResetsAt ) }
257+ </ text >
258+ </ box >
259+ </ box >
260+ ) : null }
261+ </ box >
262+ )
263+ }
0 commit comments