Add postcode search box

This commit is contained in:
Tom Russell 2019-02-11 09:04:19 +00:00
parent 2a676103ba
commit f05fe3dba5
3 changed files with 159 additions and 3 deletions

View File

@ -3,10 +3,12 @@ import { Map, TileLayer, ZoomControl, AttributionControl } from 'react-leaflet-u
import '../../node_modules/leaflet/dist/leaflet.css'
import './map.css'
import ThemeSwitcher from './theme-switcher';
import { parseCategoryURL } from '../parse';
import Legend from './legend';
import { HelpIcon } from './icons';
import Legend from './legend';
import { parseCategoryURL } from '../parse';
import SearchBox from './search-box';
import ThemeSwitcher from './theme-switcher';
const OS_API_KEY = 'NVUxtY5r8eA6eIfwrPTAGKrAAsoeI9E9';
@ -24,9 +26,18 @@ class ColouringMap extends Component {
zoom: 16
};
this.handleClick = this.handleClick.bind(this);
this.handleLocate = this.handleLocate.bind(this);
this.themeSwitch = this.themeSwitch.bind(this);
}
handleLocate(lat, lng, zoom){
this.setState({
lat: lat,
lng: lng,
zoom: zoom
})
}
handleClick(e) {
const is_edit = this.props.match.url.match('edit')
const mode = is_edit? 'edit': 'view';
@ -132,6 +143,11 @@ class ColouringMap extends Component {
}
<Legend slug={cat} />
<ThemeSwitcher onSubmit={this.themeSwitch} currentTheme={this.state.theme} />
{
this.props.match.url !== '/'? (
<SearchBox onLocate={this.handleLocate} is_building={is_building} />
) : null
}
</Fragment>
);
}

View File

@ -0,0 +1,29 @@
.search-box {
position: absolute;
top: 3.625rem;
left: 25.5rem;
z-index: 1000;
}
.building.search-box {
top: 0.5rem;
}
.search-box form,
.search-box .search-box-results {
border-radius: 4px;
background: #fff;
box-shadow: 0px 0px 1px 1px #222222;
}
.search-box button {
margin-bottom: 0;
}
.search-box .search-box-results {
margin-top: 0.25rem;
list-style: none;
padding: 0;
overflow: hidden;
}
.search-box-result {
display: block;
padding: 0.25rem 0.5rem;
border-bottom: 1px solid #eee;
}

View File

@ -0,0 +1,111 @@
import React, { Component } from 'react';
import './search-box.css';
/**
* Search for location
*/
class SearchBox extends Component {
constructor(props) {
super(props);
this.state = {
q: "",
results: [],
fetching: false
}
this.handleChange = this.handleChange.bind(this);
this.search = this.search.bind(this);
}
// Update search term
handleChange(e) {
this.setState({
q: e.target.value
})
}
// Query search endpoint
search(e) {
e.preventDefault();
this.setState({
fetching: true
})
fetch(
'/search?q='+this.state.q
).then(
(res) => res.json()
).then((data) => {
if (data && data.results){
this.setState({
results: data.results,
fetching: false
})
} else {
console.error(data);
this.setState({
results: [],
fetching: false
})
}
}).catch((err) => {
console.error(err)
this.setState({
results: [],
fetching: false
})
})
}
render() {
const resultsList = this.state.results.length?
<ul className="search-box-results">
{
this.state.results.map((result) => {
const label = result.attributes.label;
const lng = result.geometry.coordinates[0];
const lat = result.geometry.coordinates[1];
const zoom = result.attributes.zoom;
const href = `?lng=${lng}&lat=${lat}&zoom=${zoom}`
return (
<li key={result.attributes.label}>
<a
className="search-box-result"
onClick={(e) => {
e.preventDefault();
this.props.onLocate(lat, lng, zoom);
}}
href={href}
>{`${label.substring(0,4)} ${label.substring(4, 7)}`}</a>
</li>
)
})
}
</ul>
: null;
return (
<div className={`search-box ${this.props.is_building? "building" : ""}`}>
<form action="/search" method="GET" onSubmit={this.search}
class="form-inline">
<input
className="form-control"
type="search"
id="search-box-q"
name="q"
value={this.state.q}
placeholder="Search for a postcode"
aria-label="Search for a postcode"
onChange={this.handleChange}
/>
<button class="btn btn-outline-dark" type="submit">Search</button>
</form>
{ resultsList }
</div>
)
}
}
export default SearchBox;