366 lines
9.2 KiB
JavaScript
366 lines
9.2 KiB
JavaScript
import Cookies from "js-cookie";
|
|
import React, { Component } from "react";
|
|
import Geocode from "react-geocode";
|
|
import Autocomplete from "react-google-autocomplete";
|
|
import {
|
|
GoogleMap,
|
|
InfoWindow,
|
|
Marker,
|
|
withGoogleMap,
|
|
withScriptjs,
|
|
} from "react-google-maps";
|
|
import { GoogleMapsAPI } from "./client-config";
|
|
|
|
Geocode.setApiKey(GoogleMapsAPI);
|
|
Geocode.enableDebug();
|
|
|
|
class Map extends Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.state = {
|
|
address: "",
|
|
city: "",
|
|
area: "",
|
|
state: "",
|
|
mapPosition: {
|
|
lat: this.props.center.lat,
|
|
lng: this.props.center.lng,
|
|
},
|
|
markerPosition: {
|
|
lat: this.props.center.lat,
|
|
lng: this.props.center.lng,
|
|
},
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get the current address from the default map position and set those values in the state
|
|
*/
|
|
componentDidMount() {
|
|
Geocode.fromLatLng(
|
|
this.state.mapPosition.lat,
|
|
this.state.mapPosition.lng,
|
|
).then(
|
|
(response) => {
|
|
const address = response.results[0].formatted_address;
|
|
const addressArray = response.results[0].address_components;
|
|
const city = this.getCity(addressArray);
|
|
const area = this.getArea(addressArray);
|
|
const state = this.getState(addressArray);
|
|
|
|
console.log("city", city, area, state);
|
|
|
|
this.setState({
|
|
address: address || "",
|
|
area: area || "",
|
|
city: city || "",
|
|
state: state || "",
|
|
});
|
|
},
|
|
(error) => {
|
|
console.error(error);
|
|
},
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Component should only update ( meaning re-render ), when the user selects the address, or drags the pin
|
|
*
|
|
* @param nextProps
|
|
* @param nextState
|
|
* @return {boolean}
|
|
*/
|
|
shouldComponentUpdate(nextProps, nextState) {
|
|
if (
|
|
this.state.markerPosition.lat !== this.props.center.lat ||
|
|
this.state.address !== nextState.address ||
|
|
this.state.city !== nextState.city ||
|
|
this.state.area !== nextState.area ||
|
|
this.state.state !== nextState.state
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
if (this.props.center.lat == nextProps.center.lat) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the city and set the city input value to the one selected
|
|
*
|
|
* @param addressArray
|
|
* @return {string}
|
|
*/
|
|
getCity = (addressArray) => {
|
|
let city = "";
|
|
|
|
for (const element of addressArray) {
|
|
if (
|
|
element.types[0] &&
|
|
element.types[0] == "administrative_area_level_2"
|
|
) {
|
|
city = element.long_name;
|
|
return city;
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Get the area and set the area input value to the one selected
|
|
*
|
|
* @param addressArray
|
|
* @return {string}
|
|
*/
|
|
getArea = (addressArray) => {
|
|
let area = "";
|
|
|
|
for (const element of addressArray) {
|
|
if (element.types[0]) {
|
|
for (let j = 0; j < element.types.length; j++) {
|
|
if (
|
|
element.types[j] == "sublocality_level_1" ||
|
|
element.types[j] == "locality"
|
|
) {
|
|
area = element.long_name;
|
|
return area;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* Get the address and set the address input value to the one selected
|
|
*
|
|
* @param addressArray
|
|
* @return {string}
|
|
*/
|
|
getState = (addressArray) => {
|
|
let state = "";
|
|
|
|
for (let i = 0; i < addressArray.length; i++) {
|
|
for (const element of addressArray) {
|
|
if (
|
|
element.types[0] &&
|
|
element.types[0] == "administrative_area_level_1"
|
|
) {
|
|
state = element.long_name;
|
|
return state;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
/**
|
|
* And function for city,state and address input
|
|
* @param event
|
|
*/
|
|
onChange = (event) => {
|
|
this.setState({
|
|
[event.target.name]: event.target.value,
|
|
});
|
|
};
|
|
/**
|
|
* This Event triggers when the marker window is closed
|
|
*
|
|
* @param event
|
|
*/
|
|
onInfoWindowClose = () => {};
|
|
/**
|
|
* When the marker is dragged you get the lat and long using the functions available from event object.
|
|
* Use geocode to get the address, city, area and state from the lat and lng positions.
|
|
* And then set those values in the state.
|
|
*
|
|
* @param event
|
|
*/
|
|
onMarkerDragEnd = (event) => {
|
|
const newLat = event.latLng.lat();
|
|
const newLng = event.latLng.lng();
|
|
|
|
Geocode.fromLatLng(newLat, newLng).then(
|
|
(response) => {
|
|
const address = response.results[0].formatted_address;
|
|
const addressArray = response.results[0].address_components;
|
|
const city = this.getCity(addressArray);
|
|
const area = this.getArea(addressArray);
|
|
const state = this.getState(addressArray);
|
|
|
|
this.setState({
|
|
address: address || "",
|
|
area: area || "",
|
|
city: city || "",
|
|
state: state || "",
|
|
markerPosition: {
|
|
lat: newLat,
|
|
lng: newLng,
|
|
},
|
|
mapPosition: {
|
|
lat: newLat,
|
|
lng: newLng,
|
|
},
|
|
});
|
|
Cookies.set("map_lat", `${newLat}`, {
|
|
expires: 1
|
|
});
|
|
Cookies.set("map_long", `${newLng}`, {
|
|
expires: 1
|
|
});
|
|
$(".input-location-schedule").val(address);
|
|
},
|
|
(error) => {
|
|
console.error(error);
|
|
},
|
|
);
|
|
};
|
|
/**
|
|
* When the user types an address in the search box
|
|
* @param place
|
|
*/
|
|
onPlaceSelected = (place) => {
|
|
console.log("plc", place);
|
|
const address = place.formatted_address;
|
|
const addressArray = place.address_components;
|
|
const city = this.getCity(addressArray);
|
|
const area = this.getArea(addressArray);
|
|
const state = this.getState(addressArray);
|
|
const latValue = place.geometry.location.lat();
|
|
const lngValue = place.geometry.location.lng();
|
|
|
|
// Set these values in the state.
|
|
this.setState({
|
|
address: address || "",
|
|
area: area || "",
|
|
city: city || "",
|
|
state: state || "",
|
|
markerPosition: {
|
|
lat: latValue,
|
|
lng: lngValue,
|
|
},
|
|
mapPosition: {
|
|
lat: latValue,
|
|
lng: lngValue,
|
|
},
|
|
});
|
|
Cookies.set("map_lat", `${latValue}`, {
|
|
expires: 1
|
|
});
|
|
Cookies.set("map_long", `${lngValue}`, {
|
|
expires: 1
|
|
});
|
|
$(".input-location-schedule").val(address);
|
|
};
|
|
render() {
|
|
const AsyncMap = withScriptjs(
|
|
withGoogleMap(() => (
|
|
<GoogleMap
|
|
google={this.props.google}
|
|
defaultZoom={this.props.zoom}
|
|
defaultCenter={{
|
|
lat: this.state.mapPosition.lat,
|
|
lng: this.state.mapPosition.lng,
|
|
}}
|
|
>
|
|
<Autocomplete
|
|
style={{
|
|
width: "100%",
|
|
height: "40px",
|
|
paddingLeft: "16px",
|
|
marginTop: "2px",
|
|
marginBottom: "500px",
|
|
}}
|
|
onPlaceSelected={this.onPlaceSelected}
|
|
options={{
|
|
types: ["geocode"],
|
|
}}
|
|
/>
|
|
{/* InfoWindow on top of marker */}
|
|
<InfoWindow
|
|
onClose={this.onInfoWindowClose}
|
|
position={{
|
|
lat: this.state.markerPosition.lat + 0.0018,
|
|
lng: this.state.markerPosition.lng,
|
|
}}
|
|
>
|
|
<div>
|
|
<span
|
|
style={{
|
|
padding: 0,
|
|
margin: 0,
|
|
}}
|
|
>
|
|
{this.state.address}
|
|
</span>
|
|
</div>
|
|
</InfoWindow>
|
|
{/* Marker */}
|
|
<Marker
|
|
google={this.props.google}
|
|
name="Dolores park"
|
|
draggable={this.props.draggable}
|
|
onDragEnd={this.onMarkerDragEnd}
|
|
position={{
|
|
lat: this.state.markerPosition.lat,
|
|
lng: this.state.markerPosition.lng,
|
|
}}
|
|
/>
|
|
<Marker />
|
|
{/* For Auto complete Search Box */}
|
|
</GoogleMap>
|
|
)),
|
|
);
|
|
|
|
let map;
|
|
|
|
if (this.props.center.lat == undefined) {
|
|
map = (
|
|
<div
|
|
style={{
|
|
height: this.props.height,
|
|
}}
|
|
/>
|
|
);
|
|
} else {
|
|
map = (
|
|
<div>
|
|
{/* <div>
|
|
<div className="form-group">
|
|
<label htmlFor="">Address</label>
|
|
<input type="text" name="address" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.address }/>
|
|
</div>
|
|
<div className="form-group">
|
|
<label htmlFor="">All Data</label>
|
|
<input type="text" name="address" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.markerPosition.lat + ";" + this.state.markerPosition.lng }/>
|
|
</div>
|
|
</div> */}
|
|
<AsyncMap
|
|
googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${GoogleMapsAPI}&libraries=places`}
|
|
loadingElement={
|
|
<div
|
|
style={{
|
|
height: "100%",
|
|
}}
|
|
/>
|
|
}
|
|
containerElement={
|
|
<div
|
|
style={{
|
|
height: this.props.height,
|
|
}}
|
|
/>
|
|
}
|
|
mapElement={
|
|
<div
|
|
style={{
|
|
height: "100%",
|
|
}}
|
|
/>
|
|
}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return map;
|
|
}
|
|
}
|
|
|
|
export default Map;
|