diff --git a/src/containers/BookingDatesForm/BookingDatesForm.js b/src/containers/BookingDatesForm/BookingDatesForm.js index 48b845e2..16772b22 100644 --- a/src/containers/BookingDatesForm/BookingDatesForm.js +++ b/src/containers/BookingDatesForm/BookingDatesForm.js @@ -1,12 +1,11 @@ import React, { Component } from 'react'; -import PropTypes from 'prop-types'; +import { string, bool } from 'prop-types'; import { compose } from 'redux'; -import { connect } from 'react-redux'; -import { reduxForm, formValueSelector, propTypes as formPropTypes } from 'redux-form'; +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 } from '../../util/validators'; +import { required, bookingDatesRequired, composeValidators } from '../../util/validators'; import { START_DATE, END_DATE } from '../../util/dates'; import { propTypes } from '../../util/types'; import config from '../../config'; @@ -34,7 +33,7 @@ export class BookingDatesFormComponent extends Component { // focus on that input, otherwise continue with the // default handleSubmit function. handleFormSubmit(e) { - const { startDate, endDate } = this.props.bookingDates; + const { startDate, endDate } = e.bookingDates || {}; if (!startDate) { e.preventDefault(); this.setState({ focusedInput: START_DATE }); @@ -42,28 +41,13 @@ export class BookingDatesFormComponent extends Component { e.preventDefault(); this.setState({ focusedInput: END_DATE }); } else { - this.props.handleSubmit(e); + this.props.onSubmit(e); } } render() { - const { - rootClassName, - className, - submitButtonWrapperClassName, - unitType, - bookingDates, - form, - price: unitPrice, - intl, - startDatePlaceholder, - endDatePlaceholder, - isOwnListing, - } = this.props; - - const { startDate, endDate } = bookingDates; + const { rootClassName, className, price: unitPrice, ...rest } = this.props; const classes = classNames(rootClassName || css.root, className); - const submitButtonClasses = classNames(css.submitButtonWrapper, submitButtonWrapperClassName); if (!unitPrice) { return ( @@ -84,91 +68,124 @@ export class BookingDatesFormComponent extends Component { ); } - 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' }); - - // This is the place to collect breakdown estimation data. See the - // EstimatedBreakdownMaybe component to change the calculations - // for customised 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); - return ( -
- - {bookingInfo} -

- -

-
- - - -
- + { + const { + endDatePlaceholder, + startDatePlaceholder, + form, + handleSubmit, + intl, + isOwnListing, + submitButtonWrapperClassName, + unitPrice, + unitType, + values, + } = 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', + }); + + // This is the place to collect breakdown estimation data. See the + // EstimatedBreakdownMaybe component to change the calculations + // for customised 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( + css.submitButtonWrapper, + submitButtonWrapperClassName + ); + + return ( +
+ + {bookingInfo} +

+ +

+
+ + + +
+ + ); + }} + /> ); } } @@ -183,11 +200,7 @@ BookingDatesFormComponent.defaultProps = { endDatePlaceholder: null, }; -const { instanceOf, shape, string, bool } = PropTypes; - BookingDatesFormComponent.propTypes = { - ...formPropTypes, - rootClassName: string, className: string, submitButtonWrapperClassName: string, @@ -196,12 +209,6 @@ BookingDatesFormComponent.propTypes = { price: propTypes.money, isOwnListing: bool, - // from formValueSelector - bookingDates: shape({ - startDate: instanceOf(Date), - endDate: instanceOf(Date), - }).isRequired, - // from injectIntl intl: intlShape.isRequired, @@ -210,21 +217,7 @@ BookingDatesFormComponent.propTypes = { endDatePlaceholder: string, }; -const formName = 'BookingDates'; - -// When a field depends on the value of another field, we must connect -// to the store and select the required values to inject to the -// component. -// -// See: http://redux-form.com/6.6.1/examples/selectingFormValues/ -const selector = formValueSelector(formName); -const mapStateToProps = state => ({ bookingDates: selector(state, 'bookingDates') || {} }); - -const BookingDatesForm = compose( - connect(mapStateToProps), - reduxForm({ form: formName }), - injectIntl -)(BookingDatesFormComponent); +const BookingDatesForm = compose(injectIntl)(BookingDatesFormComponent); BookingDatesForm.displayName = 'BookingDatesForm'; export default BookingDatesForm; diff --git a/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap b/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap index 2164cfc9..7aac3053 100644 --- a/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap +++ b/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap @@ -1,48 +1,61 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`BookingDatesForm matches snapshot without selected dates 1`] = ` -
- -

- -

-
- - - -
- + } + invalid={false} + isOwnListing={false} + onSubmit={[Function]} + pristine={true} + pure={true} + render={[Function]} + reset={[Function]} + resetSection={[Function]} + startDatePlaceholder="today" + submit={[Function]} + submitButtonWrapperClassName={null} + submitFailed={false} + submitSucceeded={false} + submitting={false} + touch={[Function]} + unitPrice={ + Money { + "amount": 1099, + "currency": "USD", + } + } + unitType="line-item/night" + untouch={[Function]} + valid={true} +/> `;