diff --git a/src/components/BookingBreakdown/BookingBreakdown.css b/src/components/BookingBreakdown/BookingBreakdown.css index f15fbf59..0d199214 100644 --- a/src/components/BookingBreakdown/BookingBreakdown.css +++ b/src/components/BookingBreakdown/BookingBreakdown.css @@ -37,7 +37,7 @@ @media (--viewportMedium) { font-weight: 700; - margin-top: 1px; /* align with baseline */ + margin-top: -1px; margin-bottom: 0; } } @@ -52,7 +52,7 @@ background-color: var(--matterColorNegative); @media (--viewportMedium) { - margin: 2px 0 8px 0; + margin: 2px 0 14px 0; } } @@ -61,6 +61,10 @@ /* Move so that baseline aligns with the total price */ padding-top: 7px; + + @media (--viewportMedium) { + padding-top: 8px; + } } .totalPrice { diff --git a/src/components/OrderDetailsPanel/OrderDetailsPanel.css b/src/components/OrderDetailsPanel/OrderDetailsPanel.css index 8460c0be..80e78123 100644 --- a/src/components/OrderDetailsPanel/OrderDetailsPanel.css +++ b/src/components/OrderDetailsPanel/OrderDetailsPanel.css @@ -4,8 +4,75 @@ } +.container { + position: relative; + display: flex; + flex-direction: column; + + @media (--viewportMedium) { + flex-direction: row; + justify-content: center; + } +} + +/* Firefox doesn't support image aspect ratio inside flexbox */ +.aspectWrapper { + padding-bottom: 66.6667%; /* 3:2 Aspect Ratio */ + background-color: var(--matterColorNegative); /* Loading BG color */ + + @media (--viewportMedium) { + display: none; + } +} + +.breakdownAspectWrapper { + position: relative; + padding-bottom: 66.6667%; /* 3:2 Aspect Ratio */ + background-color: var(--matterColorNegative); /* Loading BG color */ +} + +.rootForImage { + /* Layout - image will take space defined by aspect ratio wrapper */ + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; +} + +.avatarWrapper { + /* Position (over the listing image)*/ + margin-left: 24px; + margin-top: -31px; + + /* Rendering context to the same lavel as listing image */ + position: relative; + + /* Layout */ + display: block; + width: 61px; + height: 61px; +} + +.avatarMobile { + @media (--viewportMedium) { + display: none; + } +} + +.orderInfo { + @media (--viewportMedium) { + max-width: 517px; + } +} + .title { margin: 28px 24px 0 24px; + + @media (--viewportMedium) { + margin-top: 177px; + } } .mainTitle { @@ -20,15 +87,76 @@ .message { display: flex; margin: 24px 24px 47px 24px; + + @media (--viewportMedium) { + margin-top: 27px; + } } .transitionDate { white-space: nowrap; } +.breakdownMobile { + @media (--viewportMedium) { + display: none; + } +} + +.breakdownDesktop { + display: none; + + @media (--viewportMedium) { + display: block; + padding-bottom: 55px; + } +} + .bookingBreakdownContainer { - margin-bottom: 40px; - padding: 0 24px; + margin: 1px 0 40px 0; + + @media (--viewportMedium) { + width: 409px; + margin-top: 122px; + margin-left: 24px; + margin-right: 24px; + box-shadow: var(--boxShadowBreakdown); + } + @media (--viewportLarge) { + margin-left: 131px; + } +} + +.breakdownHeadings { + display: none; + + @media (--viewportMedium) { + display: block; + margin-left: 24px; + margin-right: 24px; + } +} + +.breakdownTitle { + margin-bottom: 10px; + + @media (--viewportMedium) { + margin-top: 13px; + margin-bottom: 0; + } +} + +.breakdownSubtitle { + @apply --marketplaceH5FontStyles; + color: var(--matterColorAnti); + + margin-top: 0; + margin-bottom: 0; + + @media (--viewportMedium) { + margin-top: 0; + margin-bottom: 0; + } } .bookingBreakdownTitle { @@ -37,11 +165,16 @@ margin-top: 5px; margin-bottom: 14px; + margin-left: 24px; + margin-right: 24px; + @media (--viewportMedium) { - margin-top: 5px; - margin-bottom: 14px; + margin-top: 38px; + margin-bottom: 10px; } } .receipt { + margin-left: 24px; + margin-right: 24px; } diff --git a/src/components/OrderDetailsPanel/OrderDetailsPanel.js b/src/components/OrderDetailsPanel/OrderDetailsPanel.js index 898aa691..ff480c79 100644 --- a/src/components/OrderDetailsPanel/OrderDetailsPanel.js +++ b/src/components/OrderDetailsPanel/OrderDetailsPanel.js @@ -4,7 +4,7 @@ import classNames from 'classnames'; import * as propTypes from '../../util/propTypes'; import { createSlug } from '../../util/urlHelpers'; import { ensureListing, ensureTransaction, ensureBooking, ensureUser } from '../../util/data'; -import { BookingBreakdown, NamedLink } from '../../components'; +import { BookingBreakdown, NamedLink, ResponsiveImage, AvatarMedium } from '../../components'; import css from './OrderDetailsPanel.css'; @@ -131,7 +131,9 @@ const OrderDetailsPanel = props => { const currentProvider = ensureUser(currentTransaction.provider); const currentCustomer = ensureUser(currentTransaction.customer); - const providerName = currentProvider.attributes.profile.firstName; + const providerProfile = currentProvider.attributes.profile; + const authorFirstName = providerProfile.firstName; + const authorLastName = providerProfile.lastName; const customerName = currentCustomer.attributes.profile.firstName; const transactionState = currentTransaction.attributes.state; const lastTransitionedAt = currentTransaction.attributes.lastTransitionedAt; @@ -149,29 +151,86 @@ const OrderDetailsPanel = props => { ); } + const listingTitle = currentListing.attributes.title; + const bookingInfo = breakdown(currentTransaction); const title = orderTitle(transactionState, listingLink, customerName, lastTransition); const message = orderMessage( transactionState, listingLink, - providerName, + authorFirstName, lastTransitionedAt, lastTransition ); + const firstImage = currentListing.images && currentListing.images.length > 0 + ? currentListing.images[0] + : null; + const classes = classNames(rootClassName || css.root, className); return (
-

{title}

-
- {message} -
-
-

- -

- {bookingInfo} +
+
+ +
+
+ +
+
+

{title}

+
+ {message} +
+
+
+
+

+ +

+ {bookingInfo} +
+
+
+ +
+
+ +
+
+

{listingTitle}

+

+ +

+
+

+ +

+ {bookingInfo} +
+
); diff --git a/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap b/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap index 4c436fbb..9e88ce72 100644 --- a/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap +++ b/src/components/OrderDetailsPanel/__snapshots__/OrderDetailsPanel.test.js.snap @@ -1,87 +1,202 @@ exports[`OrderDetailsPanel matches snapshot 1`] = `
-

- - +
+
+ +
+
+ +
+
+

+ + + + + + listing1 title + , + } + } /> + +

+
- - - listing1 title - , +
+
+
+
+

+ +

+ - -

-
- -
-
-

- -

- +
+
+
+ +
+
+ +
+
+

+ listing1 title +

+

+ +

+
+

+ +

+ + } + } + userRole="customer" /> +
+
`; diff --git a/src/containers/OrderPage/OrderPage.duck.js b/src/containers/OrderPage/OrderPage.duck.js index 875f8745..4eaf7ae7 100644 --- a/src/containers/OrderPage/OrderPage.duck.js +++ b/src/containers/OrderPage/OrderPage.duck.js @@ -41,15 +41,29 @@ const fetchOrderError = e => ({ type: FETCH_ORDER_ERROR, error: true, payload: e // ================ Thunks ================ // +const listingRelationship = txResponse => { + return txResponse.data.data.relationships.listing.data; +}; + export const fetchOrder = id => (dispatch, getState, sdk) => { dispatch(fetchOrderRequest()); + let txResponse = null; + return sdk.transactions .show({ id, include: ['customer', 'provider', 'listing', 'booking'] }, { expand: true }) .then(response => { + txResponse = response; + const listingId = listingRelationship(response).id; + + return sdk.listings.show({ id: listingId, include: ['author', 'images'] }); + }) + .then(response => { + dispatch(addMarketplaceEntities(txResponse)); dispatch(addMarketplaceEntities(response)); - dispatch(fetchOrderSuccess(response)); + dispatch(fetchOrderSuccess(txResponse)); + return response; }) .catch(e => { diff --git a/src/marketplace.css b/src/marketplace.css index 6a9149a6..dad0e3ec 100644 --- a/src/marketplace.css +++ b/src/marketplace.css @@ -60,6 +60,7 @@ --boxShadowLight: 0 2px 4px 0 rgba(0, 0, 0, 0.05); --boxShadowPopup: 0 8px 16px 0 rgba(0, 0, 0, 0.3); --boxShadowPopupLight: 0 3px 6px 0 rgba(0, 0, 0, 0.2); + --boxShadowBreakdown: 0 3px 6px 0 rgba(0, 0, 0, 0.2); --boxShadowButton: 0 4px 8px 0 rgba(0, 0, 0, 0.10); --boxShadowListingCard: 0 0 50px 0 rgba(0,0,0,0.1); diff --git a/src/translations/en.json b/src/translations/en.json index 0b40f4b1..f3b1170d 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -131,6 +131,7 @@ "OrderDetailsPanel.orderPreauthorizedTitle": "Great success, {customerName}!", "OrderDetailsPanel.orderRejectedStatus": "Unfortunately {providerName} declined the request on {transitionDate}.", "OrderDetailsPanel.orderRejectedTitle": "You requested to book {listingLink}", + "OrderDetailsPanel.hostedBy": "Hosted by {name}", "OrderPage.fetchOrderFailed": "Fetching order data failed.", "OrderPage.loadingData": "Loading order data.", "OrderPage.title": "Order details: {listingTitle}",