UNPKG

@bigfishtv/cockpit

Version:

217 lines (194 loc) 5.46 kB
import PropTypes from 'prop-types' import React, { Component } from 'react' import DatePicker from 'react-datepicker' import moment from 'moment' import Icon from '../Icon' const valueDateTimeFormat = 'YYYY-MM-DDTHH:mm:ssZ' const dateFormat = 'DD/MM/YY' const timeFormat = 'h:mm A' const dateFormats = [ // day/month/year 'DD/MM/YYYY', 'D/MM/YYYY', 'DD/M/YYYY', 'D/M/YYYY', 'DD/MM/YY', 'D/M/YY', 'D/MM/YY', 'DD/M/YY', // year-month-day 'YYYY-MM-DD', 'YYYY-MM-D', 'YYYY-M-DD', 'YYYY-M-D', 'YY-MM-DD', 'YY-MM-D', 'YY-M-DD', 'YY-M-D', ] const timeFormats = ['', 'ha', 'h:mm', 'h:mma', 'h', 'hh'] export default class DateTimeInput extends Component { static propTypes = { value: PropTypes.string, defaultTime: PropTypes.string, } static defaultProps = { displayTime: true, defaultTime: '', onChange: value => console.warn('No onChange prop set for DateTime'), readOnly: false, } constructor(props) { super() const state = this.getStateForValue(props) this.state = { dirtyTime: false, dirtyDate: false, dateValid: state.dateValue !== '', timeValid: state.timeValue !== '', ...state, } } componentWillReceiveProps(nextProps) { if (nextProps.value != this.props.value && !this.state.dirty) { this.setState({ ...this.getStateForValue(nextProps) }) } } getStateForValue(nextProps) { const dateTimeString = nextProps.value if (!dateTimeString) { return { dateValue: '', timeValue: nextProps.defaultTime, currentDate: null, } } const dateTime = moment(dateTimeString, valueDateTimeFormat) return { dateValue: dateTime.format(dateFormat), timeValue: dateTime.hour() == 0 && dateTime.minute() == 0 ? '' : dateTime.format(timeFormat), currentDate: dateTime, } } handleChangeDate = event => { // if parsed + formatted date is the same as the // input value, then just send an onChange event // TODO: also support this when defaultTime is provided const date = moment(event.target.value, dateFormats) if (date.format(dateFormat) === event.target.value && !this.props.defaultTime) { this.props.onChange(date.format(valueDateTimeFormat)) return } this.setState({ dirtyDate: true, dateValue: event.target.value, }) } handleChangeDatepicker = dateTime => { this.setState( { dateValue: dateTime.format(dateFormat), dirtyDate: true, timeValue: this.state.timeValue || this.props.defaultTime, currentDate: dateTime, }, () => this.handleBlur() ) setTimeout(() => this.dateInputRef.focus(), 1) } handleChangeTime = event => { // if parsed + formatted time is the same as the // input value, then just send an onChange event const time = moment(event.target.value, timeFormats) if (time.format(timeFormat) === event.target.value) { const date = moment(this.state.dateValue, dateFormats) date.hours(time.hours()) date.minutes(time.minutes()) date.seconds(time.seconds()) this.props.onChange(date.format(valueDateTimeFormat)) return } this.setState({ dirtyTime: true, timeValue: event.target.value, }) } handleBlur = event => { const { dateValue, timeValue, dirtyDate, dirtyTime } = this.state // if no values have changed then donna worry bout ittt if (!dirtyTime && !dirtyDate) return // attempt to parse date and time from input values const date = moment(dateValue, dateFormats) const time = moment(timeValue, timeFormats) // update state, including if values are valid this.setState({ dirtyDate: false, dirtyTime: false, dateValid: date.isValid(), timeValid: time.isValid() }, () => { // return blank date if invalid if (!this.state.dateValid) { this.props.onChange(null) return } // copy time value into date object if (this.state.timeValid) { date.hours(time.hours()) date.minutes(time.minutes()) date.seconds(time.seconds()) } this.props.onChange(date.format(valueDateTimeFormat)) }) } handleKeyDown = event => { if (event.key === 'Enter') { this.handleBlur() } } render() { const { timeValue, dateValue } = this.state const { value, minDate, maxDate, displayTime } = this.props return ( <div className="inputs-inline"> <div className="input-group"> <div className="input-group-icon"> {!this.props.readOnly && !this.props.disabled && ( <DatePicker showYearDropdown selected={this.state.currentDate} onChange={this.handleChangeDatepicker} minDate={minDate ? moment(minDate) : null} maxDate={maxDate ? moment(maxDate) : null} tabIndex={-1} /> )} <Icon name="calendar" size="18" /> </div> <input ref={el => (this.dateInputRef = el)} type="text" placeholder={dateFormat} value={dateValue} onChange={this.handleChangeDate} onBlur={this.handleBlur} onKeyDown={this.handleKeyDown} readOnly={this.props.readOnly} autoFocus={this.props.autoFocus} /> </div> {displayTime && value && ( <div className="input-group"> <div className="input-group-icon"> <Icon name="clock" size="18" /> </div> <input type="text" placeholder={value ? '12:00 AM' : ''} value={timeValue} onChange={this.handleChangeTime} onBlur={this.handleBlur} onKeyDown={this.handleKeyDown} readOnly={this.props.readOnly} /> </div> )} </div> ) } }