mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 20:53:24 +10:00
Use ModalInMobile in ListingPage
This commit is contained in:
parent
8cf00d218c
commit
7ada8024de
5 changed files with 135 additions and 68 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 => ({
|
||||
|
|
|
|||
|
|
@ -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))>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue