react-cm-ui
Version:
React UI for Healthy Church
459 lines (406 loc) • 19.6 kB
JSX
/* eslint-disable */
/**
* NOTE: Disabled eslint for this file due to this component being deprecated.
*/
import _ from 'lodash';
import ClassNames from 'classnames';
import moment from 'moment-timezone';
import PropTypes from 'prop-types';
import React from 'react';
import ReactDOM from 'react-dom';
import TetherComponent from 'react-tether';
import DatePickerCalendar from './datePickerDeprecatedCalendar';
import DatePickerInput from './datePickerDeprecatedInput';
import DatePickerUtils from '../../utils/datePickerUtils';
class DatePicker extends React.Component {
constructor(props) {
super(props);
this.state = {
inputHasValue: false,
isCalendarOpen: false,
presetLink: 'open',
};
}
shouldComponentUpdate(nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
render() {
const { buttonClear, className, classNameInput,
date, dateEnd, dateFormat,
dateSecondaryEnd, dateSecondaryStart, dateStart,
disabled, error, events,
excludeDates, filterDates, id,
includeDates, locale, maxDate,
minDate, required, tabIndex,
type, uxMode } = this.props;
const containerClasses = ClassNames('ui', 'date-picker-deprecated', className);
const calendarJSX = (
<DatePickerCalendar
buttonClear={buttonClear}
date={this._convertTimestamp(date)}
dateEnd={this._convertTimestamp(dateEnd)}
dateSecondaryEnd={this._convertTimestamp(dateSecondaryEnd)}
dateSecondaryStart={this._convertTimestamp(dateSecondaryStart)}
dateStart={this._convertTimestamp(dateStart)}
events={events}
excludeDates={excludeDates}
filterDates={filterDates}
includeDates={includeDates}
locale={locale}
maxDate={maxDate}
minDate={minDate}
onApplyClick={this.props.onApplyClick}
onClearClick={this._onClearClick.bind(this)}
onClose={this._onCalendarClickOutside.bind(this)}
onMonthChange={this._onMonthChange.bind(this)}
onSelect={this._onSelect.bind(this)}
ref="calendar"
type={type || 'singleDate'}
uxMode={uxMode}
/>
);
return (
<div className={containerClasses}>
{uxMode === 'input' ? (
<TetherComponent
attachment={'top left'}
classPrefix="date-picker-deprecated-tether"
constraints={[{
to: 'window',
attachment: 'together',
}]}
renderElement={ref => this.state.isCalendarOpen && (
<div ref={ref}>
{calendarJSX}
</div>
)}
renderTarget={ref => (
<div ref={ref}>
<DatePickerInput
className={classNameInput}
date={this._convertTimestamp(date)}
dateEnd={this._convertTimestamp(dateEnd)}
dateFormat={dateFormat}
dateSecondaryEnd={this._convertTimestamp(dateSecondaryEnd)}
dateSecondaryStart={this._convertTimestamp(dateSecondaryStart)}
dateStart={this._convertTimestamp(dateStart)}
disabled={disabled}
error={error}
excludeDates={excludeDates}
filterDates={filterDates}
hasValue={this._hasValue.bind(this)}
id={id}
includeDates={includeDates}
locale={locale}
maxDate={maxDate}
minDate={minDate}
onBlur={this._onInputBlur.bind(this)}
onClick={this._onInputClick.bind(this)}
onDone={this._setOpen.bind(this)}
onFocus={this._onInputFocus.bind(this)}
onSelect={this._onSelect.bind(this)}
open={this.state.isCalendarOpen}
ref="input"
required={required}
setSelected={this._setSelected.bind(this)}
tabIndex={tabIndex}
type={type || 'singleDate'}
uxMode={uxMode}
/>
</div>
)}
targetAttachment={'bottom left'}
targetOffset={'10px 0'}
/>
) : (
<div>
{type === 'dateRange' ? (
<div>
<ul className="date-picker date-picker-presets">
<li>
<a
className={ClassNames('font-size-xsmall', {
'color-static': this.state.presetLink !== 'open',
'color-text': this.state.presetLink === 'open',
'text-decoration-underline': this.state.presetLink === 'open',
})}
onClick={this._onPresetClick.bind(this, 'open')}
>
Open
</a>
</li>
<li>
<a
className={ClassNames('font-size-xsmall', {
'color-static': this.state.presetLink !== 'pastWeek',
'color-text': this.state.presetLink === 'pastWeek',
'text-decoration-underline': this.state.presetLink === 'pastWeek',
})}
onClick={this._onPresetClick.bind(this, 'pastWeek')}
>
Past Week
</a>
</li>
<li>
<a
className={ClassNames('font-size-xsmall', {
'color-static': this.state.presetLink !== 'monthToDate',
'color-text': this.state.presetLink === 'monthToDate',
'text-decoration-underline': this.state.presetLink === 'monthToDate',
})}
onClick={this._onPresetClick.bind(this, 'monthToDate')}
>
Past 30 Days
</a>
</li>
<li>
<a
className={ClassNames('font-size-xsmall', {
'color-static': this.state.presetLink !== 'custom',
'color-text': this.state.presetLink === 'custom',
'text-decoration-underline': this.state.presetLink === 'custom',
})}
onClick={this._onPresetClick.bind(this, 'custom')}
>
Custom
</a>
</li>
</ul>
<DatePickerInput
dateEnd={this._convertTimestamp(dateEnd)}
dateStart={this._convertTimestamp(dateStart)}
disabled={disabled}
hasValue={this._hasValue.bind(this)}
locale={locale}
onClick={this._onInputClick.bind(this)}
onSelect={this._onSelect.bind(this)}
open={this.state.isCalendarOpen}
type={type}
uxMode={uxMode}
/>
</div>
) : null}
{type === 'servicePeriodRange' ? (
<div>
<p className="font-size-xxsmall color-static" style={{ margin: 0 }}>
Start Service Period
</p>
<p style={{ margin: '0 0 22px' }}>
{dateStart && dateEnd ? (
<span>
{`${this._convertTimestamp(dateStart).locale(locale || moment.locale()).format('MM/DD/YYYY')} - ${this._convertTimestamp(dateEnd).locale(locale || moment.locale()).format('MM/DD/YYYY')}`}
</span>
) : (
<span>mm/dd/yyyy - mm/dd/yyyy</span>
)}
</p>
<p className="font-size-xxsmall color-static" style={{ margin: 0 }}>
End Service Period
</p>
<p style={{ margin: '0 0 22px' }}>
{dateSecondaryStart && dateSecondaryEnd ? (
<span>
{`${this._convertTimestamp(dateSecondaryStart).locale(locale || moment.locale()).format('MM/DD/YYYY')} - ${this._convertTimestamp(dateSecondaryEnd).locale(locale || moment.locale()).format('MM/DD/YYYY')}`}
</span>
) : (
<span>mm/dd/yyyy - mm/dd/yyyy</span>
)}
</p>
</div>
) : null}
{calendarJSX}
</div>
)}
</div>
);
}
componentDidMount() {
console.warn('<DatePicker /> has been deprecated. This will be removed in the next major version of react-cm-ui. Please use <DatePickerInput />: http://cm-ui-docs.saddleback.com/modules/date-picker-input or use <DatePickerCalendar />: http://cm-ui-docs.saddleback.com/modules/date-picker-calendar');
}
_convertTimestamp(timestamp) {
return !_.isNil(timestamp) ? moment.unix(timestamp).utc() : null;
}
_hasValue(date) {
this.setState({ inputHasValue: !_.isNull(date) && !_.isEmpty(date) });
}
_onCalendarClickOutside(event) {
this._setOpen(false);
this.props.onClickOutside ? this.props.onClickOutside() : null;
}
_onClearClick(event) {
const { type } = this.props;
if (type === 'dateRange') {
this._onPresetClick('open');
} else if (type === 'servicePeriodRange' || type === 'servicePeriodRangeEnd' || type === 'servicePeriodRangeStart') {
this.props.onChange({
dateFirstChoice: null,
dateSecondChoice: null,
});
} else {
this._setSelected(null);
}
}
_onInputBlur(event) {
if (this.state.isCalendarOpen) {
ReactDOM.findDOMNode(this.refs.input).focus();
} else {
if (_.isFunction(this.props.onBlur)) {
this.props.onBlur(event);
}
}
}
_onInputClick() {
this._setOpen(true);
}
_onInputFocus(event) {
if (_.isFunction(this.props.onFocus)) {
this.props.onFocus(event);
}
this._setOpen(true);
}
_onMonthChange(month, year) {
if (typeof this.props.onMonthChange === 'function') {
this.props.onMonthChange(month, year);
}
}
_onPresetClick(type) {
let activePreset;
if (type === 'open') {
activePreset = 'open';
this.props.onChange({
dateEnd: null,
dateStart: null,
});
} else if (type === 'pastWeek') {
activePreset = 'pastWeek';
this.props.onChange({
dateEnd: moment().subtract(1, 'day').unix(),
dateStart: moment().subtract(1, 'week').unix(),
});
} else if (type === 'monthToDate') {
activePreset = 'monthToDate';
this.props.onChange({
dateEnd: moment().unix(),
dateStart: moment().subtract(1, 'month').unix(),
});
} else if (type === 'custom') {
activePreset = 'custom';
}
this.setState({ presetLink: activePreset });
}
_onSelect(date, dateType, clear) {
const { dateEnd, dateSecondaryEnd, dateSecondaryStart, dateStart, type } = this.props;
if (type === 'dateRange') {
const dateObj = {
dateEnd: dateEnd,
dateStart: dateStart,
};
const isDateBeforeDateStart = (_.isUndefined(dateType) || dateType === 'dateStart') && date.isBefore(this._convertTimestamp(dateStart));
const isDateBeforeDateEnd = (_.isUndefined(dateType) || dateType === 'dateEnd') && date.isBefore(this._convertTimestamp(dateEnd));
const isDateAfterDateEnd = (_.isUndefined(dateType) || dateType === 'dateEnd') && date.isAfter(this._convertTimestamp(dateEnd));
if (!clear &&
!dateStart ||
(dateStart && !dateEnd && isDateBeforeDateStart) ||
(dateStart && dateEnd && isDateBeforeDateStart) ||
(dateType === 'dateStart' && dateStart && dateEnd && date.isBefore(this._convertTimestamp(dateEnd)))
) {
dateObj.dateStart = date.unix();
this.props.onChange(dateObj);
this.setState({ presetLink: 'custom' });
}
if (!clear &&
!isDateBeforeDateStart && (
(dateStart && !dateEnd) ||
(dateStart && dateEnd && isDateBeforeDateEnd) ||
(dateStart && dateEnd && isDateAfterDateEnd)
)) {
dateObj.dateEnd = date.unix();
this.props.onChange(dateObj);
this.setState({ presetLink: 'custom' });
}
// Reset selections
if (clear ||
(_.isNumber(dateStart) && _.isNumber(dateEnd)) &&
(_.isEqual(dateStart, dateEnd) && _.isEqual(dateEnd, date.unix()))
) {
dateObj.dateStart = null;
dateObj.dateEnd = null;
this.props.onChange(dateObj);
this._hasValue(null);
this.setState({ presetLink: 'open' });
}
} else if (type === 'servicePeriod') {
this.props.onChange(_.isObject(date) && date.clone().isValid() ? date.clone().unix() : null);
this._hasValue(date);
} else if (type === 'servicePeriodRange' || type === 'servicePeriodRangeEnd' || type === 'servicePeriodRangeStart') {
const dateObj = {
dateFirstChoice: dateStart,
dateSecondChoice: dateSecondaryStart,
};
const isDateBeforeDateStart = date.isBefore(this._convertTimestamp(dateStart));
const isDateAfterDateEnd = date.isAfter(this._convertTimestamp(dateEnd));
const isDateBeforeDateSecondaryStart = date.isBefore(this._convertTimestamp(dateSecondaryStart));
if (!dateStart && !dateEnd ||
(dateStart && dateEnd && isDateBeforeDateStart)
) {
dateObj.dateFirstChoice = date.unix();
this.props.onChange(dateObj);
}
if ((dateStart && dateEnd && isDateAfterDateEnd) ||
(dateStart && dateEnd && dateSecondaryStart && dateSecondaryEnd && isDateBeforeDateSecondaryStart)
) {
dateObj.dateSecondChoice = date.unix();
this.props.onChange(dateObj);
}
} else {
if (moment.isMoment(date)) {
this.props.onChange(date.unix());
} else {
this.props.onChange(null);
}
this._hasValue(date);
}
}
_setOpen(open) {
this.setState({ isCalendarOpen: open });
}
_setSelected(date) {
if (_.isFunction(this.props.onChange) && !DatePickerUtils.isSameDay(this._convertTimestamp(this.props.date), date)) {
this.props.onChange(date);
}
this._hasValue(date);
}
}
const typeEnums = [ 'dateRange', 'servicePeriod', 'servicePeriodRange', 'servicePeriodRangeEnd', 'servicePeriodRangeStart', 'singleDate' ];
const uxModeEnums = [ 'input', 'calendar' ];
DatePicker.propTypes = {
buttonClear: PropTypes.bool,
className: PropTypes.string,
classNameInput: PropTypes.string,
date: PropTypes.number,
dateEnd: PropTypes.number,
dateFormat: PropTypes.string,
dateSecondaryEnd: PropTypes.number,
dateSecondaryStart: PropTypes.number,
dateStart: PropTypes.number,
disabled: PropTypes.bool,
errorMessage: PropTypes.string,
events: PropTypes.array,
excludeDates: PropTypes.array,
filterDates: PropTypes.func,
id: PropTypes.string,
includeDates: PropTypes.array,
locale: PropTypes.string,
maxDate: PropTypes.shape({}),
minDate: PropTypes.shape({}),
onApplyClick: PropTypes.func,
onBlur: PropTypes.func,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func,
onMonthChange: PropTypes.func,
required: PropTypes.bool,
tabIndex: PropTypes.number,
type: PropTypes.oneOf(typeEnums),
uxMode: PropTypes.oneOf(uxModeEnums),
};
export default DatePicker;