Created
October 10, 2019 16:38
-
-
Save YarikST/67b124c817b70e4e5f8e26b52b802455 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#More detali safepal and mobstar | |
google api key - https://developers.google.com/maps/documentation/javascript/get-api-key | |
doc - https://github.com/tomchentw/react-google-maps | |
//--authorization | |
import React from "react" | |
import { compose, withProps } from "recompose" | |
import { withScriptjs, withGoogleMap } from "react-google-maps" | |
export default Map => | |
compose( | |
withProps({ | |
googleMapURL: `https://maps.googleapis.com/maps/api/js?key=${document.querySelector('meta[name="google_maps_key"]').content}&v=3.exp&libraries=geometry,drawing,places`, | |
loadingElement: <div style={{ height: `100%` }} />, | |
containerElement: <div style={{ height: `600px` }} />, | |
mapElement: <div style={{ height: `100%` }} />, | |
}), | |
withScriptjs, | |
withGoogleMap | |
)((props) => | |
<Map | |
defaultZoom={16} | |
defaultCenter = {{ | |
lat: -1.2884, | |
lng: 36.8233 | |
}} | |
{...props} | |
/> | |
) | |
//--track you location | |
import React from "react" | |
import { compose, withState, lifecycle } from "recompose" | |
export default CurrentLocation => | |
compose( | |
withState('currentLocation', 'setCurrentLocation'), | |
lifecycle({ | |
componentDidMount() { | |
console.log('CurrentLocation componentDidMount'); | |
if (navigator.geolocation) { | |
navigator.geolocation.getCurrentPosition((position) =>{ | |
let location = { | |
lat: position.coords.latitude, | |
lng: position.coords.longitude | |
}; | |
this.props.setCurrentLocation(location); | |
}, ()=>{ | |
console.log('Error: The Geolocation service failed.') | |
}); | |
} else { | |
console.log('Error: Your browser doesn\'t support geolocation.') | |
} | |
} | |
}) | |
)((props)=> | |
<CurrentLocation | |
{...props} | |
/> | |
) | |
//-- first component MapMarker | |
import React from "react" | |
import { compose, withProps, withHandlers, withState, lifecycle } from "recompose" | |
import { GoogleMap, Marker } from "react-google-maps" | |
import SearchBox from "react-google-maps/lib/components/places/SearchBox"; | |
import GoogleApiWrapper from './api' | |
import GoogleCurrentLocationWrapper from './current-location' | |
const styles={ | |
deleteMarker:{ | |
position: 'relative', | |
top: 0, | |
left: 0, | |
zIndex: 5 | |
} | |
} | |
const MapMarker = compose( | |
withState('bounds', 'setBounds'), | |
withState('zoom', 'setZoom', 16), | |
withHandlers(()=> { | |
const refs = { | |
map: undefined, | |
} | |
return { | |
onMapMounted: ()=> ref=> { | |
refs.map = ref | |
}, | |
onMarkerMounted: () => ref => { | |
refs.marker = ref | |
}, | |
onSearchBoxMounted: ()=> ref => { | |
refs.searchBox = ref; | |
}, | |
onBoundsChanged: (props)=> () => { | |
props.setBounds(refs.map.getBounds()) | |
}, | |
onPlacesChanged: ()=> ()=> { | |
const places = refs.searchBox.getPlaces(); | |
const bounds = new google.maps.LatLngBounds(); | |
places.forEach(place => { | |
if (place.geometry.viewport) { | |
bounds.union(place.geometry.viewport) | |
} else { | |
bounds.extend(place.geometry.location) | |
} | |
}); | |
refs.map.fitBounds(bounds); | |
refs.map.panToBounds(bounds); | |
}, | |
onMapClick: (props)=> (event)=>{ | |
const markerPosition = { | |
lat: event.latLng.lat(), | |
lng: event.latLng.lng() | |
}; | |
console.log('onMapClick', markerPosition); | |
props.onChange && props.onChange(markerPosition); | |
if(props.onChangeAddress){ | |
new google.maps.Geocoder().geocode({'location': event.latLng}, (results, status) => { | |
let address = ''; | |
if (status === 'OK') { | |
if (results[0]) { | |
address = results[0].formatted_address; | |
} else { | |
console.log('No results found'); | |
} | |
} else { | |
console.log('Geocoder failed due to: ' + status); | |
} | |
props.onChangeAddress(address); | |
}) | |
} | |
}, | |
deleteMarker: (props)=> ()=>{ | |
props.onChange && props.onChange(null); | |
props.onChangeAddress && props.onChangeAddress(''); | |
}, | |
onLoad: (props)=> ()=>{ | |
if(props.markerPosition || props.currentLocation){ | |
const bounds = new google.maps.LatLngBounds(); | |
bounds.extend(props.markerPosition || props.currentLocation); | |
refs.map.fitBounds(bounds); | |
refs.map.panToBounds(bounds); | |
} | |
} | |
} | |
}), | |
lifecycle({ | |
componentDidMount() { | |
this.props.onLoad() | |
}, | |
componentDidUpdate(prevProps, prevState){ | |
((this.props.markerPosition && !prevProps.markerPosition) || | |
(this.props.markerPosition && this.props.markerPosition.lat != prevProps.markerPosition.lat && this.props.markerPosition.lng != prevProps.markerPosition.lng) || | |
(this.props.currentLocation && !prevProps.currentLocation && !this.props.markerPosition) | |
) | |
&& this.props.onLoad() | |
} | |
}) | |
)((props)=> | |
<GoogleMap | |
ref={props.onMapMounted} | |
defaultCenter = {props.defaultCenter} | |
defaultZoom = {props.defaultZoom} | |
onBoundsChanged={props.onBoundsChanged} | |
zoom={props.zoom} | |
onClick={props.onMapClick} | |
> | |
<SearchBox | |
ref={props.onSearchBoxMounted} | |
bounds={props.bounds} | |
controlPosition={google.maps.ControlPosition.TOP_LEFT} | |
onPlacesChanged={props.onPlacesChanged} | |
> | |
<input | |
type="text" | |
placeholder="Search" | |
style={{ | |
boxSizing: `border-box`, | |
border: `1px solid transparent`, | |
width: `240px`, | |
height: `32px`, | |
marginTop: `16px`, | |
padding: `0 12px`, | |
borderRadius: `3px`, | |
boxShadow: `0 2px 6px rgba(0, 0, 0, 0.3)`, | |
fontSize: `14px`, | |
outline: `none`, | |
textOverflow: `ellipses`, | |
color: 'black' | |
}} | |
/> | |
</SearchBox> | |
{ | |
props.markerPosition != null ? | |
<Marker | |
ref={props.onMarkerMounted} | |
position={props.markerPosition} | |
/> | |
: | |
null | |
} | |
{ | |
(props.markerPosition != null && props.onChange != null) ? | |
<input | |
style={styles.deleteMarker} | |
onClick={props.deleteMarker} | |
type="button" | |
value="Delete Marker" | |
/> | |
: | |
null | |
} | |
</GoogleMap> | |
) | |
export default compose( | |
GoogleApiWrapper, | |
GoogleCurrentLocationWrapper | |
)(MapMarker) | |
module ApplicationHelper | |
def meta_tag(tag, text) | |
content_for :"meta_#{tag}", text | |
end | |
def yield_meta_tag(tag, default_text='') | |
content_for?(:"meta_#{tag}") ? content_for(:"meta_#{tag}") : default_text | |
end | |
end | |
module ValidationHelper | |
UNICODE_TEXT = /\A([\p{L}\p{P}\d\s])+\z/ | |
end | |
<% meta_tag :google_maps_key, "key" %> | |
<meta name='google_maps_key' | |
content='<%= yield_meta_tag(:google_maps_key, 'invalid_key') %>' /> | |
validates :latitude, | |
numericality: { | |
message: "Latitude must be numericality", | |
allow_blank: true, | |
greater_than_or_equal_to: -90, | |
less_than_or_equal_to: 90, | |
} | |
validates :longitude, | |
numericality: { | |
message: "Longitude must be numericality", | |
allow_blank: true, | |
greater_than_or_equal_to: -180, | |
less_than_or_equal_to: 180, | |
} | |
validates :address, | |
presence: {message: 'Address can\'t be blank.', if: -> {latitude.present? && longitude.present?}}, | |
length: {maximum: 100, message: "Address must be in range", allow_blank: true}, | |
format: {with: ValidationHelper::UNICODE_TEXT, message: "Incorrect format of the address", allow_blank: true} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment