UNPKG

react-cm-ui

Version:
359 lines (320 loc) 13.5 kB
import _ from 'lodash'; import ClassNames from 'classnames'; import moment from 'moment-timezone'; import PropTypes from 'prop-types'; import React from 'react'; import DatePickerUtils from '../../utils/datePickerUtils'; import DateUtils from '../../utils/dateUtils'; import Grid from '../../layout/grid'; import Icon from '../../dataDisplay/icon'; import Input from '../input'; const propTypes = { className: PropTypes.string, date: PropTypes.shape({}), dateEnd: PropTypes.shape({}), dateFormat: PropTypes.string, dateSecondaryEnd: PropTypes.shape({}), dateSecondaryStart: PropTypes.shape({}), dateStart: PropTypes.shape({}), disabled: PropTypes.bool, errorMessage: PropTypes.string, excludeDates: PropTypes.array, filterDates: PropTypes.func, hasValue: PropTypes.func.isRequired, id: PropTypes.string, includeDates: PropTypes.array, locale: PropTypes.string, maxDate: PropTypes.shape({}), minDate: PropTypes.shape({}), mode: PropTypes.string, onBlur: PropTypes.func, onClick: PropTypes.func, onDone: PropTypes.func, onFocus: PropTypes.func, onSelect: PropTypes.func, open: PropTypes.bool, required: PropTypes.bool, tabIndex: PropTypes.number, type: PropTypes.string, uxMode: PropTypes.string, }; class DatePickerInput extends React.Component { constructor(props) { super(props); this.state = { hasAnError: false, listensForErrors: !_.isUndefined(props.required), maybeDate: this.safeDateFormat(props.date, props.locale), maybeDateRange: { dateEnd: this.safeDateFormat(props.dateEnd, props.locale), dateSecondaryEnd: this.safeDateFormat(props.dateSecondaryEnd, props.locale), dateSecondaryStart: this.safeDateFormat(props.dateSecondaryStart, props.locale), dateStart: this.safeDateFormat(props.dateStart, props.locale), }, }; this.onErrorRef = this.onError.bind(this); this._dateFormats = this.getAllowedDateFormats('MM/DD/YYYY'); this.onBlur = this.onBlur.bind(this); this.onClick = this.onClick.bind(this); this.onFocus = this.onFocus.bind(this); this.onKeyDown = this.onKeyDown.bind(this); } componentDidMount() { if (this.state.listensForErrors) { ParsleyFormStore.addChangeListener(this.onErrorRef); } } componentDidUpdate(prevProps, prevState) { const { date, dateStart, dateEnd, dateSecondaryStart, dateSecondaryEnd, locale } = this.props; if (!DatePickerUtils.isSameDay(date, prevProps.date) || !DatePickerUtils.isSameDay(dateStart, prevProps.dateStart) || !DatePickerUtils.isSameDay(dateEnd, prevProps.dateEnd) || !DatePickerUtils.isSameDay(dateSecondaryStart, prevProps.dateSecondaryStart) || !DatePickerUtils.isSameDay(dateSecondaryEnd, prevProps.dateSecondaryEnd) || !_.isEqual(locale, prevProps.locale) ) { this.setState({ maybeDate: this.safeDateFormat(date, locale), maybeDateRange: { dateEnd: this.safeDateFormat(dateEnd, locale), dateSecondaryEnd: this.safeDateFormat(dateSecondaryEnd, locale), dateSecondaryStart: this.safeDateFormat(dateSecondaryStart, locale), dateStart: this.safeDateFormat(dateStart, locale), }, }); } } componentWillUnmount() { if (this.state.listensForErrors) { ParsleyFormStore.removeChangeListener(this.onErrorRef); } } onBlur(value) { const { date, dateEnd, dateStart, locale, type } = this.props; const isSingleDateOrServicePeriod = type === 'singleDate' || type === 'servicePeriod'; const isDateRange = type === 'dateRange'; if (!_.isUndefined(this.props.onBlur)) { this.props.onBlur(event); } this.props.hasValue(value); this.setState({ maybeDate: isSingleDateOrServicePeriod ? this.safeDateFormat(date, locale) : this.state.maybeDate, maybeDateRange: isDateRange ? { dateEnd: this.safeDateFormat(dateEnd, locale), dateStart: this.safeDateFormat(dateStart, locale), } : this.state.maybeDateRange, }); } onChange(dateType, value) { const { type, locale, uxMode } = this.props; const newLocale = locale || moment.locale(); if (uxMode === 'input' && type === 'dateRange') { const datesArray = value ? value.split('-') : ''; if (value !== '' && value !== '__/__/____ - __/__/____') { _.map(datesArray, (date, index) => { const newDate = moment(date.trim(), this._dateFormats, newLocale, true); const dateType = index === 0 ? 'dateStart' : index === 1 ? 'dateEnd' : null; if (newDate.isValid() && (!DatePickerUtils.isDayDisabled(newDate, this.props) && (index === 0 && !DatePickerUtils.isSameDay(this.props.dateStart, newDate)) || (index === 1 && !DatePickerUtils.isSameDay(this.props.dateEnd, newDate))) ) { this.props.onSelect(newDate, dateType); } }); } else { this.props.onSelect(null, null, true); } this.setState({ maybeDateRange: { dateEnd: value ? datesArray[1].trim() : '', dateStart: value ? datesArray[0].trim() : '', }, }); } else if (uxMode === 'calendar' || uxMode === 'input' && type === 'singleDate') { const date = moment(value, this._dateFormats, newLocale, true); if (date.isValid() && !DatePickerUtils.isDayDisabled(date, this.props)) { this.props.onSelect(date); } else if (value === '' || value === '__/__/____') { this.props.onSelect(null, null, true); } if (uxMode === 'input') { this.setState({ maybeDate: value }); } if (uxMode === 'calendar') { this.setState({ maybeDateRange: { dateEnd: dateType === 'dateEnd' ? value : this.state.maybeDateRange.dateEnd, dateStart: dateType === 'dateStart' ? value : this.state.maybeDateRange.dateStart, }, }); } } this.props.hasValue(value); } onClick(dateField) { if (_.isFunction(this.props.onClick)) { this.props.onClick(); } } onError() { this.setState({ 'hasAnError': ParsleyFormStore.inputHasError(this.props.id) }); } onFocus() { if (_.isFunction(this.props.onFocus)) { this.props.onFocus(); } } onKeyDown(event) { if (event.keyCode === 9 || event.keyCode === 13) { this.props.onDone(); } } getAllowedDateFormats(specifiedFormat) { const formats = DateUtils.getAllowedDateFormats(); if (_.indexOf(formats, specifiedFormat) < 0) { formats.unshift(specifiedFormat); } return formats; } safeDateFormat(date, locale) { if (date && date.isValid()) { return date.clone().locale(locale || moment.locale()).format('MM/DD/YYYY'); } if (_.isNull(date)) { return null; } } render() { const { className, open, type, uxMode } = this.props; const disabled = this.props.disabled || type === 'servicePeriod' || type === 'servicePeriodRangeEnd' || type === 'servicePeriodRangeStart'; const containerClasses = ClassNames('date-picker-deprecated-input', { 'date-picker-input-disabled': disabled, 'date-picker-input-type-date-range': type === 'dateRange', 'date-picker-input-type-service-period': type === 'servicePeriod', 'date-picker-input-type-service-period-range': type === 'servicePeriodRange', 'date-picker-input-type-single-date': type === 'singleDate', 'ignore-react-onclickoutside': open, }, className); let mask, placeholder, value; if (uxMode === 'input' && type === 'dateRange' || type === 'servicePeriod' || type === 'servicePeriodRangeEnd' || type === 'servicePeriodRangeStart' ) { mask = [ /\d/, /\d/, '/', /\d/, /\d/, '/', /\d/, /\d/, /\d/, /\d/, ' ', '-', ' ', /\d/, /\d/, '/', /\d/, /\d/, '/', /\d/, /\d/, /\d/, /\d/, ]; placeholder = 'mm/dd/yyyy - mm/dd/yyyy'; if (type === 'servicePeriodRangeEnd') { value = `${this.state.maybeDateRange.dateSecondaryStart} - ${this.state.maybeDateRange.dateSecondaryEnd}`; } else { value = `${this.state.maybeDateRange.dateStart} - ${this.state.maybeDateRange.dateEnd}`; } } else { mask = [ /\d/, /\d/, '/', /\d/, /\d/, '/', /\d/, /\d/, /\d/, /\d/, ]; placeholder = 'mm/dd/yyyy'; value = this.state.maybeDate; } if (uxMode === 'input') { return ( <Input autoComplete="off" className={containerClasses} data-parsley-error-message={this.props.errorMessage} disabled={disabled} guide={true} icon={( <Icon color={open ? 'highlight' : null} compact={true} onClick={this.onClick} type="calendar" /> )} id={this.props.id} keepCharPositions mask={mask} onBlur={this.onBlur} onChange={this.onChange.bind(this, 'date')} onClick={this.onClick} onFocus={this.onFocus} onKeyDown={this.onKeyDown} placeholder={placeholder} ref="input" required={this.props.required} tabIndex={this.props.tabIndex} type="text" value={value} /> ); } else if (uxMode === 'calendar') { return ( <Grid columns={2} spacing={2} style={{ marginBottom: 5, marginTop: 7, }} > <Grid.Column> <Input autoComplete="off" className={containerClasses} data-parsley-error-message={this.props.errorMessage} disabled={disabled} guide={true} id={this.props.id} keepCharPositions={true} label="From" mask={mask} onBlur={this.onBlur} onChange={this.onChange.bind(this, 'dateStart')} onClick={this.onClick} onFocus={this.onFocus} placeholder={placeholder} required={this.props.required} tabIndex={this.props.tabIndex} type="text" value={this.state.maybeDateRange.dateStart} /> </Grid.Column> <Grid.Column> <Input autoComplete="off" className={containerClasses} data-parsley-error-message={this.props.errorMessage} disabled={disabled} guide={true} id={this.props.id} keepCharPositions={true} label="To" mask={mask} onBlur={this.onBlur} onChange={this.onChange.bind(this, 'dateEnd')} onClick={this.onClick} onFocus={this.onFocus} placeholder={placeholder} ref="inputEnd" required={this.props.required} tabIndex={this.props.tabIndex} type="text" value={this.state.maybeDateRange.dateEnd} /> </Grid.Column> </Grid> ); } } } DatePickerInput.propTypes = propTypes; export default DatePickerInput;