import React, { Component } from 'react'; import { string, bool, arrayOf } from 'prop-types'; import { compose } from 'redux'; import { Form as FinalForm } from 'react-final-form'; import { FormattedMessage, intlShape, injectIntl } from 'react-intl'; import classNames from 'classnames'; import moment from 'moment'; import { required, bookingDatesRequired, composeValidators } from '../../util/validators'; import { START_DATE, END_DATE } from '../../util/dates'; import { propTypes } from '../../util/types'; import config from '../../config'; import { Form, PrimaryButton, FieldDateRangeInput } from '../../components'; import EstimatedBreakdownMaybe from './EstimatedBreakdownMaybe'; import css from './BookingDatesForm.css'; export class BookingDatesFormComponent extends Component { constructor(props) { super(props); this.state = { focusedInput: null }; this.handleFormSubmit = this.handleFormSubmit.bind(this); this.onFocusedInputChange = this.onFocusedInputChange.bind(this); } // Function that can be passed to nested components // so that they can notify this component when the // focused input changes. onFocusedInputChange(focusedInput) { this.setState({ focusedInput }); } // In case start or end date for the booking is missing // focus on that input, otherwise continue with the // default handleSubmit function. handleFormSubmit(e) { const { startDate, endDate } = e.bookingDates || {}; if (!startDate) { e.preventDefault(); this.setState({ focusedInput: START_DATE }); } else if (!endDate) { e.preventDefault(); this.setState({ focusedInput: END_DATE }); } else { this.props.onSubmit(e); } } render() { const { rootClassName, className, price: unitPrice, ...rest } = this.props; const classes = classNames(rootClassName || css.root, className); if (!unitPrice) { return (

); } if (unitPrice.currency !== config.currency) { return (

); } return ( { const { endDatePlaceholder, startDatePlaceholder, form, handleSubmit, intl, isOwnListing, submitButtonWrapperClassName, unitPrice, unitType, values, timeSlots, fetchTimeSlotsError, } = fieldRenderProps; const { startDate, endDate } = values && values.bookingDates ? values.bookingDates : {}; const bookingStartLabel = intl.formatMessage({ id: 'BookingDatesForm.bookingStartTitle', }); const bookingEndLabel = intl.formatMessage({ id: 'BookingDatesForm.bookingEndTitle' }); const requiredMessage = intl.formatMessage({ id: 'BookingDatesForm.requiredDate' }); const startDateErrorMessage = intl.formatMessage({ id: 'FieldDateRangeInput.invalidStartDate', }); const endDateErrorMessage = intl.formatMessage({ id: 'FieldDateRangeInput.invalidEndDate', }); const timeSlotsError = fetchTimeSlotsError ? (

) : null; // This is the place to collect breakdown estimation data. See the // EstimatedBreakdownMaybe component to change the calculations // for customized payment processes. const bookingData = startDate && endDate ? { unitType, unitPrice, startDate, endDate, // NOTE: If unitType is `line-item/units`, a new picker // for the quantity should be added to the form. quantity: 1, } : null; const bookingInfo = bookingData ? (

) : null; const dateFormatOptions = { weekday: 'short', month: 'short', day: 'numeric', }; const now = moment(); const today = now.startOf('day').toDate(); const tomorrow = now .startOf('day') .add(1, 'days') .toDate(); const startDatePlaceholderText = startDatePlaceholder || intl.formatDate(today, dateFormatOptions); const endDatePlaceholderText = endDatePlaceholder || intl.formatDate(tomorrow, dateFormatOptions); const submitButtonClasses = classNames( submitButtonWrapperClassName || css.submitButtonWrapper ); return (
{timeSlotsError} {bookingInfo}

); }} /> ); } } BookingDatesFormComponent.defaultProps = { rootClassName: null, className: null, submitButtonWrapperClassName: null, price: null, isOwnListing: false, startDatePlaceholder: null, endDatePlaceholder: null, timeSlots: null, }; BookingDatesFormComponent.propTypes = { rootClassName: string, className: string, submitButtonWrapperClassName: string, unitType: propTypes.bookingUnitType.isRequired, price: propTypes.money, isOwnListing: bool, timeSlots: arrayOf(propTypes.timeSlot), // from injectIntl intl: intlShape.isRequired, // for tests startDatePlaceholder: string, endDatePlaceholder: string, }; const BookingDatesForm = compose(injectIntl)(BookingDatesFormComponent); BookingDatesForm.displayName = 'BookingDatesForm'; export default BookingDatesForm;