Add postcode search box
This commit is contained in:
parent
2a676103ba
commit
f05fe3dba5
@ -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>
|
||||
);
|
||||
}
|
||||
|
29
app/src/frontend/search-box.css
Normal file
29
app/src/frontend/search-box.css
Normal 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;
|
||||
}
|
111
app/src/frontend/search-box.js
Normal file
111
app/src/frontend/search-box.js
Normal 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;
|
Loading…
Reference in New Issue
Block a user