diff --git a/src/components/Avatar/Avatar.css b/src/components/Avatar/Avatar.css
new file mode 100644
index 00000000..6cf812bf
--- /dev/null
+++ b/src/components/Avatar/Avatar.css
@@ -0,0 +1,3 @@
+.avatar {
+ border-radius: 50%;
+}
diff --git a/src/components/Avatar/Avatar.js b/src/components/Avatar/Avatar.js
new file mode 100644
index 00000000..ae94ca83
--- /dev/null
+++ b/src/components/Avatar/Avatar.js
@@ -0,0 +1,27 @@
+import React, { PropTypes } from 'react';
+import classNames from 'classnames';
+
+import css from './Avatar.css';
+
+const Avatar = props => {
+ const { className, name } = props;
+
+ // TODO hard coded placeholder image need to be changed to something else
+ const avatarImageURL = 'http://placehold.it/44x44';
+ const classes = classNames(css.avatar, className);
+
+ return
;
+};
+
+const { string } = PropTypes;
+
+Avatar.defaultProps = {
+ className: null,
+};
+
+Avatar.propTypes = {
+ className: string,
+ name: string.isRequired,
+};
+
+export default Avatar;
diff --git a/src/components/BookingInfo/BookingInfo.js b/src/components/BookingInfo/BookingInfo.js
index 6b9a8ff7..4daaddcf 100644
--- a/src/components/BookingInfo/BookingInfo.js
+++ b/src/components/BookingInfo/BookingInfo.js
@@ -13,7 +13,7 @@ import { types } from '../../util/sdkLoader';
import css from './BookingInfo.css';
const BookingInfoComponent = props => {
- const { bookingStart, bookingEnd, className, intl, unitPrice } = props;
+ const { bookingStart, bookingEnd, className, intl, totalPrice, unitPrice } = props;
const hasSelectedDays = bookingStart && bookingEnd;
const bookingPeriod = hasSelectedDays
@@ -30,13 +30,20 @@ const BookingInfoComponent = props => {
?
: null;
- const priceAsNumber = convertMoneyToNumber(unitPrice, config.currencyConfig.subUnitDivisor);
- const formattedPrice = intl.formatNumber(priceAsNumber, config.currencyConfig);
- const totalPriceAsNumber = hasSelectedDays
- ? new Decimal(priceAsNumber).times(nightCount).toNumber()
+ const currencyConfig = config.currencyConfig;
+ const subUnitDivisor = currencyConfig.subUnitDivisor;
+ const unitPriceAsNumber = convertMoneyToNumber(unitPrice, subUnitDivisor);
+ const formattedUnitPrice = intl.formatNumber(unitPriceAsNumber, currencyConfig);
+ const calculatedTotalPriceAsNumber = !totalPrice && hasSelectedDays
+ ? new Decimal(unitPriceAsNumber).times(nightCount).toNumber()
: null;
- const formattedTotalPrice = hasSelectedDays
- ? intl.formatNumber(totalPriceAsNumber, config.currencyConfig)
+
+ // Total price can be given (when it comes from API) or calculated based on unit price and nights
+ const totalPriceAsNumber = totalPrice
+ ? convertMoneyToNumber(totalPrice, subUnitDivisor)
+ : calculatedTotalPriceAsNumber;
+ const formattedTotalPrice = totalPriceAsNumber
+ ? intl.formatNumber(totalPriceAsNumber, currencyConfig)
: null;
return (
@@ -46,7 +53,7 @@ const BookingInfoComponent = props => {
- {formattedPrice}
+ {formattedUnitPrice}
@@ -72,7 +79,12 @@ const BookingInfoComponent = props => {
);
};
-BookingInfoComponent.defaultProps = { bookingStart: null, bookingEnd: null, className: '' };
+BookingInfoComponent.defaultProps = {
+ bookingStart: null,
+ bookingEnd: null,
+ className: '',
+ totalPrice: null,
+};
const { instanceOf, string } = PropTypes;
@@ -81,6 +93,7 @@ BookingInfoComponent.propTypes = {
bookingEnd: instanceOf(Date),
className: string,
intl: intlShape.isRequired,
+ totalPrice: instanceOf(types.Money),
unitPrice: instanceOf(types.Money).isRequired,
};
diff --git a/src/components/BookingInfo/__snapshots__/BookingInfo.test.js.snap b/src/components/BookingInfo/__snapshots__/BookingInfo.test.js.snap
index fba864c1..13494205 100644
--- a/src/components/BookingInfo/__snapshots__/BookingInfo.test.js.snap
+++ b/src/components/BookingInfo/__snapshots__/BookingInfo.test.js.snap
@@ -6,7 +6,7 @@ exports[`BookingInfo matches snapshot 1`] = `
- Price per day:
+ Price per night:
- 2 days
+ 2 nights
diff --git a/src/components/OrderDetailsPanel/OrderDetailsPanel.css b/src/components/OrderDetailsPanel/OrderDetailsPanel.css
index bd0370c6..2c0ff102 100644
--- a/src/components/OrderDetailsPanel/OrderDetailsPanel.css
+++ b/src/components/OrderDetailsPanel/OrderDetailsPanel.css
@@ -1,21 +1,17 @@
-.buttonLink {
- display: block;
- width: 100%;
- font-size: 1.4rem;
- padding: 0.5rem;
- margin: 1rem 0;
- background-color: #eee;
- border: 1px solid #ddd;
- cursor: pointer;
-
- text-align: center;
- text-decoration: none;
- color: #000;
-
- &:hover {
- background-color: #ddd;
- }
- &:active {
- background-color: #ccc;
- }
+.title,
+.receipt {
+ margin: 1rem 1rem 2rem 1rem;
+}
+
+.message {
+ display: flex;
+ margin: 1rem 1rem 2rem 1rem;
+}
+
+.avatarWrapper {
+ display: block;
+ flex-basis: 44px;
+ width: 44px;
+ height: 44px;
+ margin-right: 1rem;
}
diff --git a/src/components/OrderDetailsPanel/OrderDetailsPanel.js b/src/components/OrderDetailsPanel/OrderDetailsPanel.js
index 1823babb..28e8de87 100644
--- a/src/components/OrderDetailsPanel/OrderDetailsPanel.js
+++ b/src/components/OrderDetailsPanel/OrderDetailsPanel.js
@@ -1,53 +1,76 @@
import React, { PropTypes } from 'react';
-import { NamedLink } from '../../components';
+import { FormattedMessage } from 'react-intl';
+import * as propTypes from '../../util/propTypes';
+import { createSlug } from '../../util/urlHelpers';
+import { types } from '../../util/sdkLoader';
+import { Avatar, BookingInfo, NamedLink } from '../../components';
import css from './OrderDetailsPanel.css';
-const ContactInfo = props => {
- const { addressLine1, addressLine2, phoneNumber } = props;
- return (
-
-
{addressLine1}
-
{addressLine2}
-
{phoneNumber}
-
Get directions
-
- );
-};
-
-const { number, oneOfType, string, object } = PropTypes;
-
-ContactInfo.propTypes = {
- addressLine1: string.isRequired,
- addressLine2: string.isRequired,
- phoneNumber: string.isRequired,
-};
-
const OrderDetailsPanel = props => {
- const { className, orderId, title, imageUrl, contact, confirmationCode } = props;
+ const { className, totalPrice, orderState, booking, listing, provider } = props;
+ const { firstName, lastName } = provider.attributes.profile;
+ const providerName = firstName ? `${firstName} ${lastName}` : '';
+
+ const listingLinkParams = { id: listing.id.uuid, slug: createSlug(listing.attributes.title) };
+ const listingLink = (
+
+ {listing.attributes.title}
+
+ );
+
+ const title = orderState === propTypes.TX_STATE_PREAUTHORIZED
+ ?
+ : null;
+
+ const message = orderState === propTypes.TX_STATE_PREAUTHORIZED
+ ?
+ : null;
+
+ // TODO We can't use price from listing, since that might have changed.
+ // When API includes unit price and possible additional fees, we need to change this.
+ const unitPrice = listing.attributes.price;
+
+ const bookingInfo = unitPrice
+ ?
+ : {'priceRequiredMessage'}
;
+
return (
-

-
{title}
-
-
Confirmation code {confirmationCode}
-
Cancel booking
-
- You have a new message!
-
+
{title}
+ {message}
+ {bookingInfo}
);
};
OrderDetailsPanel.defaultProps = { className: null };
+const { instanceOf, string } = PropTypes;
+
OrderDetailsPanel.propTypes = {
className: string,
- orderId: oneOfType([string, number]).isRequired,
- title: string.isRequired,
- imageUrl: string.isRequired,
- contact: object.isRequired,
- confirmationCode: string.isRequired,
+ totalPrice: instanceOf(types.Money).isRequired,
+ orderState: string.isRequired,
+ booking: propTypes.booking.isRequired,
+ listing: propTypes.listing.isRequired,
+ provider: propTypes.user.isRequired,
};
export default OrderDetailsPanel;
diff --git a/src/components/OrderDetailsPanel/OrderDetailsPanel.test.js b/src/components/OrderDetailsPanel/OrderDetailsPanel.test.js
index ee0ae9e4..46a1300f 100644
--- a/src/components/OrderDetailsPanel/OrderDetailsPanel.test.js
+++ b/src/components/OrderDetailsPanel/OrderDetailsPanel.test.js
@@ -1,25 +1,23 @@
import React from 'react';
+import { types } from '../../util/sdkLoader';
+import { createBooking, createListing, createUser } from '../../util/test-data';
import { renderShallow } from '../../util/test-helpers';
import OrderDetailsPanel from './OrderDetailsPanel.js';
describe('OrderDetailsPanel', () => {
it('matches snapshot', () => {
+ const { Money } = types;
const props = {
- orderId: 'some-test-order-id',
- title: 'Test order',
- imageUrl: 'http://example.com/img',
- info: {
- pricePerDay: '10$',
- bookingPeriod: 'some booking period',
- bookingDuration: 'some booking duration',
- total: '100$',
- },
- contact: {
- addressLine1: 'Some road 1',
- addressLine2: 'Some city, somewhere',
- phoneNumber: 'Some phone number',
- },
- confirmationCode: 'some-test-confirmation-code',
+ commission: null,
+ totalPrice: new Money(16500, 'USD'),
+ orderState: 'state/preauthorized',
+ booking: createBooking(
+ 'booking1',
+ new Date(Date.UTC(2017, 5, 10)),
+ new Date(Date.UTC(2017, 5, 13))
+ ),
+ listing: createListing('listing1'),
+ provider: createUser('provider'),
};
const tree = renderShallow();
expect(tree).toMatchSnapshot();
diff --git a/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap b/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap
index ccbf920c..bcac3fb9 100644
--- a/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap
+++ b/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap
@@ -1,36 +1,45 @@
exports[`OrderDetailsPanel matches snapshot 1`] = `
-

+
+
+
+
-
- Test order
-
-
-
- Confirmation code
- some-test-confirmation-code
-
-
- Cancel booking
-
-
- You have a new message!
-
`;
diff --git a/src/components/index.js b/src/components/index.js
index ad6dab7b..7f4b322b 100644
--- a/src/components/index.js
+++ b/src/components/index.js
@@ -1,5 +1,6 @@
import AddImages from './AddImages/AddImages';
import AuthorInfo from './AuthorInfo/AuthorInfo';
+import Avatar from './Avatar/Avatar';
import BookingInfo from './BookingInfo/BookingInfo';
import Button from './Button/Button';
import CurrencyInput from './CurrencyInput/CurrencyInput';
@@ -31,6 +32,7 @@ import StripeBankAccountToken from './StripeBankAccountToken/StripeBankAccountTo
export {
AddImages,
AuthorInfo,
+ Avatar,
BookingInfo,
Button,
CurrencyInput,
diff --git a/src/translations/en.json b/src/translations/en.json
index e1919915..cbc36530 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -12,8 +12,9 @@
"BookingDatesForm.youWontBeChargedInfo": "You won't be charged yet",
"BookingInfo.bookingPeriod": "{bookingStart} - {bookingEnd}",
"BookingInfo.bookingPeriodLabel": "Booking period:",
- "BookingInfo.nightCount": "{count, number} {count, plural, one {day} other {days}}",
- "BookingInfo.pricePerDay":"Price per day:",
+ "BookingInfo.commission": "Charged commission:",
+ "BookingInfo.nightCount": "{count, number} {count, plural, one {night} other {nights}}",
+ "BookingInfo.pricePerDay":"Price per night:",
"BookingInfo.total": "Total:",
"CheckoutPage.initiateOrderError": "Payment request failed. Please try again.",
"CheckoutPage.paymentInfo": "You'll only be charged if your request is accepted by the provider.",
@@ -54,6 +55,8 @@
"ListingPage.loadingListingData": "Loading listing data",
"ListingPage.noListingData": "Could not find listing data",
"ModalInMobile.closeModal": "Close modal",
+ "OrderDetailsPanel.listingTitle": "You have requested to book {title}",
+ "OrderDetailsPanel.orderStatusMessage": "{providerName} has been notified about the booking request, so sit back and relax",
"PageLayout.authInfoFailed": "Could not get authentication information.",
"PageLayout.logoutFailed": "Logout failed. Please try again.",
"PaginationLinks.previous": "Previous page",
diff --git a/src/util/propTypes.js b/src/util/propTypes.js
index 2ea7a658..acff214c 100644
--- a/src/util/propTypes.js
+++ b/src/util/propTypes.js
@@ -118,6 +118,16 @@ export const listing = shape({
images: arrayOf(image),
});
+// Denormalised booking object
+export const booking = shape({
+ id: uuid.isRequired,
+ type: value('booking').isRequired,
+ attributes: shape({
+ end: instanceOf(Date).isRequired,
+ start: instanceOf(Date).isRequired,
+ }),
+});
+
export const TX_STATE_ACCEPTED = 'state/accepted';
export const TX_STATE_REJECTED = 'state/rejected';
export const TX_STATE_PREAUTHORIZED = 'state/preauthorized';
@@ -135,6 +145,8 @@ export const transaction = shape({
state: oneOf(TX_STATES).isRequired,
total: any, // ???
}),
+ booking,
+ listing,
customer: user,
provider: user,
});
diff --git a/src/util/test-data.js b/src/util/test-data.js
index 8dacf15e..31bf44c2 100644
--- a/src/util/test-data.js
+++ b/src/util/test-data.js
@@ -2,6 +2,16 @@ import { types } from './sdkLoader';
const { UUID, LatLng, Money } = types;
+// Create a booking that conforms to the util/propTypes booking schema
+export const createBooking = (id, startDateInUTC, endDateInUTC) => ({
+ id: new UUID(id),
+ type: 'booking',
+ attributes: {
+ start: startDateInUTC,
+ end: endDateInUTC,
+ },
+});
+
// Create a user that conforms to the util/propTypes user schema
export const createUser = id => ({
id: new UUID(id),
@@ -62,6 +72,9 @@ export const createTransaction = options => {
const {
id,
state = 'state/preauthorized',
+ total = new Money(1000, 'USD'),
+ booking = null,
+ listing = null,
customer = null,
provider = null,
lastTransitionedAt = new Date(Date.UTC(2017, 5, 1)),
@@ -74,8 +87,10 @@ export const createTransaction = options => {
createdAt: new Date(Date.UTC(2017, 4, 1)),
lastTransitionedAt,
state,
- total: null,
+ total,
},
+ booking,
+ listing,
customer,
provider,
};