11import 'react-day-picker/lib/style.css' ;
22import { CalendarMultiselectIcon } from 'plotly-icons' ;
3- import { ms2DateTime , dateTime2ms } from 'plotly.js/src/lib/dates' ;
3+ import { ms2DateTime , dateTime2ms , isDateTime } from 'plotly.js/src/lib/dates' ;
44import DayPicker from 'react-day-picker' ;
55import PropTypes from 'prop-types' ;
66import React , { Component } from 'react' ;
77import TextInput from './TextInput' ;
88import Dropdown from './Dropdown' ;
99
10- function formatDigits ( number , nbDigits ) {
11- const string = number . toString ( ) ;
12- if ( string . length !== nbDigits ) {
13- return (
14- new Array ( nbDigits - string . length )
15- . fill ( 0 )
16- . join ( )
17- . replace ( ',' , '' ) + number
18- ) ;
19- }
20- return number ;
21- }
10+ const testDate = '2000-01-01' ;
11+ const testTime = '00:00' ;
12+ const datePlaceholder = 'yyyy-mm-dd' ;
13+ const timePlaceholder = 'hh:mm:ss.xxx' ;
2214
2315export default class DateTimePicker extends Component {
24- constructor ( ) {
25- super ( ) ;
16+ constructor ( props ) {
17+ super ( props ) ;
18+ const { time, date} = this . parseDateTime ( props . value ) ;
19+ const isValidTime = isDateTime ( testDate + ' ' + time ) ;
20+ const isValidDate = isDateTime ( date + ' ' + testTime ) ;
21+
2622 this . state = {
2723 calendarOpen : false ,
24+ dateInputClassName : isValidDate
25+ ? 'datetimepicker-container-date-input'
26+ : 'datetimepicker-container-date-input--error' ,
27+ timeInputClassName : isValidTime
28+ ? 'datetimepicker-container-time-input'
29+ : 'datetimepicker-container-time-input--error' ,
30+ timeValue : time ,
31+ dateValue : date ,
2832 } ;
2933
3034 this . toPlotlyJSDate = this . toPlotlyJSDate . bind ( this ) ;
@@ -78,22 +82,33 @@ export default class DateTimePicker extends Component {
7882 onMonthChange ( value ) {
7983 const currentDateInJS = new Date ( this . props . value ) ;
8084 currentDateInJS . setMonth ( value ) ;
81- this . props . onChange ( this . toPlotlyJSDate ( currentDateInJS ) ) ;
85+ const plotlyJSDate = this . toPlotlyJSDate ( currentDateInJS ) ;
86+
87+ if ( isDateTime ( plotlyJSDate ) ) {
88+ this . props . onChange ( plotlyJSDate ) ;
89+ }
90+
91+ const { time, date} = this . parseDateTime ( plotlyJSDate ) ;
92+ this . setState ( {
93+ timeValue : time ,
94+ dateValue : date ,
95+ } ) ;
8296 }
8397
8498 onYearChange ( value ) {
8599 const currentDateInJS = new Date ( this . props . value ) ;
86100 currentDateInJS . setFullYear ( value ) ;
87- this . props . onChange ( this . toPlotlyJSDate ( currentDateInJS ) ) ;
88- }
101+ const plotlyJSDate = this . toPlotlyJSDate ( currentDateInJS ) ;
89102
90- getTime ( JSDate ) {
91- return (
92- `${ formatDigits ( JSDate . getHours ( ) , 2 ) } :` +
93- `${ formatDigits ( JSDate . getMinutes ( ) , 2 ) } :` +
94- `${ formatDigits ( JSDate . getSeconds ( ) , 2 ) } .` +
95- `${ formatDigits ( JSDate . getMilliseconds ( ) , 3 ) } `
96- ) ;
103+ if ( isDateTime ( plotlyJSDate ) ) {
104+ this . props . onChange ( plotlyJSDate ) ;
105+ }
106+
107+ const { time, date} = this . parseDateTime ( plotlyJSDate ) ;
108+ this . setState ( {
109+ timeValue : time ,
110+ dateValue : date ,
111+ } ) ;
97112 }
98113
99114 parseDateTime ( value ) {
@@ -102,31 +117,72 @@ export default class DateTimePicker extends Component {
102117 }
103118
104119 updateTime ( value ) {
105- const { date : currentDate , time : currentTime } = this . parseDateTime ( this . props . value ) ;
120+ const update = this . state . dateValue + ' ' + value ;
121+ const isValidTime = isDateTime ( testDate + ' ' + value ) ;
122+
123+ if ( value === '' ) {
124+ this . setState ( {
125+ timeInputClassName : 'datetimepicker-container-time-input' ,
126+ timeValue : timePlaceholder ,
127+ } ) ;
128+ return ;
129+ }
106130
107- if ( value !== currentTime ) {
108- this . props . onChange ( currentDate + ' ' + value ) ;
131+ if ( isValidTime ) {
132+ this . props . onChange ( update ) ;
133+ this . setState ( {
134+ timeValue : value ,
135+ timeInputClassName : 'datetimepicker-container-time-input' ,
136+ } ) ;
137+ return ;
138+ }
139+
140+ if ( ! isValidTime ) {
141+ this . setState ( {
142+ timeInputClassName : 'datetimepicker-container-time-input--error' ,
143+ timeValue : value ,
144+ } ) ;
109145 }
110146 }
111147
112148 updateDate ( value ) {
113- const { date : currentDate , time : currentTime } = this . parseDateTime ( this . props . value ) ;
149+ const update = value + ' ' + this . state . timeValue ;
150+ const isValidDate = isDateTime ( value + ' ' + testTime ) ;
151+
152+ if ( isValidDate ) {
153+ this . props . onChange ( update ) ;
154+ this . setState ( {
155+ dateValue : value ,
156+ dateInputClassName : 'datetimepicker-container-date-input' ,
157+ } ) ;
158+ return ;
159+ }
160+
161+ if ( value === '' ) {
162+ this . setState ( {
163+ dateValue : datePlaceholder ,
164+ dateInputClassName : 'datetimepicker-container-date-input' ,
165+ } ) ;
166+ return ;
167+ }
114168
115- if ( value !== currentDate ) {
116- this . props . onChange ( value + ' ' + currentTime ) ;
169+ if ( ! isValidDate ) {
170+ this . setState ( {
171+ dateValue : value ,
172+ dateInputClassName : 'datetimepicker-container-date-input--error' ,
173+ } ) ;
117174 }
118175 }
119176
120177 render ( ) {
121- const { date : currentDate } = this . parseDateTime ( this . props . value ) ;
122178 const JSDate = new Date ( this . props . value ) ;
123179 const currentYear = JSDate . getFullYear ( ) ;
124180
125181 return (
126182 < div className = "datetimepicker-container" >
127183 < TextInput
128- value = { currentDate }
129- editableClassName = { 'datetimepicker-container-input' }
184+ value = { this . state . dateValue }
185+ editableClassName = { this . state . dateInputClassName }
130186 onUpdate = { this . updateDate }
131187 />
132188 < div className = "datetimepicker-container-icons" >
@@ -174,9 +230,10 @@ export default class DateTimePicker extends Component {
174230 ) : null }
175231 < div className = "datetimepicker-container-time" >
176232 < TextInput
177- value = { this . getTime ( JSDate ) }
233+ value = { this . state . timeValue }
178234 onUpdate = { this . updateTime }
179235 placeHolder = "hh:mm:ss.xxx"
236+ editableClassName = { this . state . timeInputClassName }
180237 />
181238 < span className = "datetimepicker-date-units" >
182239 { JSDate . toLocaleTimeString ( 'en-US' ) . split ( ' ' ) [ 1 ] === 'PM' ? 'PM' : 'AM' }
0 commit comments