From 2165c793ae0e1f2e6927d626ab6c834b23d8256d Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Thu, 26 Jan 2017 15:30:10 +0200 Subject: [PATCH 1/6] FilterPanel for SearchPage --- src/components/FilterPanel/FilterPanel.css | 37 +++++++++++++++++++ src/components/FilterPanel/FilterPanel.js | 13 +++++++ .../FilterPanel/FilterPanel.test.js | 22 +++++++++++ .../__snapshots__/FilterPanel.test.js.snap | 22 +++++++++++ 4 files changed, 94 insertions(+) create mode 100644 src/components/FilterPanel/FilterPanel.css create mode 100644 src/components/FilterPanel/FilterPanel.js create mode 100644 src/components/FilterPanel/FilterPanel.test.js create mode 100644 src/components/FilterPanel/__snapshots__/FilterPanel.test.js.snap diff --git a/src/components/FilterPanel/FilterPanel.css b/src/components/FilterPanel/FilterPanel.css new file mode 100644 index 00000000..00539109 --- /dev/null +++ b/src/components/FilterPanel/FilterPanel.css @@ -0,0 +1,37 @@ +.filterTitle { + text-align: center; +} + +.toListingsButton { + position: fixed; + bottom: 1rem; + left: 50%; + width: 200px; + margin-left: -100px; + display: block; + text-align: center; + text-decoration: none; + font-size: 1.4rem; + padding: 0.5rem; + color: #fff; + background-color: #9B9B9B; + cursor: pointer; + + &:hover { + background-color: #888; + } +} + +.close { + position: absolute; + top: 0; + left: 0; + height: 3em; + padding: 1em; + color: #999; + text-decoration: none; + + &:hover { + color: #000; + } +} diff --git a/src/components/FilterPanel/FilterPanel.js b/src/components/FilterPanel/FilterPanel.js new file mode 100644 index 00000000..28c798c8 --- /dev/null +++ b/src/components/FilterPanel/FilterPanel.js @@ -0,0 +1,13 @@ +import React from 'react'; +import { NamedLink } from '../../components'; +import css from './FilterPanel.css'; + +const FilterPanel = () => ( +
+

Filters

+ See studios + X +
+); + +export default FilterPanel; diff --git a/src/components/FilterPanel/FilterPanel.test.js b/src/components/FilterPanel/FilterPanel.test.js new file mode 100644 index 00000000..86338357 --- /dev/null +++ b/src/components/FilterPanel/FilterPanel.test.js @@ -0,0 +1,22 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { TestProvider } from '../../util/test-helpers'; +import { RoutesProvider } from '../../components'; +import routesConfiguration from '../../routesConfiguration'; +import FilterPanel from './FilterPanel'; + +describe('FilterPanel', () => { + it('matches snapshot', () => { + const component = renderer.create( + ( + + + + + + ), + ); + const tree = component.toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/src/components/FilterPanel/__snapshots__/FilterPanel.test.js.snap b/src/components/FilterPanel/__snapshots__/FilterPanel.test.js.snap new file mode 100644 index 00000000..d941b9f6 --- /dev/null +++ b/src/components/FilterPanel/__snapshots__/FilterPanel.test.js.snap @@ -0,0 +1,22 @@ +exports[`FilterPanel matches snapshot 1`] = ` +
+

+ Filters +

+ + See studios + + + X + +
+`; From 8e856d754dca651803e46802a6d748985a112b5f Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Thu, 26 Jan 2017 15:37:27 +0200 Subject: [PATCH 2/6] SearchResultsPanel for SearchPage --- src/components/Menu/Menu.css | 17 +++++++++++ src/components/Menu/Menu.js | 10 +++++++ src/components/Menu/Menu.test.js | 14 +++++++++ .../Menu/__snapshots__/Menu.test.js.snap | 10 +++++++ .../SearchResultsPanel/SearchResultsPanel.css | 24 +++++++++++++++ .../SearchResultsPanel/SearchResultsPanel.js | 22 ++++++++++++++ .../SearchResultsPanel.test.js | 22 ++++++++++++++ .../SearchResultsPanel.test.js.snap | 29 +++++++++++++++++++ 8 files changed, 148 insertions(+) create mode 100644 src/components/Menu/Menu.css create mode 100644 src/components/Menu/Menu.js create mode 100644 src/components/Menu/Menu.test.js create mode 100644 src/components/Menu/__snapshots__/Menu.test.js.snap create mode 100644 src/components/SearchResultsPanel/SearchResultsPanel.css create mode 100644 src/components/SearchResultsPanel/SearchResultsPanel.js create mode 100644 src/components/SearchResultsPanel/SearchResultsPanel.test.js create mode 100644 src/components/SearchResultsPanel/__snapshots__/SearchResultsPanel.test.js.snap diff --git a/src/components/Menu/Menu.css b/src/components/Menu/Menu.css new file mode 100644 index 00000000..b3e300b7 --- /dev/null +++ b/src/components/Menu/Menu.css @@ -0,0 +1,17 @@ +.container { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + height: 50px; + border-top: solid 1px #f7f7f7; +} +.container:hover { + background-color: #f7f7f7; + cursor: pointer; +} + +.openIndicator { + margin-left: auto; + margin-right: 1em; +} diff --git a/src/components/Menu/Menu.js b/src/components/Menu/Menu.js new file mode 100644 index 00000000..96c3a38d --- /dev/null +++ b/src/components/Menu/Menu.js @@ -0,0 +1,10 @@ +import React from 'react'; +import css from './Menu.css'; + +const Menu = () => ( +
+ New York, Jan 2nd – Jan 4th +
+); + +export default Menu; diff --git a/src/components/Menu/Menu.test.js b/src/components/Menu/Menu.test.js new file mode 100644 index 00000000..a23c1acd --- /dev/null +++ b/src/components/Menu/Menu.test.js @@ -0,0 +1,14 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { TestProvider } from '../../util/test-helpers'; +import { RoutesProvider } from '../../components'; +import routesConfiguration from '../../routesConfiguration'; +import Menu from './Menu'; + +describe('Menu', () => { + it('matches snapshot', () => { + const component = renderer.create(); + const tree = component.toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/src/components/Menu/__snapshots__/Menu.test.js.snap b/src/components/Menu/__snapshots__/Menu.test.js.snap new file mode 100644 index 00000000..3361773b --- /dev/null +++ b/src/components/Menu/__snapshots__/Menu.test.js.snap @@ -0,0 +1,10 @@ +exports[`Menu matches snapshot 1`] = ` +
+ New York, Jan 2nd – Jan 4th + + ▼ + +
+`; diff --git a/src/components/SearchResultsPanel/SearchResultsPanel.css b/src/components/SearchResultsPanel/SearchResultsPanel.css new file mode 100644 index 00000000..d811c984 --- /dev/null +++ b/src/components/SearchResultsPanel/SearchResultsPanel.css @@ -0,0 +1,24 @@ +.navigation { + display: flex; + position: fixed; + bottom: 15px; + left: 50%; + margin-left: -100px; +} + +.button { + display: block; + width: 100px; + text-align: center; + text-decoration: none; + font-size: 1.4rem; + padding: 0.5rem; + margin: 1rem 0.1rem; + color: #fff; + background-color: #9B9B9B; + cursor: pointer; + + &:hover { + background-color: #888; + } +} diff --git a/src/components/SearchResultsPanel/SearchResultsPanel.js b/src/components/SearchResultsPanel/SearchResultsPanel.js new file mode 100644 index 00000000..4c57f621 --- /dev/null +++ b/src/components/SearchResultsPanel/SearchResultsPanel.js @@ -0,0 +1,22 @@ +import React, { PropTypes } from 'react'; +import { Menu, NamedLink } from '../../components'; +import css from './SearchResultsPanel.css'; + +const SearchResultsPanel = props => ( +
+ + {props.children} +
+ Filters + Map +
+
+); + +SearchResultsPanel.defaultProps = { children: null }; + +const { any } = PropTypes; + +SearchResultsPanel.propTypes = { children: any }; + +export default SearchResultsPanel; diff --git a/src/components/SearchResultsPanel/SearchResultsPanel.test.js b/src/components/SearchResultsPanel/SearchResultsPanel.test.js new file mode 100644 index 00000000..0cb99f5e --- /dev/null +++ b/src/components/SearchResultsPanel/SearchResultsPanel.test.js @@ -0,0 +1,22 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { TestProvider } from '../../util/test-helpers'; +import { RoutesProvider } from '../../components'; +import routesConfiguration from '../../routesConfiguration'; +import SearchResultsPanel from './SearchResultsPanel'; + +describe('SearchResultsPanel', () => { + it('matches snapshot', () => { + const component = renderer.create( + ( + + + + + + ), + ); + const tree = component.toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/src/components/SearchResultsPanel/__snapshots__/SearchResultsPanel.test.js.snap b/src/components/SearchResultsPanel/__snapshots__/SearchResultsPanel.test.js.snap new file mode 100644 index 00000000..a93c2baa --- /dev/null +++ b/src/components/SearchResultsPanel/__snapshots__/SearchResultsPanel.test.js.snap @@ -0,0 +1,29 @@ +exports[`SearchResultsPanel matches snapshot 1`] = ` +
+
+ New York, Jan 2nd – Jan 4th + + ▼ + +
+
+ + Filters + + + Map + +
+
+`; From acf85d9af6f471068f4be78c40f1fd2fdfa00557 Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Thu, 26 Jan 2017 15:48:58 +0200 Subject: [PATCH 3/6] MapPanel for SearchPage --- src/components/MapPanel/MapPanel.css | 53 +++++++++++++++++++ src/components/MapPanel/MapPanel.js | 22 ++++++++ src/components/MapPanel/MapPanel.test.js | 22 ++++++++ .../__snapshots__/MapPanel.test.js.snap | 24 +++++++++ 4 files changed, 121 insertions(+) create mode 100644 src/components/MapPanel/MapPanel.css create mode 100644 src/components/MapPanel/MapPanel.js create mode 100644 src/components/MapPanel/MapPanel.test.js create mode 100644 src/components/MapPanel/__snapshots__/MapPanel.test.js.snap diff --git a/src/components/MapPanel/MapPanel.css b/src/components/MapPanel/MapPanel.css new file mode 100644 index 00000000..3ff8f8e6 --- /dev/null +++ b/src/components/MapPanel/MapPanel.css @@ -0,0 +1,53 @@ +.mapContainer { + height: 70vh; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + background-color: #ddd; + color: #fff; + font-size: 2rem; +} +.mapListingsContainer { + height: 30vh; + width: 100%; + background-color: #fff; + display: flex; + flex-direction: row; + padding: 1rem; +} + + +.toFiltersButton { + position: fixed; + top: calc(70vh - 80px); + left: 50%; + width: 200px; + margin-left: -100px; + display: block; + text-align: center; + text-decoration: none; + font-size: 1.4rem; + padding: 0.5rem; + color: #fff; + background-color: #9B9B9B; + cursor: pointer; + + &:hover { + background-color: #888; + } +} + +.close { + position: absolute; + top: 0; + left: 0; + height: 3em; + padding: 1em; + color: #999; + text-decoration: none; + + &:hover { + color: #000; + } +} diff --git a/src/components/MapPanel/MapPanel.js b/src/components/MapPanel/MapPanel.js new file mode 100644 index 00000000..a0383b4d --- /dev/null +++ b/src/components/MapPanel/MapPanel.js @@ -0,0 +1,22 @@ +import React, { PropTypes } from 'react'; +import { NamedLink } from '../../components'; +import css from './MapPanel.css'; + +const MapPanel = props => ( +
+
Map
+
+ {props.children} +
+ Filters + X +
+); + +MapPanel.defaultProps = { children: null }; + +const { any } = PropTypes; + +MapPanel.propTypes = { children: any }; + +export default MapPanel; diff --git a/src/components/MapPanel/MapPanel.test.js b/src/components/MapPanel/MapPanel.test.js new file mode 100644 index 00000000..562860b6 --- /dev/null +++ b/src/components/MapPanel/MapPanel.test.js @@ -0,0 +1,22 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { TestProvider } from '../../util/test-helpers'; +import { RoutesProvider } from '../../components'; +import routesConfiguration from '../../routesConfiguration'; +import MapPanel from './MapPanel'; + +describe('MapPanel', () => { + it('matches snapshot', () => { + const component = renderer.create( + ( + + + + + + ), + ); + const tree = component.toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/src/components/MapPanel/__snapshots__/MapPanel.test.js.snap b/src/components/MapPanel/__snapshots__/MapPanel.test.js.snap new file mode 100644 index 00000000..8b5b9f82 --- /dev/null +++ b/src/components/MapPanel/__snapshots__/MapPanel.test.js.snap @@ -0,0 +1,24 @@ +exports[`MapPanel matches snapshot 1`] = ` +
+
+ Map +
+ +`; From 1fdccf7f7143e6fdfd2deca1a9693ee37077659c Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Thu, 26 Jan 2017 16:13:24 +0200 Subject: [PATCH 4/6] ListingCard for SearchResultsPanel and ListingCardSmall for MapPanel --- src/components/ListingCard/ListingCard.css | 67 +++++++++++++++ src/components/ListingCard/ListingCard.js | 71 +++++++++++++++ .../ListingCard/ListingCard.test.js | 35 ++++++++ .../__snapshots__/ListingCard.test.js.snap | 86 +++++++++++++++++++ .../ListingCardSmall/ListingCardSmall.css | 38 ++++++++ .../ListingCardSmall/ListingCardSmall.js | 43 ++++++++++ .../ListingCardSmall/ListingCardSmall.test.js | 35 ++++++++ .../ListingCardSmall.test.js.snap | 44 ++++++++++ 8 files changed, 419 insertions(+) create mode 100644 src/components/ListingCard/ListingCard.css create mode 100644 src/components/ListingCard/ListingCard.js create mode 100644 src/components/ListingCard/ListingCard.test.js create mode 100644 src/components/ListingCard/__snapshots__/ListingCard.test.js.snap create mode 100644 src/components/ListingCardSmall/ListingCardSmall.css create mode 100644 src/components/ListingCardSmall/ListingCardSmall.js create mode 100644 src/components/ListingCardSmall/ListingCardSmall.test.js create mode 100644 src/components/ListingCardSmall/__snapshots__/ListingCardSmall.test.js.snap diff --git a/src/components/ListingCard/ListingCard.css b/src/components/ListingCard/ListingCard.css new file mode 100644 index 00000000..bafa1e92 --- /dev/null +++ b/src/components/ListingCard/ListingCard.css @@ -0,0 +1,67 @@ +.listing { + display: flex; + flex-direction: column; + border-radius: 4px; +} + +.squareWrapper { + display: block; + position: relative; + width: 100%; +} + +/* Firefox doesn't support image aspect ratio inside flexbox */ +.aspectWrapper { + padding-bottom: 75%; /* 4:3 Aspect Ratio */ +} + +.thumbnail { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100%; +} + +.info { + padding: 1rem; + +} + +.mainInfo { + width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.details { + width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.authorInfo { + width: 100%; + display: flex; + flex-direction: row; +} + +.authorDetails { + width: 100%; + display: flex; + flex-direction: column; +} +.avatarWrapper { + display: block; + flex-basis: 44px; + width: 44px; + height: 44px; + margin-right: 1rem; +} +.avatar { + border-radius: 22px; +} diff --git a/src/components/ListingCard/ListingCard.js b/src/components/ListingCard/ListingCard.js new file mode 100644 index 00000000..a868367d --- /dev/null +++ b/src/components/ListingCard/ListingCard.js @@ -0,0 +1,71 @@ +import React, { PropTypes } from 'react'; +import { NamedLink } from '../../components'; +import css from './ListingCard.css'; + +const ListingCard = props => { + const { id, title, price, description, location, review, author } = props; + const slug = encodeURIComponent(title.split(' ').join('-')); + return ( +
+
+
+ Listing Title +
+
+
+
+ + {title} + +
+ {price} +
+
+
+ {description} +
+
+
+ {location} +
+
+ ({review.rating}/5){' '} + {review.count} +
+
+
+
+
+ {author.name} +
+
+ {author.name} +
+ review: {author.review.rating}/5 +
+
+
+
+
+ ); +}; + +ListingCard.defaultProps = { location: null, review: {}, author: {} }; + +const { number, shape, string } = PropTypes; + +ListingCard.propTypes = { + id: number.isRequired, + title: string.isRequired, + price: string.isRequired, + description: string.isRequired, + location: string, + review: shape({ rating: string.isRequired, count: string.isRequired }), + author: shape({ + name: string.isRequired, + avatar: string.isRequired, + review: shape({ rating: string.isRequired }), + }), +}; + +export default ListingCard; diff --git a/src/components/ListingCard/ListingCard.test.js b/src/components/ListingCard/ListingCard.test.js new file mode 100644 index 00000000..c016fffe --- /dev/null +++ b/src/components/ListingCard/ListingCard.test.js @@ -0,0 +1,35 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { TestProvider } from '../../util/test-helpers'; +import { RoutesProvider } from '../../components'; +import routesConfiguration from '../../routesConfiguration'; +import ListingCard from './ListingCard'; + +describe('ListingCard', () => { + it('matches snapshot', () => { + const listing = { + id: 123, + title: 'Banyan Studios', + price: '55\u20AC / day', + description: 'Organic Music Production in a Sustainable, Ethical and Professional Studio.', + location: 'New York, NY \u2022 40mi away', + review: { count: '8 reviews', rating: '4' }, + author: { + name: 'The Stardust Collective', + avatar: 'http://placehold.it/44x44', + review: { rating: '4' }, + }, + }; + const component = renderer.create( + ( + + + + + + ), + ); + const tree = component.toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/src/components/ListingCard/__snapshots__/ListingCard.test.js.snap b/src/components/ListingCard/__snapshots__/ListingCard.test.js.snap new file mode 100644 index 00000000..2c06adbf --- /dev/null +++ b/src/components/ListingCard/__snapshots__/ListingCard.test.js.snap @@ -0,0 +1,86 @@ +exports[`ListingCard matches snapshot 1`] = ` +
+
+
+ Listing Title +
+
+
+
+ + Banyan Studios + +
+ 55€ / day +
+
+
+ Organic Music Production in a Sustainable, Ethical and Professional Studio. +
+
+
+ New York, NY • 40mi away +
+
+ ( + + 4 + + + /5 + + ) + + + 8 reviews + +
+
+
+
+
+ The Stardust Collective +
+
+ + The Stardust Collective + +
+ review: + + 4 + + + /5 + +
+
+
+
+
+`; diff --git a/src/components/ListingCardSmall/ListingCardSmall.css b/src/components/ListingCardSmall/ListingCardSmall.css new file mode 100644 index 00000000..4ac667ed --- /dev/null +++ b/src/components/ListingCardSmall/ListingCardSmall.css @@ -0,0 +1,38 @@ +.listing { + width: 130px; + display: flex; + flex-direction: column; + border-radius: 4px; + margin-right: 1rem; +} + +.squareWrapper { + display: block; + position: relative; + width: 100%; +} + +/* Firefox doesn't support image aspect ratio inside flexbox */ +.aspectWrapper { + padding-bottom: 75%; /* 4:3 Aspect Ratio */ +} + +.thumbnail { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100%; +} + +.info { + width: 100%; + display: flex; + flex-direction: column; + justify-content: space-between; + padding: 0.5rem; + font-size: 0.8rem; + border: solid 1px #ccc; +} diff --git a/src/components/ListingCardSmall/ListingCardSmall.js b/src/components/ListingCardSmall/ListingCardSmall.js new file mode 100644 index 00000000..c4578dd0 --- /dev/null +++ b/src/components/ListingCardSmall/ListingCardSmall.js @@ -0,0 +1,43 @@ +import React, { PropTypes } from 'react'; +import { NamedLink } from '../../components'; +import css from './ListingCardSmall.css'; + +// X +const ListingCardSmall = props => { + const { id, title, price, review } = props; + const slug = encodeURIComponent(title.split(' ').join('-')); + return ( +
+
+
+ Listing Title +
+
+
+ + {title} + +
+ ({review.rating}/5){' '} + {review.count} +
+
+ {price} +
+
+
+ ); +}; + +ListingCardSmall.defaultProps = { review: {} }; + +const { number, shape, string } = PropTypes; + +ListingCardSmall.propTypes = { + id: number.isRequired, + title: string.isRequired, + price: string.isRequired, + review: shape({ rating: string.isRequired, count: string.isRequired }), +}; + +export default ListingCardSmall; diff --git a/src/components/ListingCardSmall/ListingCardSmall.test.js b/src/components/ListingCardSmall/ListingCardSmall.test.js new file mode 100644 index 00000000..2f5e2eb1 --- /dev/null +++ b/src/components/ListingCardSmall/ListingCardSmall.test.js @@ -0,0 +1,35 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import { TestProvider } from '../../util/test-helpers'; +import { RoutesProvider } from '../../components'; +import routesConfiguration from '../../routesConfiguration'; +import ListingCardSmall from './ListingCardSmall'; + +describe('ListingCardSmall', () => { + it('matches snapshot', () => { + const listing = { + id: 123, + title: 'Banyan Studios', + price: '55\u20AC / day', + description: 'Organic Music Production in a Sustainable, Ethical and Professional Studio.', + location: 'New York, NY \u2022 40mi away', + review: { count: '8 reviews', rating: '4' }, + author: { + name: 'The Stardust Collective', + avatar: 'http://placehold.it/44x44', + review: { rating: '4' }, + }, + }; + const component = renderer.create( + ( + + + + + + ), + ); + const tree = component.toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/src/components/ListingCardSmall/__snapshots__/ListingCardSmall.test.js.snap b/src/components/ListingCardSmall/__snapshots__/ListingCardSmall.test.js.snap new file mode 100644 index 00000000..e6a52348 --- /dev/null +++ b/src/components/ListingCardSmall/__snapshots__/ListingCardSmall.test.js.snap @@ -0,0 +1,44 @@ +exports[`ListingCardSmall matches snapshot 1`] = ` +
+
+
+ Listing Title +
+
+
+ + Banyan Studios + +
+ ( + + 4 + + + /5 + + ) + + + 8 reviews + +
+
+ 55€ / day +
+
+
+`; From 4b8859db60961d61c97caf3c90211b1ef01d254a Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Thu, 26 Jan 2017 16:17:21 +0200 Subject: [PATCH 5/6] Add classnames package --- package.json | 1 + yarn.lock | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/package.json b/package.json index 9b7c33b5..fbe221ae 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "basic-auth": "^1.1.0", + "classnames": "^2.2.5", "compression": "^1.6.2", "express": "^4.14.0", "helmet": "^3.3.0", diff --git a/yarn.lock b/yarn.lock index 1ca4fa97..61929537 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1205,6 +1205,10 @@ clap@^1.0.9: dependencies: chalk "^1.1.3" +classnames@^2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" + clean-css@3.4.x: version "3.4.24" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.24.tgz#89f5a5e9da37ae02394fe049a41388abbe72c3b5" From 39aa6608325eccae7af06ed79d4d1413a6c4d2a3 Mon Sep 17 00:00:00 2001 From: Vesa Luusua Date: Thu, 26 Jan 2017 16:22:42 +0200 Subject: [PATCH 6/6] Add wireframes for SearchPage --- src/components/index.js | 21 +- src/containers/SearchPage/SearchPage.css | 36 ++ src/containers/SearchPage/SearchPage.js | 105 +++++- .../__snapshots__/SearchPage.test.js.snap | 349 +++++++++++++++++- src/routesConfiguration.js | 27 +- 5 files changed, 508 insertions(+), 30 deletions(-) create mode 100644 src/containers/SearchPage/SearchPage.css diff --git a/src/components/index.js b/src/components/index.js index 082c9dc5..da8b45ee 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -1,8 +1,27 @@ +import FilterPanel from './FilterPanel/FilterPanel'; import HeroSection from './HeroSection/HeroSection'; +import ListingCard from './ListingCard/ListingCard'; +import ListingCardSmall from './ListingCardSmall/ListingCardSmall'; +import MapPanel from './MapPanel/MapPanel'; +import Menu from './Menu/Menu'; import NamedLink from './NamedLink/NamedLink'; import NamedRedirect from './NamedRedirect/NamedRedirect'; import PageLayout from './PageLayout/PageLayout'; import RouterProvider from './RouterProvider/RouterProvider'; import RoutesProvider from './RoutesProvider/RoutesProvider'; +import SearchResultsPanel from './SearchResultsPanel/SearchResultsPanel'; -export { HeroSection, NamedLink, NamedRedirect, PageLayout, RouterProvider, RoutesProvider }; +export { + FilterPanel, + HeroSection, + ListingCard, + ListingCardSmall, + MapPanel, + Menu, + NamedLink, + NamedRedirect, + PageLayout, + RouterProvider, + RoutesProvider, + SearchResultsPanel, +}; diff --git a/src/containers/SearchPage/SearchPage.css b/src/containers/SearchPage/SearchPage.css new file mode 100644 index 00000000..690c08d9 --- /dev/null +++ b/src/containers/SearchPage/SearchPage.css @@ -0,0 +1,36 @@ +.container { + width: 100%; +} + +.tab { + display: none; +} + +.filters { + composes: tab; + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background-color: #fff; +} + +.listings{ + composes: tab; +} + +.map { + composes: tab; + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; +} + + + +.open { + display: block; +} diff --git a/src/containers/SearchPage/SearchPage.js b/src/containers/SearchPage/SearchPage.js index 73a305d8..6a476b9f 100644 --- a/src/containers/SearchPage/SearchPage.js +++ b/src/containers/SearchPage/SearchPage.js @@ -1,18 +1,97 @@ -import React from 'react'; +import React, { PropTypes } from 'react'; +import classNames from 'classnames'; import { connect } from 'react-redux'; -import { NamedLink, PageLayout } from '../../components'; +import { find } from 'lodash'; import { addFlashNotification } from '../../ducks/FlashNotification.ducks'; import { addFilter } from './SearchPage.ducks'; +import css from './SearchPage.css'; +import { + FilterPanel, + ListingCard, + ListingCardSmall, + MapPanel, + PageLayout, + SearchResultsPanel, +} from '../../components'; -export const SearchPageComponent = () => ( - - - Nice studio in Helsinki - -
- LandingPage -
-); +const tabClasses = [ + { name: 'filters', css: css.filters }, + { name: 'listings', css: css.listings }, + { name: 'map', css: css.map }, +]; + +const findTab = forTabType => { + const foundTab = find(tabClasses, c => c.name === forTabType); + if (!foundTab) { + return find(tabClasses, c => c.name === 'listings'); + } + return foundTab; +}; + +const combinedClasses = (forTabType, currentTab) => { + const foundTab = findTab(forTabType); + const shouldOpenDefault = !currentTab && foundTab.name === 'listings'; + + if (foundTab.name === currentTab || shouldOpenDefault) { + return classNames(foundTab.css, css.open); + } + + return foundTab.css; +}; + +const fakeListings = [ + { + id: 123, + title: 'Banyan Studios', + price: '55\u20AC / day', + description: 'Organic Music Production in a Sustainable, Ethical and Professional Studio.', + location: 'New York, NY \u2022 40mi away', + review: { count: '8 reviews', rating: '4' }, + author: { + name: 'The Stardust Collective', + avatar: 'http://placehold.it/44x44', + review: { rating: '4' }, + }, + }, + { + id: 1234, + title: 'Pienix Studio', + price: '80\u20AC day', + description: 'Pienix Studio specializes in music mixing and mastering production.', + location: 'New York, NY \u2022 6mi away', + review: { count: '7 reviews', rating: '4' }, + author: { name: 'Juhan', avatar: 'http://placehold.it/44x44', review: { rating: '4' } }, + }, +]; + +export const SearchPageComponent = props => { + const { tab } = props; + return ( + +
+
+ +
+
+ + {fakeListings.map(l => )} + +
+
+ + {fakeListings.map(l => )} + +
+
+
+ ); +}; + +SearchPageComponent.defaultProps = { tab: 'listings' }; + +const { string } = PropTypes; + +SearchPageComponent.propTypes = { tab: string }; /** * Container functions. @@ -25,8 +104,8 @@ const mapStateToProps = function mapStateToProps(state) { const mapDispatchToProps = function mapDispatchToProps(dispatch) { return { - addNotice: msg => dispatch(addFlashNotification('notice', msg)), - addFilter: (k, v) => dispatch(addFilter(k, v)), + onAddNotice: msg => dispatch(addFlashNotification('notice', msg)), + onAddFilter: (k, v) => dispatch(addFilter(k, v)), }; }; diff --git a/src/containers/SearchPage/__snapshots__/SearchPage.test.js.snap b/src/containers/SearchPage/__snapshots__/SearchPage.test.js.snap index f3eb1c46..1d1ee0ee 100644 --- a/src/containers/SearchPage/__snapshots__/SearchPage.test.js.snap +++ b/src/containers/SearchPage/__snapshots__/SearchPage.test.js.snap @@ -119,20 +119,339 @@ exports[`SearchPageComponent matches snapshot 1`] = `

Search page

- - Nice studio in Helsinki - -
- - LandingPage - +
+
+
+

+ Filters +

+ + See studios + + + X + +
+
+
+
+
+ New York, Jan 2nd – Jan 4th + + ▼ + +
+
+
+
+ Listing Title +
+
+
+
+ + Banyan Studios + +
+ 55€ / day +
+
+
+ Organic Music Production in a Sustainable, Ethical and Professional Studio. +
+
+
+ New York, NY • 40mi away +
+
+ ( + + 4 + + + /5 + + ) + + + 8 reviews + +
+
+
+
+
+ The Stardust Collective +
+
+ + The Stardust Collective + +
+ review: + + 4 + + + /5 + +
+
+
+
+
+
+
+
+ Listing Title +
+
+
+
+ + Pienix Studio + +
+ 80€ day +
+
+
+ Pienix Studio specializes in music mixing and mastering production. +
+
+
+ New York, NY • 6mi away +
+
+ ( + + 4 + + + /5 + + ) + + + 7 reviews + +
+
+
+
+
+ Juhan +
+
+ + Juhan + +
+ review: + + 4 + + + /5 + +
+
+
+
+
+ +
+
+
+
+
+ Map +
+
+
+
+
+ Listing Title +
+
+
+ + Banyan Studios + +
+ ( + + 4 + + + /5 + + ) + + + 8 reviews + +
+
+ 55€ / day +
+
+
+
+
+
+ Listing Title +
+
+
+ + Pienix Studio + +
+ ( + + 4 + + + /5 + + ) + + + 7 reviews + +
+
+ 80€ day +
+
+
+
+ + Filters + + + X + +
+
+
`; diff --git a/src/routesConfiguration.js b/src/routesConfiguration.js index 34ea3f9a..6f20a8f7 100644 --- a/src/routesConfiguration.js +++ b/src/routesConfiguration.js @@ -28,7 +28,32 @@ const RedirectLandingPage = () => ; const routesConfiguration = [ { pattern: '/', exactly: true, name: 'LandingPage', component: LandingPage }, - { pattern: '/s', exactly: true, name: 'SearchPage', component: SearchPage }, + { + pattern: '/s', + exactly: true, + name: 'SearchPage', + component: SearchPage, + routes: [ + { + pattern: '/s/filters', + exactly: true, + name: 'SearchFiltersPage', + component: props => , + }, + { + pattern: '/s/listings', + exactly: true, + name: 'SearchListingsPage', + component: props => , + }, + { + pattern: '/s/map', + exactly: true, + name: 'SearchMapPage', + component: props => , + }, + ], + }, { pattern: '/l', exactly: true,