diff --git a/src/components/BookingInfo/BookingInfo.css b/src/components/BookingInfo/BookingInfo.css new file mode 100644 index 00000000..214777e4 --- /dev/null +++ b/src/components/BookingInfo/BookingInfo.css @@ -0,0 +1,18 @@ +.container { + display: flex; + flex-direction: column; +} + +.row { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.totalDivider { + width: 100%; +} + +.totalPrice { + font-weight: bold; +} diff --git a/src/components/BookingInfo/BookingInfo.example.js b/src/components/BookingInfo/BookingInfo.example.js index b20ac3ff..9797d6ca 100644 --- a/src/components/BookingInfo/BookingInfo.example.js +++ b/src/components/BookingInfo/BookingInfo.example.js @@ -1,12 +1,11 @@ -/* eslint-disable import/prefer-default-export */ +import { types } from '../../util/sdkLoader'; import BookingInfo from './BookingInfo'; export const Empty = { component: BookingInfo, props: { - pricePerDay: '55\u20AC', - bookingPeriod: 'Jan 2nd - Jan 4th', - bookingDuration: '3 days', - total: '165\u20AC', + unitPrice: new types.Money(10, 'USD'), + bookingStart: new Date('Fri, 14 Apr 2017 GMT'), + bookingEnd: new Date('Sun, 16 Apr 2017 GMT'), }, }; diff --git a/src/components/BookingInfo/BookingInfo.js b/src/components/BookingInfo/BookingInfo.js index 1fec2bc1..9cb8124b 100644 --- a/src/components/BookingInfo/BookingInfo.js +++ b/src/components/BookingInfo/BookingInfo.js @@ -1,32 +1,91 @@ +/** + * This component will show the booking info and calculated total price. + * I.e. dates and other details related to payment decision in receipt format. + */ import React, { PropTypes } from 'react'; +import { FormattedMessage, intlShape, injectIntl } from 'react-intl'; +import Decimal from 'decimal.js'; +import moment from 'moment'; +import classNames from 'classnames'; +import config from '../../config'; +import { convertMoneyToNumber } from '../../util/currency'; +import { types } from '../../util/sdkLoader'; +import css from './BookingInfo.css'; + +const BookingInfoComponent = props => { + const { bookingStart, bookingEnd, className, intl, unitPrice } = props; + + const hasSelectedDays = bookingStart && bookingEnd; + const bookingPeriod = hasSelectedDays + ? + : ''; + const nightCount = hasSelectedDays ? moment(bookingEnd).diff(moment(bookingStart), 'days') : null; + const nightCountMessage = nightCount + ? + : null; + + const priceAsNumber = convertMoneyToNumber(unitPrice, config.currencyConfig.subUnitDivisor); + const formattedPrice = intl.formatNumber(priceAsNumber, config.currencyConfig); + const totalPriceAsNumber = hasSelectedDays + ? new Decimal(priceAsNumber).times(nightCount).toNumber() + : null; + const formattedTotalPrice = hasSelectedDays + ? intl.formatNumber(totalPriceAsNumber, config.currencyConfig) + : null; -const BookingInfo = props => { - const { pricePerDay, bookingPeriod, bookingDuration, total } = props; return ( -
-
- Price per day: -
-
{pricePerDay}
-
- Booking period: -
-
{`${bookingPeriod}, ${bookingDuration}`}
-
- Total -
-
{total}
-
+
+
+
+ +
+
+ {formattedPrice} +
+
+
+
+ +
+ {bookingPeriod} +
+
+ {nightCountMessage} +
+
+
+
+
+ +
+
+ {formattedTotalPrice} +
+
+
); }; -const { string } = PropTypes; +BookingInfoComponent.defaultProps = { bookingStart: null, bookingEnd: null, className: '' }; -BookingInfo.propTypes = { - pricePerDay: string.isRequired, - bookingPeriod: string.isRequired, - bookingDuration: string.isRequired, - total: string.isRequired, +const { instanceOf, string } = PropTypes; + +BookingInfoComponent.propTypes = { + bookingStart: instanceOf(Date), + bookingEnd: instanceOf(Date), + className: string, + intl: intlShape.isRequired, + unitPrice: instanceOf(types.Money).isRequired, }; +const BookingInfo = injectIntl(BookingInfoComponent); + +BookingInfo.displayName = 'BookingInfo'; + export default BookingInfo; diff --git a/src/components/BookingInfo/BookingInfo.test.js b/src/components/BookingInfo/BookingInfo.test.js index a5da72cc..d159d23d 100644 --- a/src/components/BookingInfo/BookingInfo.test.js +++ b/src/components/BookingInfo/BookingInfo.test.js @@ -1,15 +1,17 @@ import React from 'react'; +import { fakeIntl } from '../../util/test-data'; import { renderDeep } from '../../util/test-helpers'; +import { types } from '../../util/sdkLoader'; import BookingInfo from './BookingInfo'; describe('BookingInfo', () => { it('matches snapshot', () => { const tree = renderDeep( ); expect(tree).toMatchSnapshot(); diff --git a/src/components/BookingInfo/__snapshots__/BookingInfo.test.js.snap b/src/components/BookingInfo/__snapshots__/BookingInfo.test.js.snap index 67985c26..fa377ead 100644 --- a/src/components/BookingInfo/__snapshots__/BookingInfo.test.js.snap +++ b/src/components/BookingInfo/__snapshots__/BookingInfo.test.js.snap @@ -1,22 +1,52 @@ exports[`BookingInfo matches snapshot 1`] = ` -
-
- Price per day: -
-
- 55\\\\u20AC -
-
- Booking period: -
-
- Jan 2nd - Jan 4th, 3 days -
-
- Total -
-
- 165\\u20AC -
-
+
+
+
+ + Price per day: + +
+
+ $10.00 +
+
+
+
+ + Booking period: + +
+ + 04/14/2017 - 04/16/2017 + +
+
+ + 2 days + +
+
+
+
+
+ + Total: + +
+
+ $20.00 +
+
+
`; diff --git a/src/components/CurrencyInput/CurrencyInput.example.js b/src/components/CurrencyInput/CurrencyInput.example.js index f21bb246..fc3a89db 100644 --- a/src/components/CurrencyInput/CurrencyInput.example.js +++ b/src/components/CurrencyInput/CurrencyInput.example.js @@ -1,4 +1,3 @@ -/* eslint-disable import/prefer-default-export */ import React, { PropTypes } from 'react'; import { IntlProvider, addLocaleData } from 'react-intl'; import en from 'react-intl/locale-data/en'; diff --git a/src/components/DateInput/DateInput.example.js b/src/components/DateInput/DateInput.example.js index df9ede29..716cf63b 100644 --- a/src/components/DateInput/DateInput.example.js +++ b/src/components/DateInput/DateInput.example.js @@ -1,4 +1,4 @@ -/* eslint-disable import/prefer-default-export, no-console */ +/* eslint-disable no-console */ import React, { PropTypes } from 'react'; import { Field, reduxForm, propTypes as formPropTypes } from 'redux-form'; import moment from 'moment'; diff --git a/src/components/DateInput/DateInput.js b/src/components/DateInput/DateInput.js index 7ec67e04..01dac82f 100644 --- a/src/components/DateInput/DateInput.js +++ b/src/components/DateInput/DateInput.js @@ -3,10 +3,10 @@ * Styles for SingleDatePicker can be found from 'public/reactDates.css'. * CSS modules can't handle global styles so they are currently added separately */ -import React, { PropTypes } from 'react'; -import momentPropTypes from 'react-moment-proptypes'; -import moment from 'moment'; +import React, { Component, PropTypes } from 'react'; +import { intlShape, injectIntl } from 'react-intl'; import { SingleDatePicker, isInclusivelyAfterDay } from 'react-dates'; +import moment from 'moment'; const HORIZONTAL_ORIENTATION = 'horizontal'; const ANCHOR_LEFT = 'left'; @@ -18,10 +18,10 @@ const defaultProps = { // input related props id: 'date', - placeholder: 'Date', + placeholder: null, // Handled inside component disabled: false, - required: true, - screenReaderInputMessage: '', + required: false, + screenReaderInputMessage: null, // Handled inside component showClearDate: false, // calendar presentation and interaction related props @@ -52,12 +52,12 @@ const defaultProps = { displayFormat: () => moment.localeData().longDateFormat('L'), monthFormat: 'MMMM YYYY', phrases: { - closeDatePicker: 'Close', - clearDate: 'Clear Date', + closeDatePicker: null, // Handled inside component + clearDate: null, // Handled inside component }, }; -class DateInput extends React.Component { +class DateInputComponent extends Component { constructor(props) { super(props); this.state = { @@ -69,7 +69,7 @@ class DateInput extends React.Component { } onDateChange(date) { - this.props.onChange(date instanceof moment ? date.clone() : null); + this.props.onChange(date instanceof moment ? date.toDate() : null); } onFocusChange({ focused }) { @@ -85,9 +85,34 @@ class DateInput extends React.Component { render() { const { focused } = this.state; - // eslint-disable-next-line no-unused-vars - const { initialDate, onBlur, onChange, onFocus, value, ...datePickerProps } = this.props; - const date = value instanceof moment ? value.clone() : initialDate; + /* eslint-disable no-unused-vars */ + const { + initialDate, + intl, + placeholder, + onBlur, + onChange, + onFocus, + phrases, + screenReaderInputMessage, + value, + ...datePickerProps + } = this.props; + /* eslint-enable no-unused-vars */ + + const initialMoment = initialDate ? moment(initialDate) : null; + const date = value instanceof Date ? moment(value) : initialMoment; + + const placeholderText = placeholder || + intl.formatMessage({ id: 'DateInput.defaultPlaceholder' }); + const screenReaderInputText = screenReaderInputMessage || + intl.formatMessage({ id: 'DateInput.screenReaderInputMessage' }); + const closeDatePickerText = phrases.closeDatePicker + ? phrases.closeDatePicker + : intl.formatMessage({ id: 'DateInput.closeDatePicker' }); + const clearDateText = phrases.clearDate + ? phrases.clearDate + : intl.formatMessage({ id: 'DateInput.clearDate' }); return (
@@ -98,23 +123,37 @@ class DateInput extends React.Component { focused={focused} onDateChange={this.onDateChange} onFocusChange={this.onFocusChange} + placeholder={placeholderText} + screenReaderInputMessage={screenReaderInputText} + phrases={{ closeDatePicker: closeDatePickerText, clearDate: clearDateText }} />
); } } -DateInput.defaultProps = defaultProps; +DateInputComponent.defaultProps = defaultProps; -const { func, string } = PropTypes; +const { func, instanceOf, shape, string } = PropTypes; -DateInput.propTypes = { - initialDate: momentPropTypes.momentObj, +DateInputComponent.propTypes = { + initialDate: instanceOf(Date), + intl: intlShape.isRequired, + isOutsideRange: func, onChange: func.isRequired, onBlur: func.isRequired, onFocus: func.isRequired, + phrases: shape({ + closeDatePicker: string, + clearDate: string, + }), placeholder: string, - value: momentPropTypes.momentObj, + screenReaderInputMessage: string, + value: instanceOf(Date), }; +const DateInput = injectIntl(DateInputComponent); + +DateInput.displayName = 'DateInput'; + export default DateInput; diff --git a/src/components/DateInput/__snapshots__/DateInput.test.js.snap b/src/components/DateInput/__snapshots__/DateInput.test.js.snap index 35012ac8..ca1778b2 100644 --- a/src/components/DateInput/__snapshots__/DateInput.test.js.snap +++ b/src/components/DateInput/__snapshots__/DateInput.test.js.snap @@ -8,8 +8,8 @@ exports[`DateInput matches snapshot 1`] = `
- +

+ Date input +

- Date + Date input
diff --git a/src/components/ListingCard/ListingCard.example.js b/src/components/ListingCard/ListingCard.example.js index 9b739502..17511ed2 100644 --- a/src/components/ListingCard/ListingCard.example.js +++ b/src/components/ListingCard/ListingCard.example.js @@ -1,4 +1,4 @@ -/* eslint-disable no-console, import/prefer-default-export */ +/* eslint-disable no-console */ import React from 'react'; import ListingCard from './ListingCard'; import { createUser, createListing, currencyConfig, fakeIntl } from '../../util/test-data'; diff --git a/src/components/ModalInMobile/ModalInMobile.example.js b/src/components/ModalInMobile/ModalInMobile.example.js index b19caba4..f70d36c5 100644 --- a/src/components/ModalInMobile/ModalInMobile.example.js +++ b/src/components/ModalInMobile/ModalInMobile.example.js @@ -1,4 +1,4 @@ -/* eslint-disable no-console, import/prefer-default-export */ +/* eslint-disable no-console */ import React, { Component } from 'react'; import { Button } from '../../components'; import ModalInMobile from './ModalInMobile'; diff --git a/src/components/NamedLink/NamedLink.example.js b/src/components/NamedLink/NamedLink.example.js index afc54921..87d4816a 100644 --- a/src/components/NamedLink/NamedLink.example.js +++ b/src/components/NamedLink/NamedLink.example.js @@ -1,4 +1,4 @@ -/* eslint-disable no-console, import/prefer-default-export */ +/* eslint-disable no-console */ import NamedLink from './NamedLink'; export const NamedLinkToSearchPage = { diff --git a/src/components/OrderDetailsPanel/OrderDetailsPanel.js b/src/components/OrderDetailsPanel/OrderDetailsPanel.js index 8c1fcdde..1823babb 100644 --- a/src/components/OrderDetailsPanel/OrderDetailsPanel.js +++ b/src/components/OrderDetailsPanel/OrderDetailsPanel.js @@ -1,5 +1,5 @@ import React, { PropTypes } from 'react'; -import { BookingInfo, NamedLink } from '../../components'; +import { NamedLink } from '../../components'; import css from './OrderDetailsPanel.css'; @@ -24,14 +24,13 @@ ContactInfo.propTypes = { }; const OrderDetailsPanel = props => { - const { className, orderId, title, imageUrl, info, contact, confirmationCode } = props; + const { className, orderId, title, imageUrl, contact, confirmationCode } = props; return (
{title}

{title}

Confirmation code {confirmationCode}

-

Cancel booking

You have a new message! @@ -47,7 +46,6 @@ OrderDetailsPanel.propTypes = { orderId: oneOfType([string, number]).isRequired, title: string.isRequired, imageUrl: string.isRequired, - info: object.isRequired, contact: object.isRequired, confirmationCode: string.isRequired, }; diff --git a/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap b/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap index 46780dd4..ccbf920c 100644 --- a/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap +++ b/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap @@ -20,11 +20,6 @@ exports[`OrderDetailsPanel matches snapshot 1`] = ` Confirmation code some-test-confirmation-code

-

Cancel booking

diff --git a/src/components/index.js b/src/components/index.js index c860eafd..61c1b777 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -2,6 +2,7 @@ import AddImages from './AddImages/AddImages'; import BookingInfo from './BookingInfo/BookingInfo'; import Button from './Button/Button'; import CurrencyInput from './CurrencyInput/CurrencyInput'; +import DateInput from './DateInput/DateInput'; import Discussion from './Discussion/Discussion'; import FilterPanel from './FilterPanel/FilterPanel'; import HeroSection from './HeroSection/HeroSection'; @@ -30,6 +31,7 @@ export { BookingInfo, Button, CurrencyInput, + DateInput, Discussion, FilterPanel, HeroSection, diff --git a/src/containers/BookingDatesForm/BookingDatesForm.css b/src/containers/BookingDatesForm/BookingDatesForm.css new file mode 100644 index 00000000..cb2ffee2 --- /dev/null +++ b/src/containers/BookingDatesForm/BookingDatesForm.css @@ -0,0 +1,23 @@ +.receipt { + margin-top: 1rem; + margin-bottom: 2rem; +} + +.totalDivider { + width: 100%; +} + +.totalPrice { + font-weight: bold; +} + +.error { + color: red; + margin-top: 10px; + display: inline-block; +} + +.smallPrint { + font-size: 12px; + text-align: center; +} diff --git a/src/containers/BookingDatesForm/BookingDatesForm.example.js b/src/containers/BookingDatesForm/BookingDatesForm.example.js new file mode 100644 index 00000000..c1558b77 --- /dev/null +++ b/src/containers/BookingDatesForm/BookingDatesForm.example.js @@ -0,0 +1,13 @@ +/* eslint-disable no-console */ +import { types } from '../../util/sdkLoader'; +import BookingDatesForm from './BookingDatesForm'; + +export const Empty = { + component: BookingDatesForm, + props: { + onSubmit: values => { + console.log('Submit BookingDatesForm with values:', values); + }, + price: new types.Money(1099, 'USD'), + }, +}; diff --git a/src/containers/BookingDatesForm/BookingDatesForm.js b/src/containers/BookingDatesForm/BookingDatesForm.js new file mode 100644 index 00000000..5ce80c37 --- /dev/null +++ b/src/containers/BookingDatesForm/BookingDatesForm.js @@ -0,0 +1,147 @@ +import React, { PropTypes } from 'react'; +import { compose } from 'redux'; +import { connect } from 'react-redux'; +import { Field, reduxForm, formValueSelector, propTypes as formPropTypes } from 'redux-form'; +import { FormattedMessage, intlShape, injectIntl } from 'react-intl'; +import { isInclusivelyAfterDay, isInclusivelyBeforeDay } from 'react-dates'; +import moment from 'moment'; +import { types } from '../../util/sdkLoader'; +import { required } from '../../util/validators'; +import { Button, BookingInfo, DateInput } from '../../components'; +import css from './BookingDatesForm.css'; + +const EnhancedDateInput = props => { + const { input, isOutsideRange, labelMessage, placeholder, meta } = props; + const { onBlur, onChange, onFocus, value } = input; + const { touched, error } = meta; + const maybeIsOutsideRange = isOutsideRange ? { isOutsideRange } : {}; + const inputProps = { ...maybeIsOutsideRange, onBlur, onChange, onFocus, placeholder, value }; + + return ( +
+ {labelMessage ? : null} + + {touched && error ? {error} : null} +
+ ); +}; + +EnhancedDateInput.defaultProps = { + input: null, + isOutsideRange: null, + labelMessage: null, + placeholder: 'Date', +}; + +const { bool, func, instanceOf, node, object, shape, string } = PropTypes; + +EnhancedDateInput.propTypes = { + input: object, + isOutsideRange: func, + labelMessage: node, + meta: shape({ + touched: bool, + error: string, + }).isRequired, + placeholder: string, +}; + +export const BookingDatesFormComponent = props => { + const { + bookingStart, + bookingEnd, + className, + handleSubmit, + intl, + price, + pristine, + submitting, + } = props; + const placeholderText = intl.formatMessage({ id: 'BookingDatesForm.placeholder' }); + const bookingStartLabel = intl.formatMessage({ id: 'BookingDatesForm.bookingStartTitle'}); + const bookingEndLabel = intl.formatMessage({ id: 'BookingDatesForm.bookingEndTitle'}); + const requiredMessage = intl.formatMessage({ id: 'BookingDatesForm.requiredDate' }); + + // A day is outside range if it is between today and booking end date (if end date has been chosen) + const isOutsideRangeStart = bookingEnd + ? { + isOutsideRange: day => + !(isInclusivelyAfterDay(day, moment()) && + isInclusivelyBeforeDay(day, moment(bookingEnd))), + } + : {}; + + // A day is outside range if it is after booking start date (or today if none is chosen) + const startOfBookingEndRange = bookingStart ? moment(bookingStart) : moment(); + const isOutsideRangeEnd = bookingStart + ? { isOutsideRange: day => !isInclusivelyAfterDay(day, startOfBookingEndRange) } + : {}; + + const bookingInfo = price + ? + : null; + + const invalid = !(bookingStart && bookingEnd); + + return ( +
+ + + {bookingInfo} +

+ +

+ + + ); +}; + +BookingDatesFormComponent.propTypes = { + ...formPropTypes, + intl: intlShape.isRequired, + price: instanceOf(types.Money).isRequired, +}; + +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 => { + return selector(state, 'bookingStart', 'bookingEnd'); +}; + +const BookingDatesForm = compose( + connect(mapStateToProps), + reduxForm({ form: formName }), + injectIntl +)(BookingDatesFormComponent); +BookingDatesForm.displayName = 'BookingDatesForm'; + +export default BookingDatesForm; diff --git a/src/containers/BookingDatesForm/BookingDatesForm.test.js b/src/containers/BookingDatesForm/BookingDatesForm.test.js new file mode 100644 index 00000000..72ba4fc0 --- /dev/null +++ b/src/containers/BookingDatesForm/BookingDatesForm.test.js @@ -0,0 +1,22 @@ +import React from 'react'; +import { types } from '../../util/sdkLoader'; +import { renderShallow } from '../../util/test-helpers'; +import { fakeIntl, fakeFormProps } from '../../util/test-data'; +import { BookingDatesFormComponent } from './BookingDatesForm'; + +const noop = () => null; + +describe('BookingDatesForm', () => { + it('matches snapshot', () => { + const tree = renderShallow( + v} + price={new types.Money(1099, 'USD')} + /> + ); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap b/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap new file mode 100644 index 00000000..ea220fc4 --- /dev/null +++ b/src/containers/BookingDatesForm/__snapshots__/BookingDatesForm.test.js.snap @@ -0,0 +1,47 @@ +exports[`BookingDatesForm matches snapshot 1`] = ` +
+ + + +

+ +

+ + +`; diff --git a/src/containers/ChangeAccountPasswordForm/ChangeAccountPasswordForm.example.js b/src/containers/ChangeAccountPasswordForm/ChangeAccountPasswordForm.example.js index 5e480a54..513d1ea8 100644 --- a/src/containers/ChangeAccountPasswordForm/ChangeAccountPasswordForm.example.js +++ b/src/containers/ChangeAccountPasswordForm/ChangeAccountPasswordForm.example.js @@ -1,4 +1,4 @@ -/* eslint-disable no-console, import/prefer-default-export */ +/* eslint-disable no-console */ import ChangeAccountPasswordForm from './ChangeAccountPasswordForm'; export const Empty = { diff --git a/src/containers/ChangePasswordForm/ChangePasswordForm.example.js b/src/containers/ChangePasswordForm/ChangePasswordForm.example.js index dbbc6b91..c7dd7703 100644 --- a/src/containers/ChangePasswordForm/ChangePasswordForm.example.js +++ b/src/containers/ChangePasswordForm/ChangePasswordForm.example.js @@ -1,4 +1,4 @@ -/* eslint-disable no-console, import/prefer-default-export */ +/* eslint-disable no-console */ import ChangePasswordForm from './ChangePasswordForm'; export const Empty = { diff --git a/src/containers/EditListingForm/EditListingForm.example.js b/src/containers/EditListingForm/EditListingForm.example.js index ad22e0a7..c73352d6 100644 --- a/src/containers/EditListingForm/EditListingForm.example.js +++ b/src/containers/EditListingForm/EditListingForm.example.js @@ -1,4 +1,4 @@ -/* eslint-disable no-console, import/prefer-default-export */ +/* eslint-disable no-console */ import EditListingForm from './EditListingForm'; export const Empty = { diff --git a/src/containers/HeroSearchForm/HeroSearchForm.example.js b/src/containers/HeroSearchForm/HeroSearchForm.example.js index 6f763010..623faf7c 100644 --- a/src/containers/HeroSearchForm/HeroSearchForm.example.js +++ b/src/containers/HeroSearchForm/HeroSearchForm.example.js @@ -1,4 +1,4 @@ -/* eslint-disable no-console, import/prefer-default-export */ +/* eslint-disable no-console */ import HeroSearchForm from './HeroSearchForm'; export const Empty = { diff --git a/src/containers/ListingPage/ListingPage.css b/src/containers/ListingPage/ListingPage.css index fa6e4aaa..3eea1da6 100644 --- a/src/containers/ListingPage/ListingPage.css +++ b/src/containers/ListingPage/ListingPage.css @@ -67,7 +67,11 @@ background-color: #eee; } -.openDatePickerForm { +.bookingForm { + margin: 0 1rem; +} + +.openBookingForm { position: fixed; bottom: 0; left: 0; diff --git a/src/containers/ListingPage/ListingPage.js b/src/containers/ListingPage/ListingPage.js index 9843212c..31ec6806 100644 --- a/src/containers/ListingPage/ListingPage.js +++ b/src/containers/ListingPage/ListingPage.js @@ -6,6 +6,7 @@ import config from '../../config'; import { types } from '../../util/sdkLoader'; import { convertMoneyToNumber } from '../../util/currency'; import { Button, Map, ModalInMobile, PageLayout } from '../../components'; +import { BookingDatesForm } from '../../containers'; import { getListingsById } from '../../ducks/sdk.duck'; import { showListing } from './ListingPage.duck'; import css from './ListingPage.css'; @@ -39,9 +40,22 @@ export class ListingPageComponent extends Component { isBookingModalOpenOnMobile: tab && tab === 'book', pageClassNames: '', }; + + this.onSubmit = this.onSubmit.bind(this); this.togglePageClassNames = this.togglePageClassNames.bind(this); } + onSubmit(values) { + const { marketplaceData, params } = this.props; + const id = new UUID(params.id); + const listingsById = getListingsById(marketplaceData, [id]); + const currentListing = listingsById.length > 0 ? listingsById[0] : null; + + this.setState({ isBookingModalOpenOnMobile: false }); + // eslint-disable-next-line no-console + console.log('Submitting: bookedDates', values, 'and price', currentListing.attributes.price); + } + togglePageClassNames(className, addClass = true) { this.setState(prevState => { const prevPageClassNames = prevState.pageClassNames.split(' '); @@ -116,10 +130,10 @@ export class ListingPageComponent extends Component { title={bookBtnMessage} togglePageClassNames={this.togglePageClassNames} > - ModalInMobile content + {map ?
{map}
: null} -
+
diff --git a/src/containers/ListingPage/ListingPage.test.js b/src/containers/ListingPage/ListingPage.test.js index 8c76c2b1..b0ed9c03 100644 --- a/src/containers/ListingPage/ListingPage.test.js +++ b/src/containers/ListingPage/ListingPage.test.js @@ -11,14 +11,19 @@ const { UUID } = types; describe('ListingPage', () => { it('matches snapshot', () => { const marketplaceData = { entities: { listing: { listing1: createListing('listing1') } } }; - const tree = renderShallow( - l} - /> - ); + const props = { + flattenedRoutes: [], + location: { search: '' }, + history: { + push: () => console.log('HistoryPush called'), + }, + params: { slug: 'listing1-title', id: 'listing1' }, + marketplaceData, + intl: fakeIntl, + onLoadListing: () => {}, + }; + + const tree = renderShallow(); expect(tree).toMatchSnapshot(); }); diff --git a/src/containers/ListingPage/__snapshots__/ListingPage.test.js.snap b/src/containers/ListingPage/__snapshots__/ListingPage.test.js.snap index 762e291e..c6acbc7c 100644 --- a/src/containers/ListingPage/__snapshots__/ListingPage.test.js.snap +++ b/src/containers/ListingPage/__snapshots__/ListingPage.test.js.snap @@ -24,9 +24,14 @@ exports[`ListingPage matches snapshot 1`] = ` showAsModalMaxWidth={2500} title="ListingPage.ctaButtonMessage" togglePageClassNames={[Function]}> - - ModalInMobile content - +
{ title, orderId, imageUrl: 'http://placehold.it/750x470', - info: { - pricePerDay: '55\u20AC', - bookingPeriod: 'Jan 2nd - Jan 4th', - bookingDuration: '3 days', - total: '165\u20AC', - }, contact: { addressLine1: '350 5th Avenue', addressLine2: 'New York, NY 10118', diff --git a/src/containers/OrderPage/__snapshots__/OrderPage.test.js.snap b/src/containers/OrderPage/__snapshots__/OrderPage.test.js.snap index fb8c4b88..2c05edda 100644 --- a/src/containers/OrderPage/__snapshots__/OrderPage.test.js.snap +++ b/src/containers/OrderPage/__snapshots__/OrderPage.test.js.snap @@ -35,14 +35,6 @@ exports[`OrderPage matches snapshot 1`] = ` } } imageUrl="http://placehold.it/750x470" - info={ - Object { - "bookingDuration": "3 days", - "bookingPeriod": "Jan 2nd - Jan 4th", - "pricePerDay": "55€", - "total": "165€", - } - } orderId={1234} title="Banyan Studios" /> }, {} ); -/* eslint-enable import/prefer-default-export */