Add SearchAttributes component

Move search summary content into the new SearchAttributes component.
This commit is contained in:
Hannu Lyytikainen 2017-12-20 10:48:55 +02:00
parent c33752e8b8
commit 3a1a472a32
8 changed files with 156 additions and 160 deletions

View file

@ -0,0 +1,52 @@
@import '../../marketplace.css';
.searchResultSummary {
display: none;
@media (--viewportMedium) {
display: block;
margin: 8px 24px 14px 24px;
}
@media (--viewportLarge) {
margin: 8px 36px 14px 36px;
}
}
.searchResultSummaryMobile {
display: flex;
justify-content: space-between;
background-color: var(--matterColorBright);
width: 100vw;
padding: 1px 24px 14px 24px;
/* sticky result summary in mobile */
position: sticky;
top: 0;
z-index: 9;
@media (--viewportMedium) {
display: none;
}
}
.mapIcon {
/* Font */
@apply --marketplaceTinyFontStyles;
font-weight: var(--fontWeightBold);
/* background map image */
background-image: url(./images/map_icon@2x.png);
background-size: cover;
border-radius: 3px;
width: 72px;
height: 35px;
margin-top: 23px;
padding: 9px 22px;
}
.error {
color: var(--failColor);
}

View file

@ -0,0 +1,66 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import css from './SearchAttributes.css';
const SearchAttributes = props => {
const { listingsAreLoaded, resultsCount, searchInProgress, searchListingsError, onMapIconClick} = props;
const searchError = (
<h2 className={css.error}>
<FormattedMessage id="SearchAttributes.searchError" />
</h2>
);
const loadingResults = (
<h2>
<FormattedMessage id="SearchAttributes.loadingResults" />
</h2>
);
const resultsFound = (
<h2>
<FormattedMessage id="SearchAttributes.foundResults" values={{ count: resultsCount }} />
</h2>
);
const noResults = (
<h2>
<FormattedMessage id="SearchAttributes.noResults" />
</h2>
);
const resultsFoundMobile = (
<h2>
<FormattedMessage id="SearchAttributes.foundResultsMobile" values={{ count: resultsCount }} />
</h2>
);
return (
<div>
<div className={css.searchResultSummary}>
{searchListingsError ? searchError : null}
{listingsAreLoaded && resultsCount > 0 ? resultsFound : null}
{listingsAreLoaded && resultsCount === 0 ? noResults : null}
{searchInProgress ? loadingResults : null}
</div>
<div className={css.searchResultSummaryMobile}>
<div>
{searchListingsError ? searchError : null}
{listingsAreLoaded && resultsCount > 0 ? resultsFoundMobile : null}
{listingsAreLoaded && resultsCount === 0 ? noResults : null}
{searchInProgress ? loadingResults : null}
</div>
<div
className={css.mapIcon}
onClick={onMapIconClick}
>
<FormattedMessage id="SearchAttributes.openMapView" className={css.mapIconText} />
</div>
</div>
</div>
);
};
export default SearchAttributes;

View file

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -85,6 +85,7 @@ export { default as ResponsiveImage } from './ResponsiveImage/ResponsiveImage';
export { default as ReviewModal } from './ReviewModal/ReviewModal';
export { default as ReviewRating } from './ReviewRating/ReviewRating';
export { default as Reviews } from './Reviews/Reviews';
export { default as SearchAttributes } from './SearchAttributes/SearchAttributes';
export { default as SearchMap } from './SearchMap/SearchMap';
export { default as SearchMapGroupLabel } from './SearchMapGroupLabel/SearchMapGroupLabel';
export { default as SearchMapInfoCard } from './SearchMapInfoCard/SearchMapInfoCard';

View file

