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