import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { DayPickerRangeController, isInclusivelyAfterDay, isInclusivelyBeforeDay, } from 'react-dates'; import classNames from 'classnames'; import moment from 'moment'; import { START_DATE } from '../../util/dates'; import config from '../../config'; import { IconArrowHead } from '../../components'; import css from './DateRangeController.css'; export const HORIZONTAL_ORIENTATION = 'horizontal'; export const ANCHOR_LEFT = 'left'; // IconArrowHead component might not be defined if exposed directly to the file. // This component is called before IconArrowHead component in components/index.js const PrevIcon = props => ( ); const NextIcon = props => ( ); const defaultProps = { startDateOffset: undefined, endDateOffset: undefined, // calendar presentation and interaction related props orientation: HORIZONTAL_ORIENTATION, verticalHeight: undefined, withPortal: false, isRTL: false, initialVisibleMonth: null, firstDayOfWeek: config.i18n.firstDayOfWeek, numberOfMonths: 1, daySize: 38, keepOpenOnDateSelect: false, renderCalendarInfo: null, hideKeyboardShortcutsPanel: true, // navigation related props navPrev: , navNext: , onPrevMonthClick() {}, onNextMonthClick() {}, transitionDuration: 200, // milliseconds between next month changes etc. renderCalendarDay: undefined, // If undefined, renders react-dates/lib/components/CalendarDay // day presentation and interaction related props renderDayContents: day => { return {day.format('D')}; }, minimumNights: config.bookingUnitType === 'line-item/night' ? 1 : 0, enableOutsideDays: false, isDayBlocked: () => false, // outside range -><- today ... today+available days -1 -><- outside range isOutsideRange: day => { const endOfRange = config.dayCountAvailableForBooking - 1; return ( !isInclusivelyAfterDay(day, moment()) || !isInclusivelyBeforeDay(day, moment().add(endOfRange, 'days')) ); }, isDayHighlighted: () => {}, // Internationalization props // Multilocale support can be achieved with displayFormat like moment.localeData.longDateFormat('L') // https://momentjs.com/ // displayFormat: 'ddd, MMM D', monthFormat: 'MMMM YYYY', weekDayFormat: 'dd', phrases: {}, // Add overwrites to default phrases used by react-dates }; class DateRangeController extends Component { constructor(props) { super(props); this.state = { startDate: props.value && props.value.startDate ? moment(props.value.startDate) : null, endDate: props.value && props.value.endDate ? moment(props.value.endDate) : null, focusedInput: START_DATE, }; this.onDatesChange = this.onDatesChange.bind(this); this.onFocusChange = this.onFocusChange.bind(this); this.onReset = this.onReset.bind(this); } onDatesChange(values) { const { startDate, endDate } = values; const start = startDate ? startDate.toDate() : null; const end = endDate ? endDate.toDate() : null; this.setState({ startDate, endDate }); if (startDate && endDate) { this.props.onChange({ startDate: start, endDate: end }); } } onFocusChange(focusedInput) { this.setState({ // Force the focusedInput to always be truthy so that dates are always selectable focusedInput: !focusedInput ? START_DATE : focusedInput, }); } onReset(startDate, endDate) { if (startDate && endDate) { this.setState({ startDate: moment(startDate), endDate: moment(endDate), focusedInput: START_DATE, }); } else { this.setState({ startDate: null, endDate: null, focusedInput: START_DATE, }); } } render() { // Removing Final Form field props: name, value, onChange, onFocus, meta, children, render const { rootClassName, className, name, value, onChange, onFocus, meta, children, render, ...controllerProps } = this.props; const classes = classNames(rootClassName || css.inputRoot, className); const startDateFromState = this.state.startDate; const endDateFromState = this.state.endDate; const startDateFromForm = value && value.startDate ? moment(value.startDate) : null; const endDateFromForm = value && value.endDate ? moment(value.endDate) : null; const isSelected = startDateFromState && endDateFromState; // Value given by Final Form reflects url params and is valid if both dates are set. // If only one date is selected state should be used to get the correct date. const startDate = isSelected ? startDateFromForm : startDateFromState; const endDate = isSelected ? endDateFromForm : endDateFromState; return (
); } } DateRangeController.defaultProps = { rootClassName: null, className: null, ...defaultProps, }; const { string } = PropTypes; DateRangeController.propTypes = { rootClassName: string, className: string, }; export default DateRangeController;