@ -45,57 +45,6 @@
}
}
.searchResultSummary {
display: none;
@media (--viewportMedium) {
display: block;
margin: 8px 24px 14px 24px;
}
@media (--viewportLarge) {
margin: 8px 36px 14px 36px;
}
}
.searchResultSummaryMobile {
display: flex;
justify-content: space-between;
background-color: var(--matterColorBright);
width: 100vw;
padding: 1px 24px 14px 24px;
/* sticky result summary in mobile */
position: sticky;
top: 0;
z-index: 9;
@media (--viewportMedium) {
display: none;
}
}
.mapIcon {
/* Font */
@apply --marketplaceTinyFontStyles;
font-weight: var(--fontWeightBold);
/* background map image */
background-image: url(./images/map_icon@2x.png);
background-size: cover;
border-radius: 3px;
width: 72px;
height: 35px;
margin-top: 23px;
padding: 9px 22px;
}
.error {
color: var(--failColor);
}
.searchString {
/* Search string should not break on white spaces - i.e. line-break should happen before. */
white-space: nowrap;

View file

@ -1,6 +1,6 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
import { injectIntl, intlShape } from 'react-intl';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { withRouter } from 'react-router-dom';
@ -19,7 +19,13 @@ import { createSlug, parse, stringify } from '../../util/urlHelpers';
import * as propTypes from '../../util/propTypes';
import { getListingsById } from '../../ducks/marketplaceData.duck';
import { manageDisableScrolling, isScrollingDisabled } from '../../ducks/UI.duck';
import { SearchMap, ModalInMobile, Page, SearchResultsPanel } from '../../components';
import {
SearchMap,
ModalInMobile,
Page,
SearchResultsPanel,
SearchAttributes,
} from '../../components';
import { TopbarContainer } from '../../containers';
import { searchListings, searchMapListings } from './SearchPage.duck';
@ -172,48 +178,6 @@ export class SearchPageComponent extends Component {
const totalItems = searchParamsMatch && hasPaginationInfo ? pagination.totalItems : 0;
const listingsAreLoaded = !searchInProgress && searchParamsMatch && hasPaginationInfo;
const searchError = (
<h2 className={css.error}>
<FormattedMessage id="SearchPage.searchError" />
</h2>
);
const resultsFoundNoAddress = (
<h2>
<FormattedMessage id="SearchPage.foundResults" values={{ count: totalItems }} />
</h2>
);
const addressNode = address ? (
<span className={css.searchString}>{searchInURL.address.split(', ')[0]}</span>
) : null;
const resultsFoundWithAddress = (
<h2>
<FormattedMessage
id="SearchPage.foundResultsWithAddress"
values={{ count: totalItems, address: addressNode }}
/>
</h2>
);
const resultsFound = address && !mapSearch ? resultsFoundWithAddress : resultsFoundNoAddress;
const resultsFoundMobile = (
<h2>
<FormattedMessage id="SearchPage.foundResultsMobile" values={{ count: totalItems }} />
</h2>
);
const noResults = (
<h2>
<FormattedMessage id="SearchPage.noResults" />
</h2>
);
const loadingResults = (
<h2>
<FormattedMessage id="SearchPage.loadingResults" />
</h2>
);
const searchMap = (
<SearchMap
bounds={bounds}
@ -264,6 +228,14 @@ export class SearchPageComponent extends Component {
itemListElement: schemaListings,
});
const onMapIconClick = () => {
this.useLocationSearchBounds = true;
this.modalOpenedBoundsChange = true;
this.setState({ isSearchMapOpenOnMobile: true });
};
// N.B. openMobileMap button is sticky.
// For some reason, stickyness doesn't work on Safari, if the element is <button>
/* eslint-disable jsx-a11y/no-static-element-interactions */
@ -283,30 +255,14 @@ export class SearchPageComponent extends Component {
<TopbarContainer className={css.topbar} />
<div className={css.container}>
<div className={css.searchResultContainer}>
<div className={css.searchResultSummary}>
{searchListingsError ? searchError : null}
{listingsAreLoaded && totalItems > 0 ? resultsFound : null}
{listingsAreLoaded && totalItems === 0 ? noResults : null}
{searchInProgress ? loadingResults : null}
</div>
<div className={css.searchResultSummaryMobile}>
<div>
{searchListingsError ? searchError : null}
{listingsAreLoaded && totalItems > 0 ? resultsFoundMobile : null}
{listingsAreLoaded && totalItems === 0 ? noResults : null}
{searchInProgress ? loadingResults : null}
</div>
<div
className={css.mapIcon}
onClick={() => {
this.useLocationSearchBounds = true;
this.modalOpenedBoundsChange = true;
this.setState({ isSearchMapOpenOnMobile: true });
}}
>
<FormattedMessage id="SearchPage.openMapView" className={css.mapIconText} />
</div>
</div>
<SearchAttributes
listingsAreLoaded={listingsAreLoaded}
resultsCount={totalItems}
searchInProgress={searchInProgress}
searchListingsError={searchListingsError}
onMapIconClick={onMapIconClick}
/>
<div
className={classNames(css.listings, {
[css.newSearchInProgress]: !listingsAreLoaded,

View file

@ -20,40 +20,12 @@ exports[`SearchPageComponent matches snapshot 1`] = `
<withRouter(Connect(TopbarContainerComponent)) />
<div>
<div>
<div>
<h2>
<FormattedMessage
id="SearchPage.foundResults"
values={
Object {
"count": 22,
}
}
/>
</h2>
</div>
<div>
<div>
<h2>
<FormattedMessage
id="SearchPage.foundResultsMobile"
values={
Object {
"count": 22,
}
}
/>
</h2>
</div>
<div
onClick={[Function]}
>
<FormattedMessage
id="SearchPage.openMapView"
values={Object {}}
/>
</div>
</div>
<SearchAttributes
listingsAreLoaded={true}
resultsCount={22}
searchInProgress={false}
searchListingsError={null}
/>
<div
className=""
>

View file

@ -455,17 +455,17 @@
"ReviewModal.description": "Reviews are an important part of the Saunatime community. Please share what went well and what could have been improved.",
"ReviewModal.later": "Later",
"ReviewModal.title": "Leave a review for {revieweeName}",
"SearchAttributes.foundResults": "{count, number} {count, plural, one {sauna} other {saunas}} found",
"SearchAttributes.foundResultsMobile": "{count, number} {count, plural, one {result} other {results}}",
"SearchAttributes.foundResultsWithAddress": "{count, number} {count, plural, one {sauna} other {saunas}} around {address}",
"SearchAttributes.loadingResults": "Loading search results…",
"SearchAttributes.noResults": "Could not find any listings.",
"SearchAttributes.openMapView": "Map",
"SearchAttributes.searchError": "Search failed. Please try again.",
"SearchMapInfoCard.noImage": "No image",
"SearchPage.foundResults": "{count, number} {count, plural, one {sauna} other {saunas}} found",
"SearchPage.foundResultsMobile": "{count, number} {count, plural, one {result} other {results}}",
"SearchPage.foundResultsWithAddress": "{count, number} {count, plural, one {sauna} other {saunas}} around {address}",
"SearchPage.loadingResults": "Loading search results…",
"SearchPage.noResults": "Could not find any listings.",
"SearchPage.openMapView": "Map",
"SearchPage.schemaDescription": "Showing search results",
"SearchPage.schemaMapSearch": "map search",
"SearchPage.schemaTitle": "Search results for {searchAddress} | {siteTitle}",
"SearchPage.searchError": "Search failed. Please try again.",
"SearchResultsPanel.nextPage": "Next page",
"SearchResultsPanel.previousPage": "Previous page",
"SectionHero.mobileSearchButtonText": "Search saunas",