11'use client' ;
22
3+ import type { UsageResponse } from '@databuddy/shared' ;
34import { CalendarIcon , ChartBarIcon } from '@phosphor-icons/react' ;
45import { useMemo , useState } from 'react' ;
56import {
@@ -14,7 +15,6 @@ import {
1415import { DateRangePicker } from '@/components/date-range-picker' ;
1516import { Button } from '@/components/ui/button' ;
1617import { Skeleton } from '@/components/ui/skeleton' ;
17- import type { UsageResponse } from '@databuddy/shared' ;
1818import { calculateOverageCost , type OverageInfo } from '../utils/billing-utils' ;
1919
2020type ViewMode = 'daily' | 'cumulative' ;
@@ -46,7 +46,9 @@ export function ConsumptionChart({
4646 const [ hiddenTypes , setHiddenTypes ] = useState < Record < string , boolean > > ( { } ) ;
4747
4848 const chartData = useMemo ( ( ) => {
49- if ( ! usageData ?. dailyUsageByType ) return [ ] ;
49+ if ( ! usageData ?. dailyUsageByType ) {
50+ return [ ] ;
51+ }
5052
5153 // Group the real daily usage by type data by date
5254 const dailyDataMap = new Map < string , Record < string , number > > ( ) ;
@@ -74,7 +76,7 @@ export function ConsumptionChart({
7476 }
7577
7678 // Convert to chart format with cumulative calculation if needed
77- let runningTotals = Object . keys ( EVENT_TYPE_COLORS ) . reduce (
79+ const runningTotals = Object . keys ( EVENT_TYPE_COLORS ) . reduce (
7880 ( acc , key ) => {
7981 acc [ key ] = 0 ;
8082 return acc ;
@@ -113,8 +115,8 @@ export function ConsumptionChart({
113115
114116 if ( isLoading ) {
115117 return (
116- < div className = "h-full flex flex-col border-b" >
117- < div className = "px-6 py-4 border-b bg-muted/20" >
118+ < div className = "flex h-full flex-col border-b" >
119+ < div className = "border-b bg-muted/20 px-6 py-4 " >
118120 < div className = "flex items-center justify-between" >
119121 < Skeleton className = "h-6 w-48" />
120122 < Skeleton className = "h-8 w-32" />
@@ -129,20 +131,20 @@ export function ConsumptionChart({
129131
130132 if ( ! usageData || chartData . length === 0 ) {
131133 return (
132- < div className = "h-full flex flex-col border-b" >
133- < div className = "px-6 py-4 border-b bg-muted/20" >
134+ < div className = "flex h-full flex-col border-b" >
135+ < div className = "border-b bg-muted/20 px-6 py-4 " >
134136 < div className = "flex items-center gap-2" >
135137 < ChartBarIcon className = "h-5 w-5" weight = "duotone" />
136- < h2 className = "text-lg font-semibold" > Consumption Breakdown</ h2 >
138+ < h2 className = "font-semibold text-lg " > Consumption Breakdown</ h2 >
137139 </ div >
138140 </ div >
139- < div className = "flex-1 px-6 py-6 flex items-center justify-center" >
141+ < div className = "flex flex -1 items-center justify-center px-6 py-6 " >
140142 < div className = "text-center" >
141143 < CalendarIcon
142- className = "mx-auto h-12 w-12 text-muted-foreground mb-4 "
144+ className = "mx-auto mb-4 h-12 w-12 text-muted-foreground"
143145 weight = "duotone"
144146 />
145- < h3 className = "text-lg font-semibold" > No Data Available</ h3 >
147+ < h3 className = "font-semibold text-lg " > No Data Available</ h3 >
146148 < p className = "text-muted-foreground" >
147149 No usage data found for the selected period
148150 </ p >
@@ -163,12 +165,12 @@ export function ConsumptionChart({
163165 const yAxisMax = Math . ceil ( maxValue * 1.1 ) ;
164166
165167 return (
166- < div className = "h-full flex flex-col border-b" >
167- < div className = "px-6 py-4 border-b bg-muted/20" >
168+ < div className = "flex h-full flex-col border-b" >
169+ < div className = "border-b bg-muted/20 px-6 py-4 " >
168170 < div className = "flex items-center justify-between" >
169171 < div className = "flex items-center gap-2" >
170172 < ChartBarIcon className = "h-5 w-5" weight = "duotone" />
171- < h2 className = "text-lg font-semibold" > Consumption Breakdown</ h2 >
173+ < h2 className = "font-semibold text-lg " > Consumption Breakdown</ h2 >
172174 </ div >
173175 < div className = "flex items-center gap-2" >
174176 < DateRangePicker
@@ -190,25 +192,24 @@ export function ConsumptionChart({
190192 />
191193 < div className = "flex rounded border" >
192194 < Button
193- variant = { viewMode === 'cumulative' ? 'default' : 'ghost' }
194- size = "sm"
195- onClick = { ( ) => setViewMode ( 'cumulative' ) }
196195 className = "rounded-r-none border-r"
196+ onClick = { ( ) => setViewMode ( 'cumulative' ) }
197+ size = "sm"
198+ variant = { viewMode === 'cumulative' ? 'default' : 'ghost' }
197199 >
198200 Cumulative
199201 </ Button >
200202 < Button
201- variant = { viewMode === 'daily' ? 'default' : 'ghost' }
202- size = "sm"
203- onClick = { ( ) => setViewMode ( 'daily' ) }
204203 className = "rounded-l-none"
204+ onClick = { ( ) => setViewMode ( 'daily' ) }
205+ size = "sm"
206+ variant = { viewMode === 'daily' ? 'default' : 'ghost' }
205207 >
206208 Daily
207209 </ Button >
208210 </ div >
209211 < Button
210- variant = "outline"
211- size = "sm"
212+ className = "text-xs"
212213 onClick = { ( ) => {
213214 const allHidden = Object . keys ( EVENT_TYPE_COLORS ) . reduce (
214215 ( acc , key ) => {
@@ -219,7 +220,8 @@ export function ConsumptionChart({
219220 ) ;
220221 setHiddenTypes ( allHidden ) ;
221222 } }
222- className = "text-xs"
223+ size = "sm"
224+ variant = "outline"
223225 >
224226 Select None
225227 </ Button >
@@ -228,7 +230,7 @@ export function ConsumptionChart({
228230 </ div >
229231 < div className = "flex-1 px-6 py-6" >
230232 < div className = "h-full" >
231- < ResponsiveContainer width = "100%" height = "100%" >
233+ < ResponsiveContainer height = "100%" width = "100%" >
232234 < BarChart
233235 data = { chartData }
234236 margin = { { top : 20 , right : 30 , left : 20 , bottom : 5 } }
@@ -252,31 +254,34 @@ export function ConsumptionChart({
252254 ) ) }
253255 </ defs >
254256 < XAxis
255- dataKey = "date"
256257 axisLine = { { stroke : 'var(--border)' , strokeOpacity : 0.5 } }
257- tickLine = { false }
258+ dataKey = "date"
258259 tick = { {
259260 fontSize : 11 ,
260261 fill : 'var(--muted-foreground)' ,
261262 fontWeight : 500 ,
262263 } }
264+ tickLine = { false }
263265 />
264266 < YAxis
265267 axisLine = { false }
266- tickLine = { false }
268+ domain = { [ 0 , yAxisMax ] }
267269 tick = { {
268270 fontSize : 11 ,
269271 fill : 'var(--muted-foreground)' ,
270272 fontWeight : 500 ,
271273 } }
272- width = { 45 }
273- domain = { [ 0 , yAxisMax ] }
274274 tickFormatter = { ( value ) => {
275- if ( value >= 1_000_000 )
275+ if ( value >= 1_000_000 ) {
276276 return `${ ( value / 1_000_000 ) . toFixed ( 1 ) } M` ;
277- if ( value >= 1000 ) return `${ ( value / 1000 ) . toFixed ( 1 ) } k` ;
277+ }
278+ if ( value >= 1000 ) {
279+ return `${ ( value / 1000 ) . toFixed ( 1 ) } k` ;
280+ }
278281 return value . toString ( ) ;
279282 } }
283+ tickLine = { false }
284+ width = { 45 }
280285 />
281286 < Tooltip
282287 content = { ( { active, payload, label } ) => {
@@ -310,8 +315,8 @@ export function ConsumptionChart({
310315
311316 return (
312317 < div
313- key = { index }
314318 className = "group flex items-center justify-between gap-3"
319+ key = { index }
315320 >
316321 < div className = "flex items-center gap-2.5" >
317322 < div
@@ -328,7 +333,7 @@ export function ConsumptionChart({
328333 < div className = "font-bold text-foreground text-sm group-hover:text-primary" >
329334 { eventCount . toLocaleString ( ) }
330335 </ div >
331- < div className = "text-xs text- muted-foreground" >
336+ < div className = "text-muted-foreground text-xs " >
332337 ${ overageCost . toFixed ( 6 ) }
333338 </ div >
334339 </ div >
@@ -345,15 +350,16 @@ export function ConsumptionChart({
345350 wrapperStyle = { { outline : 'none' } }
346351 />
347352 < Legend
353+ align = "center"
348354 formatter = { ( value ) => {
349355 const key = String ( value ) ;
350356 const isHidden = hiddenTypes [ key ] ;
351357 return (
352358 < span
353- className = { `inline-flex items-center text-xs font-medium capitalize transition-all duration-200 select-none leading-none ${
359+ className = { `inline-flex select-none items-center font-medium text-xs capitalize leading-none transition-all duration-200 ${
354360 isHidden
355- ? 'opacity-40 text-slate-600 line-through decoration-1'
356- : 'opacity-100 text-muted-foreground'
361+ ? 'text-slate-600 line-through decoration-1 opacity-40 '
362+ : 'text-muted-foreground opacity-100 '
357363 } `}
358364 >
359365 { key . replace ( '_' , ' ' ) }
@@ -362,19 +368,20 @@ export function ConsumptionChart({
362368 } }
363369 iconSize = { 10 }
364370 iconType = "circle"
371+ layout = "horizontal"
365372 onClick = { ( payload ) => {
366373 const anyPayload = payload as unknown as {
367374 dataKey ?: string | number ;
368375 value ?: string | number ;
369376 } ;
370377 const raw = anyPayload ?. dataKey ?? anyPayload ?. value ;
371- if ( raw == null ) return ;
378+ if ( raw == null ) {
379+ return ;
380+ }
372381 const key = String ( raw ) ;
373382 setHiddenTypes ( ( prev ) => ( { ...prev , [ key ] : ! prev [ key ] } ) ) ;
374383 } }
375- align = "center"
376384 verticalAlign = "bottom"
377- layout = "horizontal"
378385 wrapperStyle = { {
379386 display : 'flex' ,
380387 justifyContent : 'center' ,
@@ -387,17 +394,17 @@ export function ConsumptionChart({
387394 />
388395 { Object . keys ( EVENT_TYPE_COLORS ) . map ( ( eventType ) => (
389396 < Bar
390- key = { eventType }
391397 dataKey = { eventType }
392- stackId = "events"
393398 fill = { `url(#gradient-${ eventType } )` }
399+ hide = { ! ! hiddenTypes [ eventType ] }
400+ key = { eventType }
401+ stackId = "events"
394402 stroke = {
395403 EVENT_TYPE_COLORS [
396404 eventType as keyof typeof EVENT_TYPE_COLORS
397405 ]
398406 }
399407 strokeWidth = { 0.5 }
400- hide = { ! ! hiddenTypes [ eventType ] }
401408 style = { {
402409 filter : 'none' ,
403410 transition : 'none' ,
0 commit comments