Use ModalInMobile in ListingPage

This commit is contained in:
Vesa Luusua 2017-04-04 17:42:33 +03:00
parent 8cf00d218c
commit 7ada8024de
5 changed files with 135 additions and 68 deletions

View file

@ -1,7 +1,27 @@
.pageRoot {}
.listing {
display: block;
}
.listing {
padding-bottom: 80px;
}
.header {
display: flex;
flex-direction: row;
padding: 1rem;
}
.title,
.price {
font-size: 2em;
margin: 0.67em 0;
float: right;
}
.title {
flex-grow: 1;
}
.mainImage {
@ -44,27 +64,25 @@
margin-top: 3rem;
height: 300px;
width: 100%;
}
.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;
}
}
.openDatePickerForm {
position: fixed;
bottom: 0;
left: 0;
width: 100vw;
height: 80px;
padding: 1rem;
background-color: white;
border-top: solid 1px #ccc;
/* Mobile frame fix */
max-width: 375px;
left: 50%;
transform: translateX(-50%);
}
.bookingModalTitle {
margin: 1rem 0;
}

View file

@ -4,11 +4,14 @@ import { connect } from 'react-redux';
import config from '../../config';
import { types } from '../../util/sdkLoader';
import { convertMoneyToNumber } from '../../util/currency';
import { NamedLink, PageLayout, Map } from '../../components';
import { Button, Map, ModalInMobile, PageLayout } from '../../components';
import { getListingsById } from '../../ducks/sdk.duck';
import { showListing } from './ListingPage.duck';
import css from './ListingPage.css';
// This defines when ModalInMobile shows content as Modal
const MODAL_BREAKPOINT = 2500;
const { UUID } = types;
const priceData = (price, currencyConfig, intl) => {
@ -28,6 +31,14 @@ const priceData = (price, currencyConfig, intl) => {
// TODO: price unit (per x), custom fields, contact, reviews
// N.B. All the presentational content needs to be extracted to their own components
export class ListingPageComponent extends Component {
constructor(props) {
super(props);
const tab = props.tab;
this.state = {
isBookingModalOpenOnMobile: tab && tab === 'book',
};
}
render() {
const { params, marketplaceData, showListingError, intl } = this.props;
const currencyConfig = config.currencyConfig;
@ -44,6 +55,7 @@ export class ListingPageComponent extends Component {
title = '',
} = attributes;
const bookBtnMessage = intl.formatMessage({ id: 'ListingPage.ctaButtonMessage' }, { title });
const { formattedPrice, priceTitle } = priceData(price, currencyConfig, intl);
const map = geolocation ? <Map center={geolocation} address={address} /> : null;
@ -73,17 +85,31 @@ export class ListingPageComponent extends Component {
: null;
const pageContent = (
<PageLayout title={`${title} ${formattedPrice}`}>
<div className={css.price} title={priceTitle}>{formattedPrice}</div>
<h1>{title}</h1>
{imageCarousel}
{/* eslint-disable react/no-danger */}
<div className={css.description} dangerouslySetInnerHTML={{ __html: description }} />
{/* eslint-enable react/no-danger */}
{map ? <div className={css.map}>{map}</div> : null}
<NamedLink className={css.buttonLink} name="OrderDetailsPage" params={{ id: 12345 }}>
{`Book ${title}`}
</NamedLink>
<PageLayout title={`${title} ${formattedPrice}`} className={this.state.rootClasses}>
<div className={css.listing}>
<div className={css.header}>
<h1 className={css.title}>{title}</h1>
<div className={css.price} title={priceTitle}>{formattedPrice}</div>
</div>
{imageCarousel}
{/* eslint-disable react/no-danger */}
<div className={css.description} dangerouslySetInnerHTML={{ __html: description }} />
{/* eslint-enable react/no-danger */}
<ModalInMobile
isModalOpenOnMobile={this.state.isBookingModalOpenOnMobile}
onClose={() => this.setState({ isBookingModalOpenOnMobile: false })}
showAsModalMaxWidth={MODAL_BREAKPOINT}
title={bookBtnMessage}
>
<span>ModalInMobile content</span>
</ModalInMobile>
{map ? <div className={css.map}>{map}</div> : null}
<div className={css.openDatePickerForm}>
<Button onClick={() => this.setState({ isBookingModalOpenOnMobile: true })}>
{bookBtnMessage}
</Button>
</div>
</div>
</PageLayout>
);
@ -98,9 +124,12 @@ export class ListingPageComponent extends Component {
}
}
ListingPageComponent.defaultProps = { showListingError: null };
ListingPageComponent.defaultProps = {
showListingError: null,
tab: 'listing',
};
const { instanceOf, object, shape, string } = PropTypes;
const { instanceOf, object, oneOf, shape, string } = PropTypes;
ListingPageComponent.propTypes = {
intl: intlShape.isRequired,
@ -110,6 +139,7 @@ ListingPageComponent.propTypes = {
slug: string.isRequired,
}).isRequired,
showListingError: instanceOf(Error),
tab: oneOf(['book', 'listing']),
};
const mapStateToProps = state => ({

View file

@ -1,39 +1,50 @@
exports[`ListingPage matches snapshot 1`] = `
<Connect(withRouter(PageLayout))
title="listing1 title 55">
<div
title={55}>
55
</div>
<h1>
listing1 title
</h1>
<div
dangerouslySetInnerHTML={
Object {
"__html": "listing1 description",
}
} />
<div>
<Map
address="listing1 address"
center={
LatLng {
"lat": 40,
"lng": 60,
<div>
<h1>
listing1 title
</h1>
<div
title={55}>
55
</div>
</div>
<div
dangerouslySetInnerHTML={
Object {
"__html": "listing1 description",
}
}
className=""
zoom={11} />
} />
<withTogglePageClassNames(InjectIntl(ModalInMobileComponent))
isModalOpenOnMobile={false}
onClose={[Function]}
showAsModalMaxWidth={2500}
title="ListingPage.ctaButtonMessage">
<span>
ModalInMobile content
</span>
</withTogglePageClassNames(InjectIntl(ModalInMobileComponent))>
<div>
<Map
address="listing1 address"
center={
LatLng {
"lat": 40,
"lng": 60,
}
}
className=""
zoom={11} />
</div>
<div>
<Button
className={null}
onClick={[Function]}>
ListingPage.ctaButtonMessage
</Button>
</div>
</div>
<withFlattenedRoutes(withRouter(NamedLink))
name="OrderDetailsPage"
params={
Object {
"id": 12345,
}
}>
Book listing1 title
</withFlattenedRoutes(withRouter(NamedLink))>
</Connect(withRouter(PageLayout))>
`;

View file

@ -66,7 +66,14 @@ const routesConfiguration = [
exact: true,
name: 'ListingPage',
loadData: (params, search) => ListingPage.loadData(params, search),
component: props => <ListingPage {...props} />,
component: props => <ListingPage {...props} tab="listing" />,
},
{
path: '/l/:slug/:id/book',
exact: true,
name: 'ListingPage',
loadData: (params, search) => ListingPage.loadData(params, search),
component: props => <ListingPage {...props} tab="book" />,
},
{
auth: true,

View file

@ -17,6 +17,7 @@
"HeroSection.subTitle": "The largest online community to rent music studios",
"HeroSection.title": "Book Studiotime anywhere",
"ModalInMobile.closeModal": "Close modal",
"ListingPage.ctaButtonMessage": "Book {title}",
"ListingPage.loadingListingData": "Loading listing data",
"ListingPage.noListingData": "Could not find listing data",
"PageLayout.authInfoFailed": "Could not get authentication information.",