mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-31 02:26:50 +10:00
Merge pull request #325 from sharetribe/order-page-responsive-styles
Responsive Order page
This commit is contained in:
commit
b1003a62b0
7 changed files with 418 additions and 91 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div className={classes}>
|
||||
<h1 className={css.title}>{title}</h1>
|
||||
<div className={css.message}>
|
||||
{message}
|
||||
</div>
|
||||
<div className={css.bookingBreakdownContainer}>
|
||||
<h3 className={css.bookingBreakdownTitle}>
|
||||
<FormattedMessage id="OrderDetailsPanel.bookingBreakdownTitle" />
|
||||
</h3>
|
||||
{bookingInfo}
|
||||
<div className={css.container}>
|
||||
<div className={css.aspectWrapper}>
|
||||
<ResponsiveImage
|
||||
rootClassName={css.rootForImage}
|
||||
alt={listingTitle}
|
||||
image={firstImage}
|
||||
nameSet={[
|
||||
{ name: 'landscape-crop', size: '400w' },
|
||||
{ name: 'landscape-crop2x', size: '800w' },
|
||||
]}
|
||||
sizes="100vw"
|
||||
/>
|
||||
</div>
|
||||
<div className={classNames(css.avatarWrapper, css.avatarMobile)}>
|
||||
<AvatarMedium firstName={authorFirstName} lastName={authorLastName} />
|
||||
</div>
|
||||
<div className={css.orderInfo}>
|
||||
<h1 className={css.title}>{title}</h1>
|
||||
<div className={css.message}>
|
||||
{message}
|
||||
</div>
|
||||
</div>
|
||||
<div className={css.bookingBreakdownContainer}>
|
||||
<div className={css.breakdownMobile}>
|
||||
<h3 className={css.bookingBreakdownTitle}>
|
||||
<FormattedMessage id="OrderDetailsPanel.bookingBreakdownTitle" />
|
||||
</h3>
|
||||
{bookingInfo}
|
||||
</div>
|
||||
<div className={css.breakdownDesktop}>
|
||||
<div className={css.breakdownAspectWrapper}>
|
||||
<ResponsiveImage
|
||||
rootClassName={css.rootForImage}
|
||||
alt={listingTitle}
|
||||
image={firstImage}
|
||||
nameSet={[
|
||||
{ name: 'landscape-crop', size: '400w' },
|
||||
{ name: 'landscape-crop2x', size: '800w' },
|
||||
]}
|
||||
sizes="100%"
|
||||
/>
|
||||
</div>
|
||||
<div className={css.avatarWrapper}>
|
||||
<AvatarMedium firstName={authorFirstName} lastName={authorLastName} />
|
||||
</div>
|
||||
<div className={css.breakdownHeadings}>
|
||||
<h2 className={css.breakdownTitle}>{listingTitle}</h2>
|
||||
<p className={css.breakdownSubtitle}>
|
||||
<FormattedMessage
|
||||
id="OrderDetailsPanel.hostedBy"
|
||||
values={{ name: authorFirstName }}
|
||||
/>
|
||||
</p>
|
||||
</div>
|
||||
<h3 className={css.bookingBreakdownTitle}>
|
||||
<FormattedMessage id="OrderDetailsPanel.bookingBreakdownTitle" />
|
||||
</h3>
|
||||
{bookingInfo}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,87 +1,202 @@
|
|||
exports[`OrderDetailsPanel matches snapshot 1`] = `
|
||||
<div
|
||||
className="">
|
||||
<h1>
|
||||
<span>
|
||||
<span>
|
||||
<div>
|
||||
<div>
|
||||
<ResponsiveImage
|
||||
alt="listing1 title"
|
||||
className={null}
|
||||
image={null}
|
||||
nameSet={
|
||||
Array [
|
||||
Object {
|
||||
"name": "landscape-crop",
|
||||
"size": "400w",
|
||||
},
|
||||
Object {
|
||||
"name": "landscape-crop2x",
|
||||
"size": "800w",
|
||||
},
|
||||
]
|
||||
}
|
||||
rootClassName={null}
|
||||
sizes="100vw" />
|
||||
</div>
|
||||
<div
|
||||
className="">
|
||||
<AvatarMedium
|
||||
firstName="provider first name"
|
||||
lastName="provider last name" />
|
||||
</div>
|
||||
<div>
|
||||
<h1>
|
||||
<span>
|
||||
<span>
|
||||
<FormattedMessage
|
||||
id="OrderDetailsPanel.orderPreauthorizedTitle"
|
||||
values={
|
||||
Object {
|
||||
"customerName": "customer first name",
|
||||
}
|
||||
} />
|
||||
</span>
|
||||
<FormattedMessage
|
||||
id="OrderDetailsPanel.orderPreauthorizedSubtitle"
|
||||
values={
|
||||
Object {
|
||||
"listingLink": <withFlattenedRoutes(withRouter(NamedLink))
|
||||
name="ListingPage"
|
||||
params={
|
||||
Object {
|
||||
"id": "listing1",
|
||||
"slug": "listing1-title",
|
||||
}
|
||||
}>
|
||||
listing1 title
|
||||
</withFlattenedRoutes(withRouter(NamedLink))>,
|
||||
}
|
||||
} />
|
||||
</span>
|
||||
</h1>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id="OrderDetailsPanel.orderPreauthorizedTitle"
|
||||
id="OrderDetailsPanel.orderPreauthorizedStatus"
|
||||
values={
|
||||
Object {
|
||||
"customerName": "customer first name",
|
||||
"providerName": "provider first name",
|
||||
}
|
||||
} />
|
||||
</span>
|
||||
<FormattedMessage
|
||||
id="OrderDetailsPanel.orderPreauthorizedSubtitle"
|
||||
values={
|
||||
Object {
|
||||
"listingLink": <withFlattenedRoutes(withRouter(NamedLink))
|
||||
name="ListingPage"
|
||||
params={
|
||||
Object {
|
||||
"id": "listing1",
|
||||
"slug": "listing1-title",
|
||||
}
|
||||
}>
|
||||
listing1 title
|
||||
</withFlattenedRoutes(withRouter(NamedLink))>,
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="OrderDetailsPanel.bookingBreakdownTitle"
|
||||
values={Object {}} />
|
||||
</h3>
|
||||
<BookingBreakdown
|
||||
bookingEnd={2017-06-13T00:00:00.000Z}
|
||||
bookingStart={2017-06-10T00:00:00.000Z}
|
||||
lineItems={
|
||||
Array [
|
||||
Object {
|
||||
"code": "line-item/night",
|
||||
"lineTotal": Money {
|
||||
"amount": 16500,
|
||||
"currency": "USD",
|
||||
},
|
||||
"quantity": "3",
|
||||
"unitPrice": Money {
|
||||
"amount": 5500,
|
||||
"currency": "USD",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"code": "line-item/provider-commission",
|
||||
"lineTotal": Money {
|
||||
"amount": -100,
|
||||
"currency": "USD",
|
||||
},
|
||||
"unitPrice": Money {
|
||||
"amount": -100,
|
||||
"currency": "USD",
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
} />
|
||||
</span>
|
||||
</h1>
|
||||
<div>
|
||||
<FormattedMessage
|
||||
id="OrderDetailsPanel.orderPreauthorizedStatus"
|
||||
values={
|
||||
Object {
|
||||
"providerName": "provider first name",
|
||||
}
|
||||
} />
|
||||
</div>
|
||||
<div>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="OrderDetailsPanel.bookingBreakdownTitle"
|
||||
values={Object {}} />
|
||||
</h3>
|
||||
<BookingBreakdown
|
||||
bookingEnd={2017-06-13T00:00:00.000Z}
|
||||
bookingStart={2017-06-10T00:00:00.000Z}
|
||||
lineItems={
|
||||
Array [
|
||||
Object {
|
||||
"code": "line-item/night",
|
||||
"lineTotal": Money {
|
||||
payinTotal={
|
||||
Money {
|
||||
"amount": 16500,
|
||||
"currency": "USD",
|
||||
},
|
||||
"quantity": "3",
|
||||
"unitPrice": Money {
|
||||
"amount": 5500,
|
||||
}
|
||||
}
|
||||
userRole="customer" />
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<ResponsiveImage
|
||||
alt="listing1 title"
|
||||
className={null}
|
||||
image={null}
|
||||
nameSet={
|
||||
Array [
|
||||
Object {
|
||||
"name": "landscape-crop",
|
||||
"size": "400w",
|
||||
},
|
||||
Object {
|
||||
"name": "landscape-crop2x",
|
||||
"size": "800w",
|
||||
},
|
||||
]
|
||||
}
|
||||
rootClassName={null}
|
||||
sizes="100%" />
|
||||
</div>
|
||||
<div>
|
||||
<AvatarMedium
|
||||
firstName="provider first name"
|
||||
lastName="provider last name" />
|
||||
</div>
|
||||
<div>
|
||||
<h2>
|
||||
listing1 title
|
||||
</h2>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="OrderDetailsPanel.hostedBy"
|
||||
values={
|
||||
Object {
|
||||
"name": "provider first name",
|
||||
}
|
||||
} />
|
||||
</p>
|
||||
</div>
|
||||
<h3>
|
||||
<FormattedMessage
|
||||
id="OrderDetailsPanel.bookingBreakdownTitle"
|
||||
values={Object {}} />
|
||||
</h3>
|
||||
<BookingBreakdown
|
||||
bookingEnd={2017-06-13T00:00:00.000Z}
|
||||
bookingStart={2017-06-10T00:00:00.000Z}
|
||||
lineItems={
|
||||
Array [
|
||||
Object {
|
||||
"code": "line-item/night",
|
||||
"lineTotal": Money {
|
||||
"amount": 16500,
|
||||
"currency": "USD",
|
||||
},
|
||||
"quantity": "3",
|
||||
"unitPrice": Money {
|
||||
"amount": 5500,
|
||||
"currency": "USD",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"code": "line-item/provider-commission",
|
||||
"lineTotal": Money {
|
||||
"amount": -100,
|
||||
"currency": "USD",
|
||||
},
|
||||
"unitPrice": Money {
|
||||
"amount": -100,
|
||||
"currency": "USD",
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
payinTotal={
|
||||
Money {
|
||||
"amount": 16500,
|
||||
"currency": "USD",
|
||||
},
|
||||
},
|
||||
Object {
|
||||
"code": "line-item/provider-commission",
|
||||
"lineTotal": Money {
|
||||
"amount": -100,
|
||||
"currency": "USD",
|
||||
},
|
||||
"unitPrice": Money {
|
||||
"amount": -100,
|
||||
"currency": "USD",
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
payinTotal={
|
||||
Money {
|
||||
"amount": 16500,
|
||||
"currency": "USD",
|
||||
}
|
||||
}
|
||||
userRole="customer" />
|
||||
}
|
||||
}
|
||||
userRole="customer" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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}",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue