semantic-ui-calendar-react
Version:
date/time picker built from semantic-ui elements
153 lines (140 loc) • 4.17 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import moment from 'moment';
import _ from 'lodash';
import InputView from '../views/InputView';
import {
getInitializer,
parseValue,
} from './parse';
import { getUnhandledProps } from '../lib';
import DatesRangePicker from '../pickers/dayPicker/DatesRangePicker';
import BaseInput from './BaseInput';
const DATES_SEPARATOR = ' - ';
function cleanDate(inputString, dateFormat) {
const formattedDateLength = moment().format(dateFormat).length;
return inputString.trim().slice(0, formattedDateLength);
}
/**
* Extract start and end dates from input string.
* Return { start: Moment|undefined, end: Moment|undefined }
* @param {string} inputString Row input string from user
* @param {string} dateFormat Moment formatting string
*/
function parseDatesRange(inputString, dateFormat) {
// dates range is "startDate - endDate"
const dates = inputString.split(DATES_SEPARATOR)
.map(date => cleanDate(date, dateFormat));
const result = {};
let start;
let end;
start = moment(dates[0], dateFormat);
if (dates.length === 2) {
end = moment(dates[1], dateFormat);
}
if (start && start.isValid()) {
result.start = start;
}
if (end && end.isValid()) {
result.end = end;
}
return result;
}
class DatesRangeInput extends BaseInput {
/**
* Component responsibility:
* - parse input value (start: Moment, end: Moment)
* - handle DayPicker change (format {start: Moment, end: Moment} into
* string 'start - end')
*/
constructor(props) {
super(props);
this.state = {};
}
handleSelect = (e, { value }) => {
const { dateFormat } = this.props;
const {
start,
end,
} = value;
let outputString = '';
if (start && end) {
outputString = `${start.format(dateFormat)}${DATES_SEPARATOR}${end.format(dateFormat)}`;
} else if (start) {
outputString = `${start.format(dateFormat)}${DATES_SEPARATOR}`;
}
_.invoke(this.props, 'onChange', e, { ...this.props, value: outputString });
if (this.props.closable && start && end) {
this.closePopup();
}
}
render() {
const {
value,
initialDate,
dateFormat,
minDate,
maxDate,
} = this.props;
const rest = getUnhandledProps(DatesRangeInput, this.props);
const {
start,
end,
} = parseDatesRange(value, dateFormat);
return (
<InputView
popupIsClosed={this.state.popupIsClosed}
icon="calendar"
{ ...rest }
value={value}
onMount={this.onInputViewMount}
render={(pickerProps) =>
(<DatesRangePicker
{...pickerProps}
isPickerInFocus={this.isPickerInFocus}
isTriggerInFocus={this.isTriggerInFocus}
inline={this.props.inline}
onCalendarViewMount={this.onCalendarViewMount}
closePopup={this.closePopup}
onChange={this.handleSelect}
dateFormat={dateFormat}
initializeWith={getInitializer({ initialDate, dateFormat })}
start={start}
end={end}
minDate={parseValue(minDate, dateFormat)}
maxDate={parseValue(maxDate, dateFormat)} />)
}
/>
);
}
}
DatesRangeInput.propTypes = {
/** Currently selected value. */
value: PropTypes.string,
/** Moment date formatting string. */
dateFormat: PropTypes.string,
/** Date to display initially when no date is selected. */
initialDate: PropTypes.oneOfType([
PropTypes.string,
PropTypes.instanceOf(moment),
PropTypes.instanceOf(Date),
]),
/** Maximum date that can be selected. */
maxDate: PropTypes.oneOfType([
PropTypes.string,
PropTypes.instanceOf(moment),
PropTypes.instanceOf(Date),
]),
/** Minimum date that can be selected. */
minDate: PropTypes.oneOfType([
PropTypes.string,
PropTypes.instanceOf(moment),
PropTypes.instanceOf(Date),
]),
/** If true, popup closes after selecting a date-time. */
closable: PropTypes.bool,
};
DatesRangeInput.defaultProps = {
dateFormat: 'DD-MM-YYYY',
};
export default DatesRangeInput;