terriajs
Version:
Geospatial data visualization platform.
194 lines (176 loc) • 5.96 kB
JSX
/**
Initially this was written to support various location search providers in master,
however we only have a single location provider at the moment, and how we merge
them in the new design is yet to be resolved, see:
https://github.com/TerriaJS/nsw-digital-twin/issues/248#issuecomment-599919318
*/
import { observer } from "mobx-react";
import React from "react";
import createReactClass from "create-react-class";
import styled from "styled-components";
import PropTypes from "prop-types";
import { withTranslation } from "react-i18next";
import SearchHeader from "./SearchHeader";
import SearchResult from "./SearchResult";
import classNames from "classnames";
import Styles from "./location-search-result.scss";
import isDefined from "../../Core/isDefined";
import Icon, { StyledIcon } from "../../Styled/Icon";
// import Box, { BoxSpan } from "../../Styled/Box";
import { BoxSpan } from "../../Styled/Box";
import Text, { TextSpan } from "../../Styled/Text";
import { RawButton } from "../../Styled/Button";
const RawButtonAndHighlight = styled(RawButton)`
${(p) => `
&:hover, &:focus {
background-color: ${p.theme.greyLighter};
${StyledIcon} {
fill-opacity: 1;
}
}`}
`;
const MAX_RESULTS_BEFORE_TRUNCATING = 5;
const LocationSearchResults = observer(
createReactClass({
displayName: "LocationSearchResults",
propTypes: {
viewState: PropTypes.object.isRequired,
isWaitingForSearchToStart: PropTypes.bool,
terria: PropTypes.object.isRequired,
search: PropTypes.object.isRequired,
onLocationClick: PropTypes.func.isRequired,
theme: PropTypes.string,
locationSearchText: PropTypes.string,
t: PropTypes.func.isRequired
},
getInitialState() {
return {
isOpen: true,
isExpanded: false
};
},
getDefaultProps() {
return {
theme: "light"
};
},
toggleIsOpen() {
this.setState({
isOpen: !this.state.isOpen
});
},
toggleExpand() {
this.setState({
isExpanded: !this.state.isExpanded
});
},
renderResultsFooter() {
const { t } = this.props;
if (this.state.isExpanded) {
return t("search.viewLess", {
name: this.props.search.searchProvider.name
});
}
return t("search.viewMore", {
name: this.props.search.searchProvider.name
});
},
render() {
const search = this.props.search;
const { isOpen, isExpanded } = this.state;
const searchProvider = search.searchProvider;
const locationSearchBoundingBox =
this.props.terria.configParameters.locationSearchBoundingBox;
const validResults = isDefined(locationSearchBoundingBox)
? search.results.filter(function (r) {
return (
r.location.longitude > locationSearchBoundingBox[0] &&
r.location.longitude < locationSearchBoundingBox[2] &&
r.location.latitude > locationSearchBoundingBox[1] &&
r.location.latitude < locationSearchBoundingBox[3]
);
})
: search.results;
const results =
validResults.length > MAX_RESULTS_BEFORE_TRUNCATING
? isExpanded
? validResults
: validResults.slice(0, MAX_RESULTS_BEFORE_TRUNCATING)
: validResults;
return (
<div
key={searchProvider.name}
className={classNames(Styles.providerResult, {
[Styles.isOpen]: this.state.isOpen,
[Styles.dark]: this.props.theme === "dark",
[Styles.light]: this.props.theme === "light"
})}
>
{/* <button onClick={this.toggleGroup} className={Styles.heading}>
<span>{searchProvider.name}</span>
<Icon
glyph={
this.state.isOpen ? Icon.GLYPHS.opened : Icon.GLYPHS.closed
}
/>
</button> */}
<RawButtonAndHighlight
type="button"
fullWidth
onClick={this.toggleIsOpen}
>
<BoxSpan
paddedRatio={2}
paddedVertically={3}
centered
justifySpaceBetween
>
<TextSpan
textDarker
uppercase
>{`${search.searchProvider.name} (${validResults?.length})`}</TextSpan>
<StyledIcon
styledWidth={"9px"}
glyph={isOpen ? Icon.GLYPHS.opened : Icon.GLYPHS.closed}
/>
</BoxSpan>
</RawButtonAndHighlight>
<Text textDarker>
<SearchHeader
searchResults={search}
isWaitingForSearchToStart={this.props.isWaitingForSearchToStart}
/>
<ul className={Styles.items}>
{results.map((result, i) => (
<SearchResult
key={i}
clickAction={this.props.onLocationClick.bind(null, result)}
name={result.name}
icon="location2"
searchResultTheme={this.props.theme}
locationSearchText={this.props.locationSearchText}
isLastResult={results.length === i + 1}
/>
))}
</ul>
{isOpen && validResults.length > MAX_RESULTS_BEFORE_TRUNCATING && (
<BoxSpan
paddedRatio={2}
paddedVertically={3}
left
justifySpaceBetween
>
<RawButton onClick={this.toggleExpand}>
<TextSpan small isLink>
{this.renderResultsFooter()}
</TextSpan>
</RawButton>
</BoxSpan>
)}
</Text>
</div>
);
}
})
);
module.exports = withTranslation()(LocationSearchResults);