UNPKG

react-cm-ui

Version:
335 lines (301 loc) 13.3 kB
import _ from 'lodash'; import ClassNames from 'classnames'; import moment from 'moment-timezone'; import PropTypes from 'prop-types'; import onClickOutside from 'react-onclickoutside'; import React from 'react'; import Button from '../button'; import DatePickerDropdownMonth from '../datePickerCalendar/datePickerDropdownMonth'; import DatePickerDropdownYear from '../datePickerCalendar/datePickerDropdownYear'; import DatePickerMonth from './datePickerDeprecatedMonth'; import DatePickerUtils from '../../utils/datePickerUtils'; import Grid from '../../layout/grid'; import Icon from '../../dataDisplay/icon'; const propTypes = { buttonClear: PropTypes.bool, date: PropTypes.shape({}), // Single date moment object. Coverted from timestamp in parent component. dateEnd: PropTypes.shape({}), // Range end date moment object. Coverted from timestamp in parent component. dateSecondaryEnd: PropTypes.shape({}), // Range start date moment object. Coverted from timestamp in parent component. dateSecondaryStart: PropTypes.shape({}), // Range start date moment object. Coverted from timestamp in parent component. dateStart: PropTypes.shape({}), // Range start date moment object. Coverted from timestamp in parent component. events: PropTypes.array, excludeDates: PropTypes.array, filterDate: PropTypes.func, includeDates: PropTypes.array, locale: PropTypes.string, maxDate: PropTypes.shape({}), minDate: PropTypes.shape({}), onApplyClick: PropTypes.func, onClearClick: PropTypes.func, onClose: PropTypes.func, onMonthChange: PropTypes.func, onSelect: PropTypes.func.isRequired, type: PropTypes.string, uxMode: PropTypes.string, }; class DatePickerCalendar extends React.Component { constructor(props) { super(props); this.state = { dateInView: this.localizeMoment( this.getDateInView( props.date, props.dateStart, props.dateSecondaryStart, props.maxDate, props.minDate, ), ), showDropdownMonth: false, showDropdownYear: false, }; } componentDidUpdate(prevProps) { if (!DatePickerUtils.isSameDay(prevProps.date, this.props.date) || !DatePickerUtils.isSameDay(prevProps.dateStart, this.props.dateStart) ) { this.setState({ dateInView: this.localizeMoment( this.getDateInView( this.props.date, this.props.dateStart, this.props.dateSecondaryStart, this.props.maxDate, this.props.minDate, ), ), }); } } componentWillUpdate(nextProps, nextState) { // issue onMonthChange() call when month changes due to a user selection of the date // (as opposed to via the month dropdown) if (this.state.dateInView && nextState.dateInView && (nextState.dateInView.month() !== this.state.dateInView.month()) && (typeof this.props.onMonthChange === 'function')) { this.props.onMonthChange(nextState.dateInView.month(), nextState.dateInView.year()); } } getDateInView(date, dateStart, dateSecondaryStart, maxDate, minDate) { const today = moment(); if (date) { return date; } else if (dateStart /*&& (_.isNull(dateSecondaryStart) || dateSecondaryStart)*/) { // I'm 99.9% certain that portion is useless ... it should ALWAYS be either NULL OR truthy, right...? return dateStart; } else if (!dateStart && dateSecondaryStart) { return dateSecondaryStart; } if (minDate && minDate.isAfter(today)) { return minDate; } else if (maxDate && maxDate.isBefore(today)) { return maxDate; } else { return today; } } handleClickOutside() { this.props.onClose(); } headerDays() { const startOfWeek = this.state.dateInView.clone().startOf('week'); return [0, 1, 2, 3, 4, 5, 6].map(offset => { const day = startOfWeek.clone().add(offset, 'days'); return ( <div className="ui date-picker-deprecated-day" key={offset} > {day.localeData().weekdaysMin(day)} </div> ); }); } localizeMoment(date) { return date.clone().locale(this.props.locale || moment.locale()); } onApplyClick() { if (_.isFunction(this.props.onApplyClick)) { this.props.onApplyClick(); } } onChangeMonth(month) { if (typeof this.props.onMonthChange === 'function') this.props.onMonthChange(month, this.state.dateInView.year()); this.setState({ dateInView: this.state.dateInView.clone().set('month', month), showDropdownMonth: false, }); } onChangeYear(year) { this.setState({ dateInView: this.state.dateInView.clone().set('year', year), showDropdownYear: false, }); } onClearClick() { this.props.onClearClick(); } onDayClick(day) { if (_.isFunction(this.props.onSelect)) { this.props.onSelect(day); } } onDropdownMonthClick() { this.setState({ showDropdownMonth: !this.state.showDropdownMonth }); } onDropdownYearClick() { this.setState({ showDropdownYear: !this.state.showDropdownYear }); } render() { const { buttonClear, date, dateEnd, dateStart, dateSecondaryEnd, dateSecondaryStart, onApplyClick, type, uxMode, } = this.props; const dateInView = this.state.dateInView; const containerClasses = ClassNames('ui', 'date-picker-deprecated-calendar', { 'date-picker-deprecated-calendar-uxmode-input': uxMode === 'input', 'date-picker-deprecated-calendar-uxmode-calendar': uxMode === 'calendar', 'date-picker-deprecated-calendar-date-range': type === 'dateRange', 'date-picker-deprecated-calendar-service-period': type === 'servicePeriod', 'date-picker-deprecated-calendar-service-period-range': type === 'servicePeriodRange' || type === 'servicePeriodRangeEnd' || type === 'servicePeriodRangeStart', 'date-picker-deprecated-calendar-single-date': type === 'singleDate', }); return ( <div className={containerClasses}> {uxMode === 'input' ? ( <div className="date-picker-pointer" /> ) : null} <div className="date-picker-selected-month-year"> <div className="date-picker-selected-month" onClick={this.onDropdownMonthClick.bind(this)}> <span> {dateInView.format('MMMM')} <Icon align="right" size="xxsmall" type="caret-down" /> </span> {this.state.showDropdownMonth ? ( <DatePickerDropdownMonth month={dateInView.month()} onChange={this.onChangeMonth.bind(this)} onClose={this.onDropdownMonthClick.bind(this)} /> ) : null} </div> <div className="date-picker-selected-year" onClick={this.onDropdownYearClick.bind(this)}> <span> {dateInView.format('YYYY')} <Icon align="right" size="xxsmall" type="caret-down" /> </span> {this.state.showDropdownYear ? ( <DatePickerDropdownYear onChange={this.onChangeYear.bind(this)} onClose={this.onDropdownYearClick.bind(this)} year={dateInView.year()} /> ) : null} </div> </div> <div className="date-picker-month-container"> <div className="ui date-picker-header-days"> {this.headerDays()} </div> <DatePickerMonth dateInView={dateInView} date={date} dateEnd={dateEnd} dateSecondaryEnd={dateSecondaryEnd} dateSecondaryStart={dateSecondaryStart} dateStart={dateStart} events={this.props.events} excludeDates={this.props.excludeDates} filterDates={this.props.filterDates} includeDates={this.props.includeDates} key="datepicker-month" maxDate={this.props.maxDate} minDate={this.props.minDate} onDayClick={this.onDayClick.bind(this)} type={this.props.type} uxMode={this.props.uxMode} /> </div> {buttonClear === true || _.isFunction(onApplyClick) ? ( <Grid alignItems="center" justifyContent="space-between" spacing={2} style={{ marginTop: 11, }} > <Grid.Column> {buttonClear === true && (dateStart || dateSecondaryStart) ? ( <a className="font-size-xsmall color-alert" onClick={this.onClearClick.bind(this)} > Clear </a> ) : null} </Grid.Column> {_.isFunction(onApplyClick) ? ( <Grid.Column> <Button color={ (type === 'singleDate' && date) || ( (type === 'dateRange' || type === 'servicePeriod') && dateStart && dateEnd ) || ( type === 'servicePeriodRange' && dateStart && dateEnd && dateSecondaryStart && dateSecondaryEnd ) ? 'primary' : 'disable' } onClick={ date || (dateStart && dateEnd) || (dateSecondaryStart && dateSecondaryEnd) ? this.onApplyClick.bind(this) : null } > { (type === 'singleDate' && date) || ( ( type === 'dateRange' || type === 'servicePeriod' ) && dateStart && dateEnd ) || ( type === 'servicePeriodRange' && dateStart && dateEnd && dateSecondaryStart && dateSecondaryEnd ) ? 'Apply' : 'Select' } </Button> </Grid.Column> ) : null} </Grid> ) : null} </div> ); } } DatePickerCalendar.propTypes = propTypes; export default onClickOutside(DatePickerCalendar);