@@ -18,7 +18,12 @@ import {
1818 CardTitle ,
1919} from '@/components/ui/card' ;
2020import { cn } from '@/lib/utils' ;
21- import { type ChartDataRow , METRIC_COLORS , METRICS } from './metrics-constants' ;
21+ import {
22+ type ChartDataRow ,
23+ METRIC_COLORS ,
24+ METRICS ,
25+ type MetricConfig ,
26+ } from './metrics-constants' ;
2227import { SkeletonChart } from './skeleton-chart' ;
2328
2429const CustomTooltip = ( {
@@ -97,6 +102,8 @@ interface MetricsChartProps {
97102 className ?: string ;
98103 hiddenMetrics ?: Record < string , boolean > ;
99104 onToggleMetric ?: ( metricKey : string ) => void ;
105+ metricsFilter ?: ( metric : MetricConfig ) => boolean ;
106+ showLegend ?: boolean ;
100107}
101108
102109export function MetricsChart ( {
@@ -108,6 +115,8 @@ export function MetricsChart({
108115 className,
109116 hiddenMetrics = { } ,
110117 onToggleMetric,
118+ metricsFilter,
119+ showLegend = true ,
111120} : MetricsChartProps ) {
112121 const chartData = useMemo ( ( ) => data || [ ] , [ data ] ) ;
113122
@@ -174,15 +183,17 @@ export function MetricsChart({
174183 ) ;
175184 }
176185
177- const analyticsMetrics = METRICS . filter ( ( metric ) =>
178- [
179- 'pageviews' ,
180- 'visitors' ,
181- 'sessions' ,
182- 'bounce_rate' ,
183- 'avg_session_duration' ,
184- ] . includes ( metric . key )
185- ) ;
186+ const displayMetrics = metricsFilter
187+ ? METRICS . filter ( metricsFilter )
188+ : METRICS . filter ( ( metric ) =>
189+ [
190+ 'pageviews' ,
191+ 'visitors' ,
192+ 'sessions' ,
193+ 'bounce_rate' ,
194+ 'avg_session_duration' ,
195+ ] . includes ( metric . key )
196+ ) ;
186197
187198 return (
188199 < Card className = { cn ( 'w-full overflow-hidden rounded-none p-0' , className ) } >
@@ -268,85 +279,89 @@ export function MetricsChart({
268279 } }
269280 wrapperStyle = { { outline : 'none' } }
270281 />
271- < Legend
272- align = "center"
273- formatter = { ( value ) => {
274- const metric = analyticsMetrics . find (
275- ( m ) => m . label === value || m . key === value
276- ) ;
277- if ( ! metric ) {
278- // Fallback for unknown metrics
279- return (
280- < span className = "inline-flex cursor-pointer select-none items-center font-medium text-muted-foreground text-xs capitalize leading-none opacity-100 transition-all duration-200 hover:text-foreground" >
281- { String ( value ) . replace ( / _ / g, ' ' ) }
282- </ span >
282+ { showLegend && (
283+ < Legend
284+ align = "center"
285+ formatter = { ( value ) => {
286+ const metric = displayMetrics . find (
287+ ( m ) => m . label === value || m . key === value
283288 ) ;
284- }
289+ if ( ! metric ) {
290+ // Fallback for unknown metrics
291+ return (
292+ < span className = "inline-flex cursor-pointer select-none items-center font-medium text-muted-foreground text-xs capitalize leading-none opacity-100 transition-all duration-200 hover:text-foreground" >
293+ { String ( value ) . replace ( / _ / g, ' ' ) }
294+ </ span >
295+ ) ;
296+ }
285297
286- const hasData = chartData . some (
287- ( item ) =>
288- metric . key in item &&
289- item [ metric . key ] !== undefined &&
290- item [ metric . key ] !== null
291- ) ;
292- const isHidden = hiddenMetrics [ metric . key ] ;
298+ const hasData = chartData . some (
299+ ( item ) =>
300+ metric . key in item &&
301+ item [ metric . key ] !== undefined &&
302+ item [ metric . key ] !== null
303+ ) ;
304+ const isHidden = hiddenMetrics [ metric . key ] ;
293305
294- return (
295- < span
296- className = { `inline-flex cursor-pointer select-none items-center font-medium text-xs capitalize leading-none transition-all duration-200 ${
297- isHidden
298- ? 'text-slate-600 line-through decoration-1 opacity-40'
299- : hasData
300- ? 'text-muted-foreground opacity-100 hover:text-foreground'
301- : 'text-muted-foreground/60 opacity-60 hover:text-foreground'
302- } `}
303- >
304- { metric . label }
305- </ span >
306- ) ;
307- } }
308- iconSize = { 10 }
309- iconType = "circle"
310- layout = "horizontal"
311- onClick = { ( payload ) => {
312- const anyPayload = payload as unknown as {
313- dataKey ?: string | number ;
314- value ?: string | number ;
315- id ?: string | number ;
316- } ;
317- const raw =
318- anyPayload ?. dataKey ?? anyPayload ?. value ?? anyPayload ?. id ;
319- if ( raw == null || ! onToggleMetric ) {
320- return ;
321- }
322- const key = String ( raw ) ;
323- const metric = analyticsMetrics . find (
324- ( m ) => m . label === key || m . key === key
325- ) ;
326- if ( metric ) {
327- onToggleMetric ( metric . key ) ;
328- }
329- } }
330- payload = { analyticsMetrics . map ( ( metric ) => ( {
331- value : metric . label ,
332- type : 'circle' ,
333- color : metric . color ,
334- id : metric . key ,
335- dataKey : metric . key ,
336- } ) ) }
337- verticalAlign = "bottom"
338- wrapperStyle = { {
339- display : 'flex' ,
340- justifyContent : 'center' ,
341- gap : 12 ,
342- fontSize : '12px' ,
343- paddingTop : '20px' ,
344- bottom : chartData . length > 5 ? 35 : 5 ,
345- fontWeight : 500 ,
346- cursor : 'pointer' ,
347- } }
348- />
349- { analyticsMetrics . map ( ( metric ) => {
306+ return (
307+ < span
308+ className = { `inline-flex cursor-pointer select-none items-center font-medium text-xs capitalize leading-none transition-all duration-200 ${
309+ isHidden
310+ ? 'text-slate-600 line-through decoration-1 opacity-40'
311+ : hasData
312+ ? 'text-muted-foreground opacity-100 hover:text-foreground'
313+ : 'text-muted-foreground/60 opacity-60 hover:text-foreground'
314+ } `}
315+ >
316+ { metric . label }
317+ </ span >
318+ ) ;
319+ } }
320+ iconSize = { 10 }
321+ iconType = "circle"
322+ layout = "horizontal"
323+ onClick = { ( payload ) => {
324+ const anyPayload = payload as unknown as {
325+ dataKey ?: string | number ;
326+ value ?: string | number ;
327+ id ?: string | number ;
328+ } ;
329+ const raw =
330+ anyPayload ?. dataKey ??
331+ anyPayload ?. value ??
332+ anyPayload ?. id ;
333+ if ( raw == null || ! onToggleMetric ) {
334+ return ;
335+ }
336+ const key = String ( raw ) ;
337+ const metric = displayMetrics . find (
338+ ( m ) => m . label === key || m . key === key
339+ ) ;
340+ if ( metric ) {
341+ onToggleMetric ( metric . key ) ;
342+ }
343+ } }
344+ payload = { displayMetrics . map ( ( metric ) => ( {
345+ value : metric . label ,
346+ type : 'circle' ,
347+ color : metric . color ,
348+ id : metric . key ,
349+ dataKey : metric . key ,
350+ } ) ) }
351+ verticalAlign = "bottom"
352+ wrapperStyle = { {
353+ display : 'flex' ,
354+ justifyContent : 'center' ,
355+ gap : 12 ,
356+ fontSize : '12px' ,
357+ paddingTop : '20px' ,
358+ bottom : chartData . length > 5 ? 35 : 5 ,
359+ fontWeight : 500 ,
360+ cursor : 'pointer' ,
361+ } }
362+ />
363+ ) }
364+ { displayMetrics . map ( ( metric ) => {
350365 const hasData = chartData . some (
351366 ( item ) =>
352367 metric . key in item &&
0 commit comments