@@ -4,24 +4,76 @@ import Popper from "@mui/material/Popper";
44import Paper from "@mui/material/Paper" ;
55import Stack from "@mui/material/Stack" ;
66import Typography from "@mui/material/Typography" ;
7+ import Divider from "@mui/material/Divider" ;
8+ import Box from "@mui/material/Box" ;
79import { useItemTooltip , useMouseTracker } from "@mui/x-charts" ;
810import { generateVirtualElement } from "./generateVirtualElement" ;
11+ import { BulkPoint , ProcessedTrialData , SoloPoint } from "@/types/global" ;
912
10- export function CustomItemTooltip ( ) {
13+ interface CustomItemTooltipProps {
14+ datePoints ?: Record < string , ProcessedTrialData [ ] > ;
15+ }
16+
17+ export function CustomItemTooltip ( { datePoints = { } } : CustomItemTooltipProps ) {
1118 const tooltipData = useItemTooltip ( ) ;
12- const mousePosition = useMouseTracker ( ) ; // Track the mouse position on chart.
19+ const mousePosition = useMouseTracker ( ) ;
1320
1421 if ( ! tooltipData || ! mousePosition ) {
15- // No data to display
1622 return null ;
1723 }
1824
19- // The pointer type can be used to have different behavior based on pointer type.
25+ const isSoloOrBulkPoint = (
26+ value : unknown
27+ ) : value is SoloPoint | BulkPoint => {
28+ return value !== null && typeof value === "object" && "id" in value ;
29+ } ;
30+
2031 const isMousePointer = mousePosition ?. pointerType === "mouse" ;
21- // Adapt the tooltip offset to the size of the pointer.
2232 const yOffset = isMousePointer ? 0 : 40 - mousePosition . height ;
33+ const getRangeMarkerType = ( ) => {
34+ if ( isSoloOrBulkPoint ( tooltipData . value ) ) {
35+ const id = tooltipData . value . id ;
36+ if ( id . startsWith ( "min-" ) ) return "Lowest Score" ;
37+ if ( id . startsWith ( "max-" ) ) return "Highest Score" ;
38+ }
39+ return null ;
40+ } ;
41+
42+ const getFormattedDate = ( ) => {
43+ if ( isSoloOrBulkPoint ( tooltipData . value ) ) {
44+ let dateString = tooltipData . value . id ;
45+
46+ // If it's a range marker, extract the actual date from the id
47+ if ( dateString . startsWith ( "min-" ) || dateString . startsWith ( "max-" ) ) {
48+ dateString = dateString . replace ( / ^ ( m i n - | m a x - ) / , "" ) ;
49+ }
50+
51+ const date = new Date ( dateString ) ;
52+ return date . toLocaleDateString ( "en-US" , {
53+ month : "long" ,
54+ day : "numeric" ,
55+ year : "numeric" ,
56+ } ) ;
57+ }
58+ return "Unknown Date" ;
59+ } ;
60+
61+ const getTrialsForPoint = ( ) => {
62+ if ( ! datePoints ) return [ ] ;
2363
24- console . log ( "tooltipData.value" , tooltipData . value ) ;
64+ if ( isSoloOrBulkPoint ( tooltipData . value ) ) {
65+ const dateKey = tooltipData . value . id ;
66+ if ( dateKey && datePoints [ dateKey ] ) {
67+ return datePoints [ dateKey ] ;
68+ }
69+ }
70+
71+ return [ ] ;
72+ } ;
73+
74+ const trials = getTrialsForPoint ( ) ;
75+ const formattedDate = getFormattedDate ( ) ;
76+ const isMultiTrial = trials . length > 1 ;
2577
2678 return (
2779 < NoSsr >
@@ -43,29 +95,102 @@ export function CustomItemTooltip() {
4395 ] }
4496 >
4597 < Paper
46- elevation = { 0 }
98+ elevation = { 2 }
4799 sx = { {
48100 m : 1 ,
49- p : 1.5 ,
50- border : "solid" ,
51- borderWidth : 2 ,
52- borderColor : "divider" ,
101+ p : 2 ,
102+ minWidth : 250 ,
103+ maxWidth : 350 ,
53104 } }
54105 >
55- < Stack direction = "row" alignItems = "center" >
56- < div
57- style = { {
58- width : 11 ,
59- height : 11 ,
60- borderRadius : "50%" ,
106+ < Typography variant = "subtitle1" sx = { { fontWeight : "bold" , mb : 1 } } >
107+ { formattedDate }
108+ </ Typography >
109+
110+ < Stack direction = "row" alignItems = "center" spacing = { 1 } >
111+ < Box
112+ sx = { {
113+ width : 12 ,
114+ height : 12 ,
61115 backgroundColor : tooltipData . color ,
62116 } }
63117 />
64- < Typography sx = { { ml : 2 } } fontWeight = "light" >
65- { tooltipData . label }
118+ < Typography variant = "body2" sx = { { fontWeight : "medium" } } >
119+ { getRangeMarkerType ( )
120+ ? `${ getRangeMarkerType ( ) } `
121+ : tooltipData . label }
122+ </ Typography >
123+ < Typography variant = "body2" sx = { { fontWeight : "bold" , ml : "auto" } } >
124+ { tooltipData . formattedValue }
66125 </ Typography >
67- < Typography sx = { { ml : 2 } } > { tooltipData . formattedValue } </ Typography >
68126 </ Stack >
127+
128+ { trials . length > 0 && (
129+ < >
130+ < Divider sx = { { my : 1 } } />
131+ < Typography variant = "body2" sx = { { fontWeight : "bold" , mb : 1 } } >
132+ { isMultiTrial && (
133+ < Typography
134+ variant = "body2"
135+ sx = { { fontWeight : "bold" , mb : 1 } }
136+ >
137+ Individual Trials
138+ </ Typography >
139+ ) }
140+ </ Typography >
141+
142+ < Stack spacing = { 0.5 } >
143+ { trials . map ( ( trial , idx ) => (
144+ < Stack
145+ key = { trial . trial_data_id || idx }
146+ direction = "row"
147+ justifyContent = "space-between"
148+ alignItems = "center"
149+ sx = { {
150+ py : 0.25 ,
151+ px : 1 ,
152+ backgroundColor :
153+ idx % 2 === 0 ? "action.hover" : "transparent" ,
154+ borderRadius : 0.5 ,
155+ } }
156+ >
157+ < Typography variant = "body2" sx = { { fontSize : "0.8rem" } } >
158+ { isMultiTrial ? `Trial ${ idx + 1 } ` : "Trial Detail" }
159+ </ Typography >
160+ < Typography
161+ variant = "body2"
162+ sx = { { fontSize : "0.8rem" , fontWeight : "medium" } }
163+ >
164+ { trial . successRate ?. toFixed ( 1 ) } %
165+ </ Typography >
166+ < Typography
167+ variant = "body2"
168+ sx = { { fontSize : "0.75rem" , color : "text.secondary" } }
169+ >
170+ ({ trial . success } /{ trial . numberOfAttempts } )
171+ </ Typography >
172+ </ Stack >
173+ ) ) }
174+ </ Stack >
175+
176+ { trials . length > 0 && (
177+ < Typography
178+ variant = "body2"
179+ sx = { {
180+ fontSize : "0.75rem" ,
181+ color : "text.secondary" ,
182+ mt : 1 ,
183+ fontStyle : "italic" ,
184+ } }
185+ >
186+ Staff:{ " " }
187+ { Array . from ( new Set ( trials . map ( ( t ) => t . staffName ) ) ) . join (
188+ ", "
189+ ) }
190+ </ Typography >
191+ ) }
192+ </ >
193+ ) }
69194 </ Paper >
70195 </ Popper >
71196 </ NoSsr >
0 commit comments