ListingPage: fetch & redux

This commit is contained in:
Vesa Luusua 2017-03-03 17:49:06 +02:00
parent 8f99ca324e
commit ab7666968d

View file

@ -1,9 +1,13 @@
import React from 'react';
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { types } from 'sharetribe-sdk';
import { NamedLink, PageLayout } from '../../components';
import { showListings, getListingsById } from '../../ducks/sdk.duck';
import css from './ListingPage.css';
// TODO this hard coded info needs to be removed when API supports these features
const info = {
title: 'Banyan Studios',
//title: 'Banyan Studios',
price: '55\u20AC / day',
images: [
{ id: 1, title: 'img1', imageUrl: 'http://placehold.it/750x470' },
@ -12,18 +16,18 @@ const info = {
{ id: 4, title: 'img4', imageUrl: 'http://placehold.it/750x470' },
{ id: 5, title: 'img5', imageUrl: 'http://placehold.it/750x470' },
],
description: `
<p>
Organic Music Production in a Sustainable, Ethical and Professional Studio.
</p>
<p>
Social Permaculture focuses on nourishing our environment with abundance instead of depleting it.
</p>
<p>
Banyan Studios is a comfortable, conscious, inspiring and creative retreat for musicians trying to convey their message through state of the art Audio & Video.
</p>
<a href="https://vimeo.com/168106603" alt="video">https://vimeo.com/168106603</a>
`,
// description: `
// <p>
// Organic Music Production in a Sustainable, Ethical and Professional Studio.
// </p>
// <p>
// Social Permaculture focuses on nourishing our environment with abundance instead of depleting it.
// </p>
// <p>
// Banyan Studios is a comfortable, conscious, inspiring and creative retreat for musicians trying to convey their message through state of the art Audio & Video.
// </p>
// <a href="https://vimeo.com/168106603" alt="video">https://vimeo.com/168106603</a>
// `,
reviews: [
{
id: 1,
@ -39,67 +43,113 @@ const info = {
};
// N.B. All the presentational content needs to be extracted to their own components
const ListingPage = () => (
<PageLayout title={`${info.title} ${info.price}`}>
<div className={css.imageContainer}>
<img className={css.mainImage} alt={info.images[0].title} src={info.images[0].imageUrl} />
<div className={css.thumbnailContainer}>
{info.images.slice(1).map(image => (
<div key={image.id} className={css.squareWrapper}>
<div className={css.aspectWrapper}>
<img className={css.thumbnail} alt={image.title} src={image.imageUrl} />
</div>
</div>
))}
</div>
</div>
{/* eslint-disable react/no-danger */}
<div className={css.description} dangerouslySetInnerHTML={{ __html: info.description }} />
{/* eslint-enable react/no-danger */}
<div className={css.filterSection}>
<h1>Here will be filters (or dragons)</h1>
<h2>Studio type</h2>
<h2>Amenities</h2>
<h2>Additional Services Available</h2>
<p><strong>Studio hours:</strong> 10am - 6pm</p>
</div>
<a className={css.contact} href="mailto:studio.dude@mystudio.com">
<h2>Contact studio</h2>
</a>
<div className={css.reviewSection}>
<h2>Studio reviews (1)</h2>
<div className={css.reviews}>
{info.reviews.map(review => (
<div key={review.id} className={css.review}>
<p>{review.review}</p>
<div className={css.reviewDetails}>
<div className={css.avatarWrapper}>
<img
className={css.avatar}
src={review.reviewer.avatar}
alt={review.reviewer.name}
/>
</div>
<div className={css.reviewDetails}>
<span className={css.authorName}>{review.reviewer.name}</span><span
className={css.date}
>
{review.reviewer.date}
</span>
</div>
<div className={css.rating}>
review: <span>{review.rating}</span><span>/5</span>
</div>
</div>
</div>
))}
</div>
</div>
<div className={css.map}>Map</div>
<NamedLink className={css.buttonLink} name="OrderDetailsPage" params={{ id: 12345 }}>
{`Book ${info.title}`}
</NamedLink>
</PageLayout>
);
export class ListingPageComponent extends Component {
export default ListingPage;
componentDidMount() {
ListingPageComponent.loadData(this.props.params.id, this.props.onLoadListing);
}
render() {
const { entitiesData, params } = this.props;
const id = new types.UUID(params.id);
const currentListing = entitiesData.entities.listing ? getListingsById(entitiesData, [id])[0] : null;
const title = currentListing ? currentListing.attributes.title : '';
const description = currentListing ? currentListing.attributes.description : '';
// TODO render "loading" or blank page, if currentListing is null.
return (
<PageLayout title={`${title} ${info.price}`}>
<div className={css.imageContainer}>
<img className={css.mainImage} alt={info.images[0].title} src={info.images[0].imageUrl} />
<div className={css.thumbnailContainer}>
{info.images.slice(1).map(image => (
<div key={image.id} className={css.squareWrapper}>
<div className={css.aspectWrapper}>
<img className={css.thumbnail} alt={image.title} src={image.imageUrl} />
</div>
</div>
))}
</div>
</div>
{/* eslint-disable react/no-danger */}
<div className={css.description} dangerouslySetInnerHTML={{ __html: description }} />
{/* eslint-enable react/no-danger */}
<div className={css.filterSection}>
<h1>Here will be filters (or dragons)</h1>
<h2>Studio type</h2>
<h2>Amenities</h2>
<h2>Additional Services Available</h2>
<p><strong>Studio hours:</strong> 10am - 6pm</p>
</div>
<a className={css.contact} href="mailto:studio.dude@mystudio.com">
<h2>Contact studio</h2>
</a>
<div className={css.reviewSection}>
<h2>Studio reviews (1)</h2>
<div className={css.reviews}>
{info.reviews.map(review => (
<div key={review.id} className={css.review}>
<p>{review.review}</p>
<div className={css.reviewDetails}>
<div className={css.avatarWrapper}>
<img
className={css.avatar}
src={review.reviewer.avatar}
alt={review.reviewer.name}
/>
</div>
<div className={css.reviewDetails}>
<span className={css.authorName}>{review.reviewer.name}</span><span
className={css.date}
>
{review.reviewer.date}
</span>
</div>
<div className={css.rating}>
review: <span>{review.rating}</span><span>/5</span>
</div>
</div>
</div>
))}
</div>
</div>
<div className={css.map}>Map</div>
<NamedLink className={css.buttonLink} name="OrderDetailsPage" params={{ id: 12345 }}>
{`Book ${title}`}
</NamedLink>
</PageLayout>
);
}
};
ListingPageComponent.loadData = (id, onLoadListing) => {
onLoadListing(id);
};
ListingPageComponent.defaultProps = { listing: null };
const { func, object, shape, string } = PropTypes;
ListingPageComponent.propTypes = {
entitiesData: object.isRequired,
onLoadListing: func.isRequired,
params: shape({
id: string.isRequired,
slug: string.isRequired,
}).isRequired,
};
const mapStateToProps = state => {
const { data, ListingPage } = state;
const entitiesData = data ? data : {};
return { ListingPage, entitiesData };
};
const mapDispatchToProps = (dispatch) => {
return {
onLoadListing: (id) => dispatch(showListings({ id, include: ['author'] })),
};
}
export default connect(mapStateToProps, mapDispatchToProps)(ListingPageComponent);