@@ -10,33 +10,34 @@ import { usageQueryKeys, useUsageQuery } from '../hooks/use-usage-query'
1010import { useChatStore } from '../state/chat-store'
1111import {
1212 getBannerColorLevel ,
13- generateUsageBannerText ,
1413 generateLoadingBannerText ,
1514} from '../utils/usage-banner-state'
1615import { WEBSITE_URL } from '../login/constants'
1716import { useTheme } from '../hooks/use-theme'
1817import { isClaudeOAuthValid } from '@codebuff/sdk'
1918
19+ import { formatResetTime } from '../utils/time-format'
20+
2021const MANUAL_SHOW_TIMEOUT = 60 * 1000 // 1 minute
2122const USAGE_POLL_INTERVAL = 30 * 1000 // 30 seconds
2223
2324/**
24- * Format time until reset in human-readable form
25+ * Format the renewal date for display
2526 */
26- const formatResetTime = ( resetDate : Date | null ) : string => {
27- if ( ! resetDate ) return ''
28- const now = new Date ( )
29- const diffMs = resetDate . getTime ( ) - now . getTime ( )
30- if ( diffMs <= 0 ) return 'now'
31-
32- const diffMins = Math . floor ( diffMs / ( 1000 * 60 ) )
33- const diffHours = Math . floor ( diffMins / 60 )
34- const remainingMins = diffMins % 60
35-
36- if ( diffHours > 0 ) {
37- return ` ${ diffHours } h ${ remainingMins } m`
38- }
39- return ` ${ diffMins } m`
27+ const formatRenewalDate = ( dateStr : string | null ) : string => {
28+ if ( ! dateStr ) return ''
29+ const resetDate = new Date ( dateStr )
30+ const today = new Date ( )
31+ const isToday = resetDate . toDateString ( ) === today . toDateString ( )
32+ return isToday
33+ ? resetDate . toLocaleString ( 'en-US' , {
34+ hour : 'numeric' ,
35+ minute : '2-digit' ,
36+ } )
37+ : resetDate . toLocaleDateString ( 'en-US' , {
38+ month : 'short' ,
39+ day : 'numeric' ,
40+ } )
4041}
4142
4243export const UsageBanner = ( { showTime } : { showTime : number } ) => {
@@ -106,36 +107,54 @@ export const UsageBanner = ({ showTime }: { showTime: number }) => {
106107 }
107108
108109 const colorLevel = getBannerColorLevel ( activeData . remainingBalance )
109-
110- // Show loading indicator if refreshing data
111- const text = isLoadingData
112- ? generateLoadingBannerText ( sessionCreditsUsed )
113- : generateUsageBannerText ( {
114- sessionCreditsUsed,
115- remainingBalance : activeData . remainingBalance ,
116- next_quota_reset : activeData . next_quota_reset ,
117- adCredits : activeData . balanceBreakdown ?. ad ,
118- } )
110+ const adCredits = activeData . balanceBreakdown ?. ad
111+ const renewalDate = activeData . next_quota_reset ? formatRenewalDate ( activeData . next_quota_reset ) : null
119112
120113 return (
121114 < BottomBanner
122115 borderColorKey = { isLoadingData ? 'muted' : colorLevel }
123116 onClose = { ( ) => setInputMode ( 'default' ) }
124117 >
125118 < box style = { { flexDirection : 'column' , gap : 0 } } >
126- { /* Codebuff credits section */ }
119+ { /* Codebuff credits section - structured layout */ }
127120 < Button
128121 onClick = { ( ) => {
129122 open ( WEBSITE_URL + '/usage' )
130123 } }
131124 >
132- < text style = { { fg : theme . foreground } } > { text } </ text >
125+ < box style = { { flexDirection : 'column' , gap : 0 } } >
126+ { /* Main stats row */ }
127+ < box style = { { flexDirection : 'row' , flexWrap : 'wrap' , gap : 1 } } >
128+ < text style = { { fg : theme . muted } } > Session:</ text >
129+ < text style = { { fg : theme . foreground } } > { sessionCreditsUsed . toLocaleString ( ) } </ text >
130+ < text style = { { fg : theme . muted } } > ·</ text >
131+ < text style = { { fg : theme . muted } } > Remaining:</ text >
132+ { isLoadingData ? (
133+ < text style = { { fg : theme . muted } } > ...</ text >
134+ ) : (
135+ < text style = { { fg : theme . foreground } } >
136+ { activeData . remainingBalance ?. toLocaleString ( ) ?? '?' }
137+ </ text >
138+ ) }
139+ { adCredits != null && adCredits > 0 && (
140+ < text style = { { fg : theme . muted } } > { `(${ adCredits } from ads)` } </ text >
141+ ) }
142+ { renewalDate && (
143+ < >
144+ < text style = { { fg : theme . muted } } > · Renews:</ text >
145+ < text style = { { fg : theme . foreground } } > { renewalDate } </ text >
146+ </ >
147+ ) }
148+ </ box >
149+ { /* See more link */ }
150+ < text style = { { fg : theme . muted } } > ↗ See more on codebuff.com</ text >
151+ </ box >
133152 </ Button >
134153
135154 { /* Claude subscription section - only show if connected */ }
136155 { isClaudeConnected && (
137156 < box style = { { flexDirection : 'column' , marginTop : 1 } } >
138- < text style = { { fg : theme . primary } } > Claude subscription</ text >
157+ < text style = { { fg : theme . muted } } > Claude subscription</ text >
139158 { isClaudeLoading ? (
140159 < text style = { { fg : theme . muted } } > Loading quota...</ text >
141160 ) : claudeQuota ? (
0 commit comments