Footer to ListingPage

This commit is contained in:
Vesa Luusua 2017-10-20 18:19:07 +03:00
parent 616b528f16
commit 2abe326516
3 changed files with 410 additions and 366 deletions

View file

@ -1,10 +1,10 @@
@import '../../marketplace.css';
.pageRoot {
display: block;
display: flex;
padding-bottom: 90px;
@media (--viewportLarge) {
padding-bottom: 24px;
padding-bottom: 0;
}
}
@ -393,6 +393,8 @@
}
.openBookingForm {
/* Ensure that mobile button is over Footer too */
z-index: 9;
position: fixed;
bottom: 0;
left: 0;

View file

@ -5,7 +5,6 @@ import { FormattedMessage, intlShape, injectIntl } from 'react-intl';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import classNames from 'classnames';
import config from '../../config';
import routeConfiguration from '../../routeConfiguration';
import * as propTypes from '../../util/propTypes';
@ -28,6 +27,11 @@ import {
NamedRedirect,
Modal,
ImageCarousel,
LayoutSingleColumn,
LayoutWrapperTopbar,
LayoutWrapperMain,
LayoutWrapperFooter,
Footer,
} from '../../components';
import { BookingDatesForm, TopbarContainer } from '../../containers';
@ -182,10 +186,17 @@ export class ListingPageComponent extends Component {
return (
<Page title={errorTitle}>
{topbar}
<p className={css.errorText}>
<FormattedMessage id="ListingPage.errorLoadingListingMessage" />
</p>
<LayoutSingleColumn className={css.pageRoot}>
<LayoutWrapperTopbar>{topbar}</LayoutWrapperTopbar>
<LayoutWrapperMain>
<p className={css.errorText}>
<FormattedMessage id="ListingPage.errorLoadingListingMessage" />
</p>
</LayoutWrapperMain>
<LayoutWrapperFooter>
<Footer />
</LayoutWrapperFooter>
</LayoutSingleColumn>
</Page>
);
} else if (!currentListing.id) {
@ -193,10 +204,17 @@ export class ListingPageComponent extends Component {
return (
<Page title={loadingTitle}>
{topbar}
<p className={css.loadingText}>
<FormattedMessage id="ListingPage.loadingListingMessage" />
</p>
<LayoutSingleColumn className={css.pageRoot}>
<LayoutWrapperTopbar>{topbar}</LayoutWrapperTopbar>
<LayoutWrapperMain>
<p className={css.loadingText}>
<FormattedMessage id="ListingPage.loadingListingMessage" />
</p>
</LayoutWrapperMain>
<LayoutWrapperFooter>
<Footer />
</LayoutWrapperFooter>
</LayoutSingleColumn>
</Page>
);
}
@ -275,8 +293,6 @@ export class ListingPageComponent extends Component {
const editParams = { id: listingId.uuid, slug: listingSlug, type: 'edit', tab: 'description' };
const listingClasses = classNames(css.pageRoot);
const handleBookButtonClick = () => {
const isClosed = currentListing.attributes.closed;
if (isOwnListing || isClosed) {
@ -343,130 +359,137 @@ export class ListingPageComponent extends Component {
image: schemaImages,
}}
>
{topbar}
<div className={listingClasses}>
<div className={css.threeToTwoWrapper}>
<div className={css.aspectWrapper} onClick={handleViewPhotosClick}>
{actionBar}
<ResponsiveImage
rootClassName={css.rootForImage}
alt={title}
image={firstImage}
nameSet={[
{ name: 'landscape-crop', size: '400w' },
{ name: 'landscape-crop2x', size: '800w' },
{ name: 'landscape-crop4x', size: '1600w' },
{ name: 'landscape-crop6x', size: '2400w' },
]}
sizes="100vw"
/>
{viewPhotosButton}
</div>
</div>
<Modal
id="ListingPage.imageCarousel"
scrollLayerClassName={css.carouselModalScrollLayer}
containerClassName={css.carouselModalContainer}
lightCloseButton
isOpen={this.state.imageCarouselOpen}
onClose={() => this.setState({ imageCarouselOpen: false })}
onManageDisableScrolling={onManageDisableScrolling}
>
<ImageCarousel images={currentListing.images} />
</Modal>
<div className={css.contentContainer}>
<div className={css.avatarWrapper}>
<AvatarLarge user={currentAuthor} className={css.avatarDesktop} />
<AvatarMedium user={currentAuthor} className={css.avatarMobile} />
</div>
<div className={css.mainContent}>
<div className={css.headingContainer}>
<div className={css.desktopPriceContainer}>
<div className={css.desktopPriceValue} title={priceTitle}>
{formattedPrice}
</div>
<div className={css.desktopPerNight}>
<FormattedMessage id="ListingPage.perNight" />
</div>
</div>
<div className={css.heading}>
<h1 className={css.title}>{title}</h1>
<div className={css.author}>
<span className={css.authorName}>
<FormattedMessage
id="ListingPage.hostedBy"
values={{ name: currentAuthorDisplayName }}
/>
</span>
</div>
<LayoutSingleColumn className={css.pageRoot}>
<LayoutWrapperTopbar>{topbar}</LayoutWrapperTopbar>
<LayoutWrapperMain>
<div>
<div className={css.threeToTwoWrapper}>
<div className={css.aspectWrapper} onClick={handleViewPhotosClick}>
{actionBar}
<ResponsiveImage
rootClassName={css.rootForImage}
alt={title}
image={firstImage}
nameSet={[
{ name: 'landscape-crop', size: '400w' },
{ name: 'landscape-crop2x', size: '800w' },
{ name: 'landscape-crop4x', size: '1600w' },
{ name: 'landscape-crop6x', size: '2400w' },
]}
sizes="100vw"
/>
{viewPhotosButton}
</div>
</div>
<Modal
id="ListingPage.imageCarousel"
scrollLayerClassName={css.carouselModalScrollLayer}
containerClassName={css.carouselModalContainer}
lightCloseButton
isOpen={this.state.imageCarouselOpen}
onClose={() => this.setState({ imageCarouselOpen: false })}
onManageDisableScrolling={onManageDisableScrolling}
>
<ImageCarousel images={currentListing.images} />
</Modal>
<div className={css.descriptionContainer}>
<h2 className={css.descriptionTitle}>
<FormattedMessage id="ListingPage.descriptionTitle" />
</h2>
<p className={css.description}>{description}</p>
</div>
<div className={css.contentContainer}>
<div className={css.avatarWrapper}>
<AvatarLarge user={currentAuthor} className={css.avatarDesktop} />
<AvatarMedium user={currentAuthor} className={css.avatarMobile} />
</div>
{map}
</div>
<div className={css.mainContent}>
<div className={css.headingContainer}>
<div className={css.desktopPriceContainer}>
<div className={css.desktopPriceValue} title={priceTitle}>
{formattedPrice}
</div>
<div className={css.desktopPerNight}>
<FormattedMessage id="ListingPage.perNight" />
</div>
</div>
<div className={css.heading}>
<h1 className={css.title}>{title}</h1>
<div className={css.author}>
<span className={css.authorName}>
<FormattedMessage
id="ListingPage.hostedBy"
values={{ name: currentAuthorDisplayName }}
/>
</span>
</div>
</div>
</div>
<ModalInMobile
className={css.modalInMobile}
containerClassName={css.modalContainer}
id="BookingDatesFormInModal"
isModalOpenOnMobile={this.state.isBookingModalOpenOnMobile}
onClose={() => this.setState({ isBookingModalOpenOnMobile: false })}
showAsModalMaxWidth={MODAL_BREAKPOINT}
onManageDisableScrolling={onManageDisableScrolling}
>
<div className={css.modalHeading}>
<h1 className={css.title}>{title}</h1>
<div className={css.author}>
<span className={css.authorName}>
<FormattedMessage
id="ListingPage.hostedBy"
values={{ name: currentAuthorDisplayName }}
<div className={css.descriptionContainer}>
<h2 className={css.descriptionTitle}>
<FormattedMessage id="ListingPage.descriptionTitle" />
</h2>
<p className={css.description}>{description}</p>
</div>
{map}
</div>
<ModalInMobile
className={css.modalInMobile}
containerClassName={css.modalContainer}
id="BookingDatesFormInModal"
isModalOpenOnMobile={this.state.isBookingModalOpenOnMobile}
onClose={() => this.setState({ isBookingModalOpenOnMobile: false })}
showAsModalMaxWidth={MODAL_BREAKPOINT}
onManageDisableScrolling={onManageDisableScrolling}
>
<div className={css.modalHeading}>
<h1 className={css.title}>{title}</h1>
<div className={css.author}>
<span className={css.authorName}>
<FormattedMessage
id="ListingPage.hostedBy"
values={{ name: currentAuthorDisplayName }}
/>
</span>
</div>
</div>
{bookingHeading}
{!currentListing.attributes.closed ? (
<BookingDatesForm
className={css.bookingForm}
onSubmit={handleBookingSubmit}
price={price}
isOwnListing={isOwnListing}
/>
</span>
) : null}
</ModalInMobile>
<div className={css.openBookingForm}>
<div className={css.priceContainer}>
<div className={css.priceValue} title={priceTitle}>
{formattedPrice}
</div>
<div className={css.perNight}>
<FormattedMessage id="ListingPage.perNight" />
</div>
</div>
{!currentListing.attributes.closed ? (
<Button rootClassName={css.bookButton} onClick={handleBookButtonClick}>
{bookBtnMessage}
</Button>
) : (
<div className={css.closedListingButton}>
<FormattedMessage id="ListingPage.closedListingButtonText" />
</div>
)}
</div>
</div>
{bookingHeading}
{!currentListing.attributes.closed ? (
<BookingDatesForm
className={css.bookingForm}
onSubmit={handleBookingSubmit}
price={price}
isOwnListing={isOwnListing}
/>
) : null}
</ModalInMobile>
<div className={css.openBookingForm}>
<div className={css.priceContainer}>
<div className={css.priceValue} title={priceTitle}>
{formattedPrice}
</div>
<div className={css.perNight}>
<FormattedMessage id="ListingPage.perNight" />
</div>
</div>
{!currentListing.attributes.closed ? (
<Button rootClassName={css.bookButton} onClick={handleBookButtonClick}>
{bookBtnMessage}
</Button>
) : (
<div className={css.closedListingButton}>
<FormattedMessage id="ListingPage.closedListingButtonText" />
</div>
)}
</div>
</div>
</div>
</LayoutWrapperMain>
<LayoutWrapperFooter>
<Footer />
</LayoutWrapperFooter>
</LayoutSingleColumn>
</Page>
);
}

View file

@ -22,254 +22,273 @@ exports[`ListingPage matches snapshot 1`] = `
title="ListingPage.schemaTitle"
twitterImages={Array []}
>
<withRouter(Connect(TopbarContainerComponent)) />
<div
className=""
<LayoutSingleColumn
className={null}
rootClassName={null}
>
<div>
<div
onClick={[Function]}
>
<div
onClick={[Function]}
>
<ActionBar
editParams={
Object {
"id": "listing1",
"slug": "listing1-title",
"tab": "description",
"type": "edit",
}
}
isClosed={false}
isOwnListing={false}
/>
</div>
<ResponsiveImage
alt="listing1 title"
className={null}
image={null}
nameSet={
Array [
Object {
"name": "landscape-crop",
"size": "400w",
},
Object {
"name": "landscape-crop2x",
"size": "800w",
},
Object {
"name": "landscape-crop4x",
"size": "1600w",
},
Object {
"name": "landscape-crop6x",
"size": "2400w",
},
]
}
noImageMessage={null}
rootClassName={null}
sizes="100vw"
/>
</div>
</div>
<InjectIntl(ModalComponent)
id="ListingPage.imageCarousel"
isOpen={false}
lightCloseButton={true}
onClose={[Function]}
onManageDisableScrolling={[Function]}
<LayoutWrapperTopbar
className={null}
rootClassName={null}
>
<withRouter(Connect(TopbarContainerComponent)) />
</LayoutWrapperTopbar>
<LayoutWrapperMain
className={null}
rootClassName={null}
>
<InjectIntl(ImageCarousel)
images={Array []}
/>
</InjectIntl(ModalComponent)>
<div>
<div>
<AvatarLarge
user={
Object {
"attributes": Object {
"banned": false,
"profile": Object {
"abbreviatedName": "user-1 abbreviated name",
"displayName": "user-1 display name",
},
},
"id": UUID {
"uuid": "user-1",
},
"type": "user",
}
}
/>
<AvatarMedium
user={
Object {
"attributes": Object {
"banned": false,
"profile": Object {
"abbreviatedName": "user-1 abbreviated name",
"displayName": "user-1 display name",
},
},
"id": UUID {
"uuid": "user-1",
},
"type": "user",
}
}
/>
</div>
<div>
<div>
<div>
<div
title={55}
>
55
</div>
<div>
<FormattedMessage
id="ListingPage.perNight"
values={Object {}}
/>
</div>
</div>
<div>
<h1>
listing1 title
</h1>
<div>
<span>
<FormattedMessage
id="ListingPage.hostedBy"
values={
Object {
"name": "user-1 display name",
}
}
/>
</span>
</div>
</div>
</div>
<div>
<h2>
<FormattedMessage
id="ListingPage.descriptionTitle"
values={Object {}}
/>
</h2>
<p>
listing1 description
</p>
</div>
<div>
<h2>
<FormattedMessage
id="ListingPage.locationTitle"
values={Object {}}
/>
</h2>
<div>
<Map
address="listing1 address"
center={
LatLng {
"lat": 40,
"lng": 60,
}
}
className=""
rootClassName={null}
zoom={11}
/>
</div>
</div>
</div>
<withViewport(ModalInMobileComponent)
id="BookingDatesFormInModal"
isModalOpenOnMobile={false}
onClose={[Function]}
onManageDisableScrolling={[Function]}
showAsModalMaxWidth={1023}
>
<div>
<h1>
listing1 title
</h1>
<div>
<span>
<FormattedMessage
id="ListingPage.hostedBy"
values={
Object {
"name": "user-1 display name",
}
}
/>
</span>
</div>
</div>
<div>
<h2>
<FormattedMessage
id="ListingPage.bookingTitle"
values={
Object {
"title": "listing1 title",
}
}
/>
</h2>
<div>
<FormattedMessage
id="ListingPage.bookingHelp"
values={Object {}}
/>
</div>
</div>
<BookingDatesForm
isOwnListing={false}
onSubmit={[Function]}
price={
Money {
"amount": 5500,
"currency": "USD",
}
}
/>
</withViewport(ModalInMobileComponent)>
<div>
<div>
<div
title={55}
onClick={[Function]}
>
55
</div>
<div>
<FormattedMessage
id="ListingPage.perNight"
values={Object {}}
<div
onClick={[Function]}
>
<ActionBar
editParams={
Object {
"id": "listing1",
"slug": "listing1-title",
"tab": "description",
"type": "edit",
}
}
isClosed={false}
isOwnListing={false}
/>
</div>
<ResponsiveImage
alt="listing1 title"
className={null}
image={null}
nameSet={
Array [
Object {
"name": "landscape-crop",
"size": "400w",
},
Object {
"name": "landscape-crop2x",
"size": "800w",
},
Object {
"name": "landscape-crop4x",
"size": "1600w",
},
Object {
"name": "landscape-crop6x",
"size": "2400w",
},
]
}
noImageMessage={null}
rootClassName={null}
sizes="100vw"
/>
</div>
</div>
<Button
className={null}
disabled={false}
inProgress={false}
onClick={[Function]}
ready={false}
rootClassName={null}
<InjectIntl(ModalComponent)
id="ListingPage.imageCarousel"
isOpen={false}
lightCloseButton={true}
onClose={[Function]}
onManageDisableScrolling={[Function]}
>
ListingPage.ctaButtonMessage
</Button>
<InjectIntl(ImageCarousel)
images={Array []}
/>
</InjectIntl(ModalComponent)>
<div>
<div>
<AvatarLarge
user={
Object {
"attributes": Object {
"banned": false,
"profile": Object {
"abbreviatedName": "user-1 abbreviated name",
"displayName": "user-1 display name",
},
},
"id": UUID {
"uuid": "user-1",
},
"type": "user",
}
}
/>
<AvatarMedium
user={
Object {
"attributes": Object {
"banned": false,
"profile": Object {
"abbreviatedName": "user-1 abbreviated name",
"displayName": "user-1 display name",
},
},
"id": UUID {
"uuid": "user-1",
},
"type": "user",
}
}
/>
</div>
<div>
<div>
<div>
<div
title={55}
>
55
</div>
<div>
<FormattedMessage
id="ListingPage.perNight"
values={Object {}}
/>
</div>
</div>
<div>
<h1>
listing1 title
</h1>
<div>
<span>
<FormattedMessage
id="ListingPage.hostedBy"
values={
Object {
"name": "user-1 display name",
}
}
/>
</span>
</div>
</div>
</div>
<div>
<h2>
<FormattedMessage
id="ListingPage.descriptionTitle"
values={Object {}}
/>
</h2>
<p>
listing1 description
</p>
</div>
<div>
<h2>
<FormattedMessage
id="ListingPage.locationTitle"
values={Object {}}
/>
</h2>
<div>
<Map
address="listing1 address"
center={
LatLng {
"lat": 40,
"lng": 60,
}
}
className=""
rootClassName={null}
zoom={11}
/>
</div>
</div>
</div>
<withViewport(ModalInMobileComponent)
id="BookingDatesFormInModal"
isModalOpenOnMobile={false}
onClose={[Function]}
onManageDisableScrolling={[Function]}
showAsModalMaxWidth={1023}
>
<div>
<h1>
listing1 title
</h1>
<div>
<span>
<FormattedMessage
id="ListingPage.hostedBy"
values={
Object {
"name": "user-1 display name",
}
}
/>
</span>
</div>
</div>
<div>
<h2>
<FormattedMessage
id="ListingPage.bookingTitle"
values={
Object {
"title": "listing1 title",
}
}
/>
</h2>
<div>
<FormattedMessage
id="ListingPage.bookingHelp"
values={Object {}}
/>
</div>
</div>
<BookingDatesForm
isOwnListing={false}
onSubmit={[Function]}
price={
Money {
"amount": 5500,
"currency": "USD",
}
}
/>
</withViewport(ModalInMobileComponent)>
<div>
<div>
<div
title={55}
>
55
</div>
<div>
<FormattedMessage
id="ListingPage.perNight"
values={Object {}}
/>
</div>
</div>
<Button
className={null}
disabled={false}
inProgress={false}
onClick={[Function]}
ready={false}
rootClassName={null}
>
ListingPage.ctaButtonMessage
</Button>
</div>
</div>
</div>
</div>
</div>
</LayoutWrapperMain>
<LayoutWrapperFooter
className={null}
rootClassName={null}
>
<InjectIntl(Footer) />
</LayoutWrapperFooter>
</LayoutSingleColumn>
</Page>
`;