2018-09-22 18:23:51 +00:00
|
|
|
import React, { Component } from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
import { compose, withStateHandlers } from 'recompose';
|
|
|
|
import {
|
|
|
|
withScriptjs,
|
|
|
|
withGoogleMap,
|
|
|
|
GoogleMap,
|
|
|
|
Marker,
|
|
|
|
InfoWindow
|
|
|
|
} from 'react-google-maps';
|
|
|
|
import { MarkerClusterer } from 'react-google-maps/lib/components/addons/MarkerClusterer';
|
|
|
|
|
|
|
|
// Custom Components
|
|
|
|
import LayerMapSwitches from './LayerMapSwitches';
|
|
|
|
|
|
|
|
// Helpers
|
|
|
|
import GOOGLE_MAPS_API from '../utils/constants';
|
|
|
|
import Client from '../utils/feathers';
|
2018-10-06 05:56:15 +00:00
|
|
|
import ClientMerchant from '../utils/feathers_merchants';
|
2018-09-22 18:23:51 +00:00
|
|
|
|
|
|
|
// Images
|
|
|
|
import MerchantPin from '../assets/img/map/merchant_pin.png';
|
|
|
|
import AmbassadorPin from '../assets/img/map/ambassador_pin.png';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This object is used for type checking the props of the component.
|
|
|
|
*/
|
|
|
|
const propTypes = {
|
|
|
|
ambassadors: PropTypes.array,
|
|
|
|
merchants: PropTypes.array,
|
|
|
|
mapCenter: PropTypes.object,
|
|
|
|
mapZoom: PropTypes.number,
|
|
|
|
// Fix google maps modal problem
|
|
|
|
showControls: PropTypes.bool
|
|
|
|
};
|
|
|
|
|
2018-10-06 05:56:15 +00:00
|
|
|
const locationObj = {"5b6235288b12017c6257536d":{"lat":30.274084,"lon":120.15507},"5b6235288b12017c6257536c":{"lat":-22.9697777,"lon":-43.1868592},"5b6235288b12017c625753b0":{"lat":37.9759033,"lon":22.9774589},"5b6235288b12017c6257538f":{"lat":37.9386365,"lon":22.9322383},"5b6235288b12017c6257536e":{"lat":37.9838096,"lon":23.7275388},"5b6235288b12017c62575372":{"lat":51.1078852,"lon":17.0385376},"5b6235288b12017c625753af":{"lat":50.0755381,"lon":14.4378005},"5b6235288b12017c62575368":{"lat":53.90453979999999,"lon":27.5615244},"5b6235288b12017c625753a9":{"lat":46.482526,"lon":30.7233095},"5b6235288b12017c625753ba":{"lat":42.2808256,"lon":-83.7430378},"5b6235288b12017c6257539a":{"lat":42.331427,"lon":-83.0457538},"5b6235288b12017c62575383":{"lat":55.947064,"lon":37.4992755},"5b6235288b12017c625753b6":{"lat":51.2980824,"lon":37.8379593},"5b6235288b12017c62575373":{"lat":51.2824173,"lon":37.5434951},"5b6235288b12017c625753b5":{"lat":53.4129429,"lon":59.00162330000001},"5b6235288b12017c62575369":{"lat":51.8857552,"lon":26.8427098},"5b6235288b12017c62575399":{"lat":50.6199,"lon":26.251617},"5b6235288b12017c62575374":{"lat":47.2357137,"lon":39.701505},"5b6235288b12017c6257538e":{"lat":45.8150108,"lon":15.9819189},"5b6235288b12017c62575370":{"lat":56.6511091,"lon":23.7213541},"5b6235288b12017c6257536f":{"lat":19.0759837,"lon":72.8776559},"5b6235288b12017c6257538b":{"lat":37.8043637,"lon":-122.2711137},"5b6235288b12017c6257539d":{"lat":32.715738,"lon":-117.1610838},"5b6235288b12017c6257537c":{"lat":-12.0463731,"lon":-77.042754},"5b6235288b12017c62575388":{"lat":48.574041,"lon":39.307815},"5b6235288b12017c62575377":{"lat":52.3679843,"lon":4.9035614},"5b6235288b12017c62575371":{"lat":47.0272282,"lon":28.8263789},"5b6235288b12017c625753a0":{"lat":53.3498053,"lon":-6.2603097},"5b6235288b12017c62575395":{"lat":43.60280789999999,"lon":39.7341543},"5b6235288b12017c62575398":{"lat":52.48624299999999,"lon":-1.890401},"5b6235288b12017c625753a1":{"lat":3.139003,"lon":101.686855},"5b6235288b12017c625753ad":{"lat":30.267153,"lon":-97.7430608},"5b6235288b12017c62575389":{"lat":33.7489954,"lon":-84.3879824},"5b6235288b12017c62575387":{"lat":13.7563309,"lon":100.5017651},"5b6235288b12017c625753b8":{"lat":58.587745,"lon":16.192421},"5b6235288b12017c6257537f":{"lat":36.4340533,"lon":28.2176379},"5b6235288b12017c62575391":{"lat":20.6596988,"lon":-103.3496092},"5b6235288b12017c62575390":{"lat":40.9875181,"lon":14.1640355},"5b6235288b12017c625753a3":{"lat":39.74953310000001,"lon":-8.807682999999999},"5b6235288b12017c625753a5":{"lat":59.9342802,"lon":30.3350986},"5b6235288b12017c62575367":{"lat":52.4411761,"lon":30.9878461},"5b6235288b12017c6257538c":{"lat":53.07929619999999,"lon":8.8016936},"5b6235288b12017c6257536b":{"lat":43.653226,"lon":-79.3831843},"5b6235288b12017c625753bc":{"lat":26.1420358,"lon":-81.7948103},"5b6235288b12017c625753ac":{"lat":27.3364347,"lon":-82.53065269999999},"5b6235288b12017c6257538a":{"lat":26.640628,"lon":-81.8723084},"5b6235288b12017c625753b9":{"lat":50.4501,"lon":30.5234},"5b6235288b12017c6257539b":{"lat":44.977753,"lon":-93.2650108},"5b6235288b12017c6257536a":{"lat":-22.8858975,"lon":-43.1152211},"5b6235288b12017c625753a2":{"lat":47.88639879999999,"lon":106.9057439},"5b6235288b12017c62575384":{"lat":55.755826,"lon":37.6172999},"5b6235288b12017c6257537b":{"lat":40.7607793,"lon":-111.8910474},"5b6235288b12017c62575366":{"lat":40.40926169999999,"lon":49.8670924},"5b6235288b12017c62575378":{"lat":48.379433,"lon":31.1655799},"5b6235288b12017c6257539c":{"lat":44.7971939,"lon":-106.9561791},"5b6235288b12017c6257539e":{"lat":9.9906919,"lon":-84.667374},"5b64aa4636a1605e5268e731":{"lat":4.710988599999999,"lon":-74.072092},"5b6235288b12017c625753a4":{"lat":54.7104264,"lon":20.4522144},"5b6235288b12017c625753b1":{"lat":35.6894875,"lon":139.6917064},"5b6235288b12017c62575382":{"lat":14.5995124,"lon":120.9842195},"5b6235288b12017c625753a8":{"lat":36.8064948,"lon":10.1815316},"5b6235288b12017c6257537d":{"lat":49.2827291,"lon":-123.1207375},"5b6235288b12017c625753b3":{"lat":33.6844202,"lon":73.04788479999999},"5b6235288b12017c625753
|
|
|
|
|
2018-09-22 18:23:51 +00:00
|
|
|
/**
|
|
|
|
* This object sets default values to the optional props.
|
|
|
|
*/
|
|
|
|
const defaultProps = {
|
|
|
|
mapCenter: { lat: -22.9068, lng: -43.1729 },
|
|
|
|
mapZoom: 12,
|
|
|
|
googleMapURL:
|
|
|
|
`https://maps.googleapis.com/maps/api/js?key=${GOOGLE_MAPS_API}&v=3.exp&libraries=geometry,drawing,places`,
|
|
|
|
loadingElement: <div style={{ height: `100%` }} />,
|
|
|
|
containerElement: <div style={{ height: `100%` }} />,
|
|
|
|
mapElement: <div style={{ height: `400px` }} />,
|
|
|
|
// Fix google maps modal problem
|
|
|
|
showControls: true,
|
|
|
|
};
|
|
|
|
defaultProps['markers'] = [
|
|
|
|
defaultProps.mapCenter
|
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Map that support Merchant Layer Markers and Ambassadors Layer Markers.
|
|
|
|
*/
|
|
|
|
const CustomLayerMap = compose(
|
|
|
|
withStateHandlers(() => ({
|
|
|
|
isOpenObj: {},
|
|
|
|
isOpenAmbassadorObj:{}
|
|
|
|
}), {
|
|
|
|
onToggleOpen: ({ isOpenObj }) => (index) => {
|
|
|
|
const openObj = isOpenObj;
|
|
|
|
openObj[index] = !openObj[index];
|
|
|
|
return openObj;
|
|
|
|
},
|
|
|
|
onToggleAmbassadorOpen: ({ isOpenAmbassadorObj }) => (index) => {
|
|
|
|
const openObj = isOpenAmbassadorObj;
|
|
|
|
openObj[index] = !openObj[index];
|
|
|
|
return openObj;
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
withScriptjs,
|
|
|
|
withGoogleMap
|
|
|
|
)(props =>
|
|
|
|
<GoogleMap
|
|
|
|
defaultZoom={props.mapZoom}
|
|
|
|
defaultCenter={props.mapCenter}
|
|
|
|
>
|
|
|
|
<MarkerClusterer
|
|
|
|
averageCenter
|
|
|
|
enableRetinaIcons
|
|
|
|
gridSize={60}
|
|
|
|
zoomOnClick={true}
|
|
|
|
imagePath='http://www.luminiasoft.com/images/merchant_cluster'
|
|
|
|
>
|
|
|
|
{props.ambassadors.map( (marker, index) => (
|
|
|
|
marker.withInfo ? (
|
|
|
|
<Marker
|
|
|
|
key={index}
|
|
|
|
position={{ lat: marker.lat, lng: marker.lng }}
|
|
|
|
icon={AmbassadorPin}
|
|
|
|
onClick={() => props.onToggleOpen(index)}
|
|
|
|
>
|
|
|
|
{props.isOpenObj[index] && <InfoWindow onCloseClick={() => props.onToggleOpen(index)}>
|
|
|
|
<div>
|
|
|
|
<div style={{ font: "bold 16px Georgia, serif" }}>{marker.infoTitle}</div>
|
|
|
|
<br />
|
|
|
|
<div style={{ font: "14px Georgia, serif" }}>{marker.infoDescription}</div>
|
|
|
|
</div>
|
|
|
|
</InfoWindow>}
|
|
|
|
</Marker>
|
|
|
|
) : (
|
|
|
|
<Marker
|
|
|
|
key={index}
|
|
|
|
position={{ lat: marker.lat, lng: marker.lng }}
|
|
|
|
icon={AmbassadorPin}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
))}
|
|
|
|
</MarkerClusterer>
|
|
|
|
<MarkerClusterer
|
|
|
|
averageCenter
|
|
|
|
enableRetinaIcons
|
|
|
|
gridSize={60}
|
|
|
|
zoomOnClick={true}
|
|
|
|
imagePath='http://www.luminiasoft.com/images/ambassador_cluster'
|
|
|
|
>
|
|
|
|
{props.merchants.map( (marker, index) => (
|
|
|
|
marker.withInfo ? (
|
|
|
|
<Marker
|
|
|
|
key={index}
|
|
|
|
position={{ lat: marker.lat, lng: marker.lng }}
|
|
|
|
icon={MerchantPin}
|
|
|
|
onClick={() => props.onToggleAmbassadorOpen(index)}
|
|
|
|
>
|
|
|
|
{props.isOpenAmbassadorObj[index] && <InfoWindow onCloseClick={() => props.onToggleAmbassadorOpen(index)}>
|
|
|
|
<div>
|
|
|
|
<div style={{ font: "bold 16px Georgia, serif" }}>{marker.infoTitle}</div>
|
|
|
|
<br />
|
|
|
|
<div style={{ font: "14px Georgia, serif" }}>{marker.infoDescription}</div>
|
|
|
|
</div>
|
|
|
|
</InfoWindow>}
|
|
|
|
</Marker>
|
|
|
|
) : (
|
|
|
|
<Marker
|
|
|
|
key={index}
|
|
|
|
position={{ lat: marker.lat, lng: marker.lng }}
|
|
|
|
icon={MerchantPin}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
))}
|
|
|
|
</MarkerClusterer>
|
|
|
|
</GoogleMap>
|
|
|
|
);
|
|
|
|
|
|
|
|
// Type checking the props of the component
|
|
|
|
CustomLayerMap.propTypes = propTypes;
|
|
|
|
// Assign default values to the optional props
|
|
|
|
CustomLayerMap.defaultProps = defaultProps;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This object is used for type checking the props of the component.
|
|
|
|
*/
|
|
|
|
const propTypesLayerMap = {
|
|
|
|
ambassadorsLayer: PropTypes.bool,
|
|
|
|
merchantsLayer: PropTypes.bool,
|
|
|
|
showControls: PropTypes.bool,
|
|
|
|
mapHeight: PropTypes.string
|
|
|
|
};
|
|
|
|
|
|
|
|
class LayerMap extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
ambassadors: [],
|
|
|
|
merchants: [],
|
|
|
|
ambassadorLayer: this.props.ambassadorsLayer,
|
|
|
|
merchantLayer: this.props.merchantsLayer
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @description Lifecycle event handler called just after the App loads into the DOM.
|
|
|
|
*/
|
|
|
|
UNSAFE_componentWillMount() {
|
|
|
|
this.getAmbassadors();
|
|
|
|
this.getMerchants();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @description Get the ambassadors list from the web service.
|
|
|
|
* @param {string} id - Merchant ID.
|
|
|
|
*/
|
|
|
|
getAmbassadors = () => {
|
|
|
|
const app = this;
|
|
|
|
const ambassadors = Client.service('api/v1/ambassadors');
|
|
|
|
|
|
|
|
this.setState({loading: true});
|
|
|
|
|
|
|
|
ambassadors.find().then( (results) => {
|
|
|
|
const markers = results.data.map(ambassador => {
|
2018-10-06 05:56:15 +00:00
|
|
|
if(locationObj[ambassador.cityId]){
|
2018-09-22 18:23:51 +00:00
|
|
|
const marker = {
|
2018-10-06 05:56:15 +00:00
|
|
|
lat: locationObj[ambassador.cityId].lat,
|
|
|
|
lng: locationObj[ambassador.cityId].lon,
|
2018-09-22 18:23:51 +00:00
|
|
|
withInfo: true,
|
|
|
|
infoTitle: ambassador.nickname,
|
|
|
|
infoDescription: `${ambassador.city} - ${ambassador.country}`,
|
|
|
|
};
|
|
|
|
return marker;
|
2018-10-06 05:56:15 +00:00
|
|
|
}
|
2018-09-22 18:23:51 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// Once both return, update the state
|
|
|
|
app.setState({
|
|
|
|
ambassadors: markers,
|
|
|
|
loading: false
|
|
|
|
});
|
|
|
|
}).catch( error => {
|
|
|
|
app.setState({responseError: error.message, loading: false});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @description Get the merchants list from the web service.
|
|
|
|
* @param {string} id - Merchant ID.
|
|
|
|
*/
|
|
|
|
getMerchants = () => {
|
|
|
|
const app = this;
|
2018-10-06 05:56:15 +00:00
|
|
|
const merchants = ClientMerchant.service('api/v1/merchants');
|
2018-09-22 18:23:51 +00:00
|
|
|
|
|
|
|
this.setState({loading: true});
|
|
|
|
|
|
|
|
merchants.find().then( (results) => {
|
|
|
|
const markers = results.data.map(merchant => {
|
|
|
|
const marker = {
|
|
|
|
lat: merchant.lat,
|
|
|
|
lng: merchant.lon,
|
|
|
|
withInfo: true,
|
|
|
|
infoTitle: merchant.name,
|
|
|
|
infoDescription: `${merchant.address}, ${merchant.city} - ${merchant.country}`,
|
|
|
|
};
|
|
|
|
return marker;
|
|
|
|
});
|
|
|
|
|
|
|
|
// Once both return, update the state
|
|
|
|
app.setState({
|
|
|
|
merchants: markers,
|
|
|
|
loading: false
|
|
|
|
});
|
|
|
|
}).catch( error => {
|
|
|
|
app.setState({responseError: error.message, loading: false});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
handleLayerChange = name => event => {
|
|
|
|
this.setState({ [name]: event.target.checked });
|
|
|
|
// Update any time changes
|
|
|
|
this.getAmbassadors();
|
|
|
|
this.getMerchants();
|
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
|
|
|
// create an array with marker components
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
{!this.props.showControls ? (
|
|
|
|
<LayerMapSwitches
|
|
|
|
ambassadors={this.state.ambassadorLayer}
|
|
|
|
merchants={this.state.merchantLayer}
|
2018-09-28 07:10:44 +00:00
|
|
|
ambsMap={this.props.ambsMap}
|
2018-09-22 18:23:51 +00:00
|
|
|
onChange={this.handleLayerChange}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<div style={{ height: 56 }}></div>
|
|
|
|
)}
|
|
|
|
<CustomLayerMap
|
|
|
|
ambassadors={this.state.ambassadorLayer ? this.state.ambassadors: []}
|
|
|
|
merchants={this.state.merchantLayer ? this.state.merchants: []}
|
|
|
|
mapZoom={3}
|
|
|
|
mapCenter={{ lat: 0, lng: 0 }}
|
|
|
|
loadingElement={<div style={{ height: `100%` }} />}
|
|
|
|
containerElement={<div style={{ height: `100%` }} />}
|
|
|
|
mapElement={<div style={{ height: this.props.mapHeight ? this.props.mapHeight: '400px' }} />}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Type checking the props of the component
|
|
|
|
LayerMap.propTypes = propTypesLayerMap;
|
|
|
|
|
|
|
|
export default LayerMap;
|