44import React , { useState } from 'react' ;
55import Box from '@mui/material/Box' ;
66import { Localization } from 'types/localization' ;
7- import { TextField , Typography , useTheme } from '@mui/material' ;
7+ import { Button , useTheme } from '@mui/material' ;
8+ import TextField from '@mui/material/TextField' ;
9+ import Typography from '@mui/material/Typography' ;
10+ import Snackbar from '@mui/material/Snackbar' ;
811import Tooltip from '@mui/material/Tooltip' ;
912import IconButton from '@mui/material/IconButton' ;
1013import CheckIcon from '@mui/icons-material/Check' ;
1114import CancelIcon from '@mui/icons-material/Cancel' ;
1215import EditIcon from '@mui/icons-material/Edit' ;
1316import RefreshIcon from '@mui/icons-material/Refresh' ;
14-
17+ import Divider from '@mui/material/Divider' ;
18+ import Portal from '@mui/material/Portal' ;
19+ import Alert from '@mui/material/Alert' ;
20+ import { useTranslation } from 'react-i18next' ;
1521interface YAxisValueSettingsProps {
22+ /** The maximum value for the Y-axis */
1623 yAxisMaxValue : number | undefined ;
24+
25+ /** The actual maximum value of the currently displayed data on the chart*/
1726 maxDataValue : number ;
27+
28+ /** The function to update the Y-axis maximum value */
1829 updateYAxisMaxValue : ( newYAxisMaxValue : number ) => void ;
30+
31+ /** The localization object */
1932 localization : Localization ;
2033}
2134
@@ -30,20 +43,53 @@ export default function YAxisValueSettings({
3043 } ,
3144} : YAxisValueSettingsProps ) {
3245 const theme = useTheme ( ) ;
46+ const { t} = useTranslation ( 'settings' ) ;
3347 const [ localYAxisMaxValue , setLocalYAxisMaxValue ] = useState < number | null > ( yAxisMaxValue ?? maxDataValue ) ;
3448 const [ editing , setEditing ] = useState < boolean > ( false ) ;
35- const isValid = localYAxisMaxValue !== null && localYAxisMaxValue > 0 ;
49+ const [ snackbarOpen , setSnackbarOpen ] = useState < boolean > ( false ) ;
50+ const [ snackbarMessage , setSnackbarMessage ] = useState < string > ( '' ) ;
51+ const [ snackbarSeverity , setSnackbarSeverity ] = useState < 'success' | 'info' | 'warning' | 'error' > ( 'info' ) ;
52+ const [ errors , setErrors ] = useState < string [ ] > ( [ ] ) ;
3653
3754 const getFormattedAndTranslatedValues = ( filteredValues : number ) : string => {
3855 return localization . formatNumber ? localization . formatNumber ( filteredValues ) : filteredValues . toString ( ) ;
3956 } ;
4057
41- const handleSave = ( ) => {
42- if ( localYAxisMaxValue === null || localYAxisMaxValue < 0 ) return ;
43- console . log ( 'localYAxisMaxValue' , localYAxisMaxValue ) ;
44- updateYAxisMaxValue ( localYAxisMaxValue ) ;
45- setEditing ( false ) ;
46- console . log ( 'UPDATE Y-AXIS MAX VALUE' ) ;
58+ const validateInput = ( newYValue : number | null ) : boolean => {
59+ const errors : string [ ] = [ ] ;
60+ if ( newYValue === null || newYValue < 0 ) {
61+ errors . push ( t ( 'y-axis-settings.validation.positiveNumber' ) ) ;
62+ }
63+
64+ setErrors ( errors ) ;
65+ return errors . length === 0 ;
66+ } ;
67+
68+ const handleSnackbarOpen = ( message : string , severity : 'success' | 'info' | 'warning' | 'error' = 'info' ) => {
69+ setSnackbarMessage ( message ) ;
70+ setSnackbarSeverity ( severity ) ;
71+ setSnackbarOpen ( true ) ;
72+ } ;
73+
74+ const handleSave = ( newYValue : number | null ) => {
75+ if ( newYValue === null ) {
76+ updateYAxisMaxValue ( maxDataValue ) ;
77+ setLocalYAxisMaxValue ( maxDataValue ) ;
78+ setEditing ( false ) ;
79+ return ;
80+ }
81+
82+ if ( validateInput ( newYValue ) ) {
83+ if ( newYValue === yAxisMaxValue ) {
84+ setEditing ( false ) ;
85+ return ;
86+ }
87+
88+ updateYAxisMaxValue ( newYValue ) ;
89+ setLocalYAxisMaxValue ( newYValue ) ;
90+ setEditing ( false ) ;
91+ handleSnackbarOpen ( t ( 'y-axis-settings.messages.success' ) , 'success' ) ;
92+ }
4793 } ;
4894
4995 const handleCancel = ( ) => {
@@ -57,33 +103,74 @@ export default function YAxisValueSettings({
57103 } ;
58104
59105 return (
60- < Box sx = { { width : '100%' , marginLeft : 4 } } >
61- { editing ? (
62- < Box
106+ < Box
107+ sx = { {
108+ width : '100%' ,
109+ marginLeft : 4 ,
110+ display : 'flex' ,
111+ flexDirection : 'row' ,
112+ alignItems : 'center' ,
113+ gap : 4 ,
114+ } }
115+ >
116+ < Portal >
117+ < Snackbar
118+ open = { snackbarOpen }
119+ autoHideDuration = { 4000 }
120+ onClose = { ( ) => setSnackbarOpen ( false ) }
121+ anchorOrigin = { { vertical : 'bottom' , horizontal : 'left' } }
122+ >
123+ < Alert severity = { snackbarSeverity } > { snackbarMessage } </ Alert >
124+ </ Snackbar >
125+ </ Portal >
126+ < Box sx = { { display : 'flex' , flexDirection : 'row' , alignItems : 'center' , gap : 2 } } >
127+ < Typography
128+ variant = 'h2'
63129 sx = { {
64- display : 'flex' ,
65- flexDirection : 'row' ,
66- gap : 1 ,
67- alignItems : 'center' ,
68- justifyContent : 'space-between' ,
130+ color : theme . palette . primary . main ,
131+ textTransform : 'uppercase' ,
132+ paddingRight : 2 ,
69133 } }
70134 >
71- < Typography variant = 'h2' sx = { { color : 'black' } } >
72- Y-Axis Maximum
73- </ Typography >
74- < Box sx = { { display : 'flex' , flexDirection : 'row' , gap : 1 , alignItems : 'center' } } >
135+ { t ( 'y-axis-settings.title' ) }
136+ </ Typography >
137+ </ Box >
138+ < Divider orientation = 'vertical' flexItem />
139+ < Box
140+ sx = { {
141+ display : 'flex' ,
142+ flexDirection : 'row' ,
143+ gap : 1 ,
144+ flex : 1 ,
145+ alignItems : 'center' ,
146+ justifyContent : 'space-between' ,
147+ } }
148+ >
149+ { editing ? (
150+ < Box
151+ sx = { {
152+ display : 'flex' ,
153+ flexDirection : 'row' ,
154+ gap : 3 ,
155+ alignItems : 'center' ,
156+ width : '100%' ,
157+ justifyContent : 'space-between' ,
158+ } }
159+ >
75160 < TextField
76- label = 'Y-Axis Max Value'
77161 id = 'y-axis-max-value'
78162 value = { localYAxisMaxValue }
79163 placeholder = { getFormattedAndTranslatedValues ( yAxisMaxValue ?? maxDataValue ) }
80- error = { ! isValid }
164+ error = { errors . length > 0 }
165+ helperText = { errors . join ( ', ' ) }
81166 onChange = { ( e ) => {
167+ setErrors ( [ ] ) ;
82168 const value = e . target . value === '' ? null : Number ( e . target . value ) ;
83169 setLocalYAxisMaxValue ( value ) ;
84170 } }
85171 size = 'small'
86172 variant = 'outlined'
173+ sx = { { width : '100%' } }
87174 />
88175 < Box
89176 sx = { {
@@ -97,9 +184,9 @@ export default function YAxisValueSettings({
97184 data-testid = 'save-threshold'
98185 onClick = { ( e ) => {
99186 e . stopPropagation ( ) ;
100- handleSave ( ) ;
187+ handleSave ( localYAxisMaxValue ) ;
101188 } }
102- disabled = { ! isValid }
189+ disabled = { errors . length > 0 }
103190 sx = { { color : theme . palette . success . main } }
104191 >
105192 < CheckIcon />
@@ -117,49 +204,54 @@ export default function YAxisValueSettings({
117204 </ IconButton >
118205 </ Box >
119206 </ Box >
120- </ Box >
121- ) : (
122- < Box
123- sx = { {
124- display : 'flex' ,
125- flexDirection : 'row' ,
126-
127- justifyContent : 'space-between' ,
128- alignItems : 'center' ,
129- } }
130- >
131- < Box sx = { { display : 'flex' , flexDirection : 'column' , alignItems : 'flex-start' } } >
132- < Typography variant = 'h2' sx = { { color : 'black' } } >
133- Y-Axis Maximum
134- </ Typography >
135- < Typography variant = 'caption' sx = { { color : 'gray' } } >
136- Global maximum value of the y-axis.
137- </ Typography >
138- </ Box >
139- < Box sx = { { display : 'flex' , flexDirection : 'row' , gap : 2 , alignItems : 'center' } } >
140- < Typography variant = 'h2' sx = { { marginRight : '1rem' } } >
141- { getFormattedAndTranslatedValues ( yAxisMaxValue ?? maxDataValue ) }
142- </ Typography >
207+ ) : (
208+ < Box
209+ sx = { {
210+ display : 'flex' ,
211+ flexDirection : 'row' ,
212+ gap : 3 ,
213+ alignItems : 'center' ,
214+ width : '100%' ,
215+ justifyContent : 'space-between' ,
216+ } }
217+ >
218+ < Button
219+ variant = 'text'
220+ onClick = { ( ) => setEditing ( true ) }
221+ sx = { {
222+ cursor : 'text' ,
223+ } }
224+ >
225+ < Typography
226+ variant = 'body1'
227+ sx = { {
228+ color : 'black' ,
229+ } }
230+ >
231+ { getFormattedAndTranslatedValues ( yAxisMaxValue ?? maxDataValue ) }
232+ </ Typography >
233+ </ Button >
143234 < Box sx = { { display : 'flex' , flexDirection : 'row' , gap : 1 , alignItems : 'center' } } >
144- < Tooltip title = 'Edit Y-Axis Maximum' >
235+ < Tooltip title = { t ( 'y-axis-settings.editTooltip' ) } >
145236 < IconButton onClick = { ( ) => setEditing ( true ) } >
146237 < EditIcon />
147238 </ IconButton >
148239 </ Tooltip >
149- < Tooltip title = 'Reset to current data maximum value' >
240+ < Tooltip title = { t ( 'y-axis-settings.resetTooltip' ) } >
150241 < IconButton
151242 onClick = { ( e ) => {
152243 e . stopPropagation ( ) ;
153244 handleReset ( ) ;
154245 } }
246+ disabled = { localYAxisMaxValue === maxDataValue }
155247 >
156248 < RefreshIcon />
157249 </ IconButton >
158250 </ Tooltip >
159251 </ Box >
160252 </ Box >
161- </ Box >
162- ) }
253+ ) }
254+ </ Box >
163255 </ Box >
164256 ) ;
165257}
0 commit comments