1+ import { Tag } from "lucide-react" ;
2+ import { useMemo } from "react" ;
13import type { DecodedMessage } from "@/hooks/use-channel-messages" ;
24import { useChartData } from "@/hooks/use-chart-data" ;
35import { SensorChart } from "@/components/shared/sensor-chart" ;
6+ import { StatCard } from "@/components/shared/stat-card" ;
47
58const COLORS = [
69 "#0ea5e9" , // sky-500
@@ -11,25 +14,53 @@ const COLORS = [
1114 "#f43f5e" , // rose-500
1215] ;
1316
17+ const TIMESTAMP_KEYS = new Set ( [ "ts" , "timestamp" ] ) ;
18+
19+ function useTextFields ( messages : DecodedMessage [ ] ) : { key : string ; value : string } [ ] {
20+ return useMemo ( ( ) => {
21+ const latest = messages . find ( ( m ) => m . envelope ) ;
22+ if ( ! latest ?. envelope ) return [ ] ;
23+ return Object . entries ( latest . envelope . p )
24+ . filter ( ( [ key , val ] ) => {
25+ if ( typeof val === "number" ) return false ;
26+ if ( TIMESTAMP_KEYS . has ( key . toLowerCase ( ) ) ) return false ;
27+ return val != null ;
28+ } )
29+ . map ( ( [ key , val ] ) => ( { key, value : String ( val ) } ) ) ;
30+ } , [ messages ] ) ;
31+ }
32+
1433interface SensorChartsProps {
1534 messages : DecodedMessage [ ] ;
1635}
1736
1837export function SensorCharts ( { messages } : SensorChartsProps ) {
1938 const series = useChartData ( messages ) ;
39+ const textFields = useTextFields ( messages ) ;
2040
21- if ( series . length === 0 ) return null ;
41+ if ( series . length === 0 && textFields . length === 0 ) return null ;
2242
2343 return (
24- < div className = "grid grid-cols-1 lg:grid-cols-3 gap-4" >
25- { series . map ( ( s , i ) => (
26- < SensorChart
27- key = { s . key }
28- title = { s . key }
29- data = { s . data }
30- color = { COLORS [ i % COLORS . length ] }
31- />
32- ) ) }
44+ < div className = "space-y-4" >
45+ { textFields . length > 0 && (
46+ < div className = "grid grid-cols-2 sm:grid-cols-3 gap-3 sm:gap-4" >
47+ { textFields . map ( ( f ) => (
48+ < StatCard key = { f . key } title = { f . key } value = { f . value } icon = { Tag } accent = "violet" />
49+ ) ) }
50+ </ div >
51+ ) }
52+ { series . length > 0 && (
53+ < div className = "grid grid-cols-1 lg:grid-cols-2 gap-4" >
54+ { series . map ( ( s , i ) => (
55+ < SensorChart
56+ key = { s . key }
57+ title = { s . key }
58+ data = { s . data }
59+ color = { COLORS [ i % COLORS . length ] }
60+ />
61+ ) ) }
62+ </ div >
63+ ) }
3364 </ div >
3465 ) ;
3566}
0 commit comments