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';
|
|
|
|
|
2018-12-03 15:26:15 +00:00
|
|
|
// Helpers
|
|
|
|
import Client from '../utils/feathers';
|
|
|
|
import { stripProtocol } from '../utils/url';
|
|
|
|
import Countries from 'country-list';
|
|
|
|
|
2018-09-22 18:23:51 +00:00
|
|
|
// Custom Components
|
|
|
|
import LayerMapSwitches from './LayerMapSwitches';
|
|
|
|
|
|
|
|
// Helpers
|
2018-12-03 15:26:15 +00:00
|
|
|
import { GOOGLE_MAPS_API } from '../utils/constants';
|
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';
|
2018-12-03 15:26:15 +00:00
|
|
|
import TellerPin from '../assets/img/map/teller_pin.png';
|
2018-09-22 18:23:51 +00:00
|
|
|
|
2018-11-05 21:02:50 +00:00
|
|
|
import ambs_m1 from '../assets/img/map/cluster/ambassadors/m1.png';
|
|
|
|
import ambs_m2 from '../assets/img/map/cluster/ambassadors/m2.png';
|
|
|
|
import ambs_m3 from '../assets/img/map/cluster/ambassadors/m3.png';
|
|
|
|
import ambs_m4 from '../assets/img/map/cluster/ambassadors/m4.png';
|
|
|
|
import ambs_m5 from '../assets/img/map/cluster/ambassadors/m5.png';
|
|
|
|
|
|
|
|
import mer_m1 from '../assets/img/map/cluster/merchants/m1.png';
|
|
|
|
import mer_m2 from '../assets/img/map/cluster/merchants/m2.png';
|
|
|
|
import mer_m3 from '../assets/img/map/cluster/merchants/m3.png';
|
|
|
|
import mer_m4 from '../assets/img/map/cluster/merchants/m4.png';
|
|
|
|
import mer_m5 from '../assets/img/map/cluster/merchants/m5.png';
|
|
|
|
|
2018-12-03 15:26:15 +00:00
|
|
|
import tel_m1 from '../assets/img/map/cluster/tellers/m1.png';
|
|
|
|
import tel_m2 from '../assets/img/map/cluster/tellers/m2.png';
|
|
|
|
import tel_m3 from '../assets/img/map/cluster/tellers/m3.png';
|
|
|
|
import tel_m4 from '../assets/img/map/cluster/tellers/m4.png';
|
|
|
|
import tel_m5 from '../assets/img/map/cluster/tellers/m5.png';
|
|
|
|
|
2019-01-15 02:23:41 +00:00
|
|
|
import { addProtocol, getProtocol } from '../utils/url';
|
|
|
|
|
|
|
|
import { WHICH_OPTIONS } from '../utils/constants';
|
|
|
|
|
2018-12-03 15:26:15 +00:00
|
|
|
// List of countries
|
|
|
|
const countries = Countries();
|
|
|
|
|
2018-09-22 18:23:51 +00:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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,
|
2018-12-03 15:26:15 +00:00
|
|
|
ambassadors: [],
|
|
|
|
merchants: [],
|
|
|
|
tellers: []
|
2018-09-22 18:23:51 +00:00
|
|
|
};
|
|
|
|
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}
|
2018-11-05 21:02:50 +00:00
|
|
|
styles={[
|
|
|
|
{
|
|
|
|
url: ambs_m1,
|
|
|
|
height: 53,
|
|
|
|
lineHeight: 53,
|
|
|
|
width: 53,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: ambs_m2,
|
|
|
|
height: 56,
|
|
|
|
lineHeight: 56,
|
|
|
|
width: 56,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: ambs_m3,
|
|
|
|
height: 66,
|
|
|
|
lineHeight: 66,
|
|
|
|
width: 66,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: ambs_m4,
|
|
|
|
height: 78,
|
|
|
|
lineHeight: 78,
|
|
|
|
width: 78,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: ambs_m5,
|
|
|
|
height: 90,
|
|
|
|
lineHeight: 90,
|
|
|
|
width: 90,
|
|
|
|
},
|
|
|
|
]}
|
2018-09-22 18:23:51 +00:00
|
|
|
>
|
|
|
|
{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>
|
2018-12-03 15:26:15 +00:00
|
|
|
|
2018-09-22 18:23:51 +00:00
|
|
|
<MarkerClusterer
|
|
|
|
averageCenter
|
|
|
|
enableRetinaIcons
|
|
|
|
gridSize={60}
|
|
|
|
zoomOnClick={true}
|
2018-11-05 21:02:50 +00:00
|
|
|
styles={[
|
|
|
|
{
|
|
|
|
url: mer_m1,
|
|
|
|
height: 53,
|
|
|
|
lineHeight: 53,
|
|
|
|
width: 53,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: mer_m2,
|
|
|
|
height: 56,
|
|
|
|
lineHeight: 56,
|
|
|
|
width: 56,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: mer_m3,
|
|
|
|
height: 66,
|
|
|
|
lineHeight: 66,
|
|
|
|
width: 66,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: mer_m4,
|
|
|
|
height: 78,
|
|
|
|
lineHeight: 78,
|
|
|
|
width: 78,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: mer_m5,
|
|
|
|
height: 90,
|
|
|
|
lineHeight: 90,
|
|
|
|
width: 90,
|
|
|
|
},
|
|
|
|
]}
|
2018-09-22 18:23:51 +00:00
|
|
|
>
|
|
|
|
{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>
|
2018-12-03 15:26:15 +00:00
|
|
|
|
|
|
|
<MarkerClusterer
|
|
|
|
averageCenter
|
|
|
|
enableRetinaIcons
|
|
|
|
gridSize={60}
|
|
|
|
zoomOnClick={true}
|
|
|
|
styles={[
|
|
|
|
{
|
|
|
|
url: tel_m1,
|
|
|
|
height: 53,
|
|
|
|
lineHeight: 53,
|
|
|
|
width: 53,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: tel_m2,
|
|
|
|
height: 56,
|
|
|
|
lineHeight: 56,
|
|
|
|
width: 56,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: tel_m3,
|
|
|
|
height: 66,
|
|
|
|
lineHeight: 66,
|
|
|
|
width: 66,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: tel_m4,
|
|
|
|
height: 78,
|
|
|
|
lineHeight: 78,
|
|
|
|
width: 78,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
url: tel_m5,
|
|
|
|
height: 90,
|
|
|
|
lineHeight: 90,
|
|
|
|
width: 90,
|
|
|
|
},
|
|
|
|
]}
|
|
|
|
>
|
|
|
|
{props.tellers.map( (marker, index) => (
|
|
|
|
marker.withInfo ? (
|
|
|
|
<Marker
|
|
|
|
key={index}
|
|
|
|
position={{ lat: marker.lat, lng: marker.lng }}
|
|
|
|
icon={TellerPin}
|
|
|
|
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={TellerPin}
|
|
|
|
/>
|
|
|
|
)
|
|
|
|
))}
|
|
|
|
</MarkerClusterer>
|
|
|
|
|
2018-09-22 18:23:51 +00:00
|
|
|
</GoogleMap>
|
|
|
|
);
|
|
|
|
|
|
|
|
// Type checking the props of the component
|
|
|
|
CustomLayerMap.propTypes = propTypes;
|
|
|
|
// Assign default values to the optional props
|
|
|
|
CustomLayerMap.defaultProps = defaultProps;
|
|
|
|
|
2019-01-15 02:23:41 +00:00
|
|
|
/**
|
|
|
|
* 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,
|
|
|
|
ambassadors: PropTypes.array,
|
|
|
|
merchants: PropTypes.array,
|
|
|
|
tellers: PropTypes.array,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This object sets default values to the optional props.
|
|
|
|
*/
|
|
|
|
const defaultPropsLayerMap = {
|
|
|
|
ambassadors: null,
|
|
|
|
merchants: null,
|
|
|
|
tellers: null
|
|
|
|
};
|
2018-12-03 15:26:15 +00:00
|
|
|
|
2018-09-22 18:23:51 +00:00
|
|
|
class LayerMap extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {
|
|
|
|
ambassadors: [],
|
|
|
|
merchants: [],
|
2018-12-03 15:26:15 +00:00
|
|
|
tellers: [],
|
2018-09-22 18:23:51 +00:00
|
|
|
ambassadorLayer: this.props.ambassadorsLayer,
|
2018-12-03 15:26:15 +00:00
|
|
|
merchantLayer: this.props.merchantsLayer,
|
|
|
|
tellerLayer: this.props.tellersLayer,
|
2018-09-22 18:23:51 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-12-03 15:26:15 +00:00
|
|
|
/**
|
|
|
|
* @description Lifecycle event handler called just after the App loads into the DOM.
|
|
|
|
*/
|
|
|
|
UNSAFE_componentWillMount() {
|
2019-01-15 02:23:41 +00:00
|
|
|
this.updateMarkers();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update markers based if props are informed
|
|
|
|
updateMarkers() {
|
|
|
|
if(!this.props.ambassadors) {
|
|
|
|
this.getAmbassadors();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!this.props.merchants) {
|
|
|
|
this.getMerchants();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.props.tellers) {
|
|
|
|
this.getTellers();
|
|
|
|
}
|
2018-12-03 15:26:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fillResults(result) {
|
|
|
|
const data = result;
|
|
|
|
return (item) => data.data.push(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @description Get ambassadors from the web service
|
|
|
|
* @param {number} [limit=10] - Max items to be returned.
|
|
|
|
* @param {number} [skip=0] - Start index search
|
|
|
|
*/
|
|
|
|
getAmbassadors = async (limit = 50, skip = 0) => {
|
|
|
|
const app = this;
|
|
|
|
// Initially we don't know how much the total value is, so to make sure we enter the loop
|
|
|
|
// at least once we're just setting it to be 1
|
|
|
|
let total = 1;
|
|
|
|
|
|
|
|
const ambassadors = Client.service('api/v2/ambassadors');
|
|
|
|
|
|
|
|
let result;
|
|
|
|
while(skip < total){
|
|
|
|
let partialResponse = await ambassadors.find({
|
|
|
|
query: {
|
|
|
|
$sort: { account: 1 },
|
|
|
|
$limit: limit,
|
|
|
|
$skip: skip
|
|
|
|
}
|
|
|
|
});
|
|
|
|
total = partialResponse.total;
|
|
|
|
result === undefined ? result = partialResponse : partialResponse.data.map(this.fillResults(result));
|
|
|
|
skip = skip + limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
const markers = [];
|
|
|
|
result.data.forEach(ambassador => {
|
|
|
|
ambassador.cities.forEach(function(city) {
|
|
|
|
const infoDescription = <div>
|
|
|
|
<div><b>Location</b>: {(city.name).replace(/(^|\s)\S/g, l => l.toUpperCase())} - {countries.getName(city.country)}</div>
|
|
|
|
{(ambassador.nickname) && (<div><b>Nickname</b>: {ambassador.nickname}</div>)}
|
|
|
|
{(ambassador.telegram) && (<div><b>Telegram</b>:
|
|
|
|
<a
|
|
|
|
href={`https://t.me/${(ambassador.telegram.trim().charAt(0) === '@') ? ambassador.telegram.trim().slice(1): ambassador.telegram.trim()}`}
|
|
|
|
target="_blank"
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
>{ambassador.telegram}</a>
|
|
|
|
</div>)}
|
|
|
|
{(ambassador.keybase) && (<div><b>Keybase</b>: {ambassador.keybase}</div>)}
|
|
|
|
{(ambassador.email) && (<div><b>Email</b>: {ambassador.email}</div>)}
|
|
|
|
{(ambassador.phone) && (<div><b>Phone</b>: {ambassador.phone}</div>)}
|
|
|
|
{(ambassador.url) && (<div><b>URL:</b>: <a target="_blank" rel="noopener noreferrer"
|
|
|
|
href={ambassador.url}>{stripProtocol(ambassador.url)}</a></div>)}
|
|
|
|
</div>;
|
|
|
|
const marker = {
|
|
|
|
lat: city.lat,
|
|
|
|
lng: city.lon,
|
|
|
|
withInfo: true,
|
|
|
|
infoTitle: ambassador.nickname,
|
|
|
|
infoDescription: infoDescription,
|
|
|
|
};
|
|
|
|
markers.push(marker);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Once both return, update the state
|
|
|
|
app.setState({ ambassadors: markers });
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @description Get merchants from the web service
|
|
|
|
* @param {number} [limit=10] - Max items to be returned.
|
|
|
|
* @param {number} [skip=0] - Start index search
|
|
|
|
*/
|
|
|
|
getMerchants = async (limit = 50, skip = 0) => {
|
|
|
|
const app = this;
|
|
|
|
// Initially we don't know how much the total value is, so to make sure we enter the loop
|
|
|
|
// at least once we're just setting it to be 1
|
|
|
|
let total = 1;
|
|
|
|
|
|
|
|
const merchants = Client.service('api/v1/merchants');
|
|
|
|
|
|
|
|
let result;
|
|
|
|
while(skip < total){
|
|
|
|
let partialResponse = await merchants.find({
|
|
|
|
query: {
|
|
|
|
$sort: { account: 1 },
|
|
|
|
$limit: limit,
|
|
|
|
$skip: skip
|
|
|
|
}
|
|
|
|
});
|
|
|
|
total = partialResponse.total;
|
|
|
|
result === undefined ? result = partialResponse : partialResponse.data.map(this.fillResults(result));
|
|
|
|
skip = skip + limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.data.forEach(function(merchants){
|
|
|
|
if(merchants.city !== undefined) merchants.city = (merchants.city).replace(/(^|\s)\S/g, l => l.toUpperCase());
|
|
|
|
if(merchants.country !== undefined) merchants.country = countries.getName(merchants.country);
|
|
|
|
});
|
|
|
|
|
|
|
|
const markers = result.data.map(merchant => {
|
|
|
|
const infoDescription = <div>
|
|
|
|
<div><b>Address</b>: {merchant.address}</div>
|
|
|
|
{(merchant.phone) && (<div><b>Phone</b>: {merchant.phone}</div>)}
|
|
|
|
{(merchant.telegram) && (<div><b>Telegram</b>:
|
|
|
|
<a
|
|
|
|
href={`https://t.me/${(merchant.telegram.trim().charAt(0) === '@') ? merchant.telegram.trim().slice(1): merchant.telegram.trim()}`}
|
|
|
|
target="_blank"
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
>{merchant.telegram}</a>
|
|
|
|
</div>)}
|
|
|
|
{(merchant.website) && (<div><b>Website:</b>: <a target="_blank" rel="noopener noreferrer"
|
|
|
|
href={merchant.website}>{stripProtocol(merchant.website)}</a></div>)}
|
|
|
|
</div>;
|
|
|
|
const marker = {
|
|
|
|
lat: merchant.lat,
|
|
|
|
lng: merchant.lon,
|
|
|
|
withInfo: true,
|
|
|
|
infoTitle: merchant.name,
|
|
|
|
infoDescription: infoDescription,
|
|
|
|
};
|
|
|
|
return marker;
|
|
|
|
});
|
|
|
|
|
|
|
|
// Once both return, update the state
|
|
|
|
app.setState({
|
|
|
|
merchants: markers,
|
|
|
|
loading: false
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @description Get tellers from the web service
|
|
|
|
* @param {number} [limit=10] - Max items to be returned.
|
|
|
|
* @param {number} [skip=0] - Start index search
|
|
|
|
*/
|
|
|
|
getTellers = async (limit = 50, skip = 0) => {
|
|
|
|
const app = this;
|
|
|
|
// Initially we don't know how much the total value is, so to make sure we enter the loop
|
|
|
|
// at least once we're just setting it to be 1
|
|
|
|
let total = 1;
|
|
|
|
|
|
|
|
const tellers = Client.service('api/v2/tellers');
|
|
|
|
this.setState({loading: true});
|
|
|
|
let result;
|
|
|
|
while(skip < total){
|
|
|
|
let partialResponse = await tellers.find({
|
|
|
|
query: {
|
|
|
|
//$sort: { account: 1 },
|
|
|
|
$limit: limit,
|
|
|
|
$skip: skip
|
|
|
|
}
|
|
|
|
});
|
|
|
|
total = partialResponse.total;
|
|
|
|
result === undefined ? result = partialResponse : partialResponse.data.map(this.fillResults(result));
|
|
|
|
skip = skip + limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
result.data.forEach(function(tellers){
|
|
|
|
if(tellers.city !== undefined) tellers.city = (tellers.city).replace(/(^|\s)\S/g, l => l.toUpperCase());
|
|
|
|
if(tellers.country !== undefined) tellers.country = countries.getName(tellers.country);
|
|
|
|
});
|
|
|
|
|
2019-01-15 02:23:41 +00:00
|
|
|
const markers = result.data.map(teller => {
|
|
|
|
if(teller.telegram){
|
|
|
|
teller.telegram_original = teller.telegram;
|
|
|
|
teller.telegram = {
|
|
|
|
searchText: teller.telegram_original,
|
|
|
|
value: (
|
|
|
|
<a
|
|
|
|
href={`https://t.me/${(teller.telegram_original.trim().charAt(0) === '@') ?
|
|
|
|
teller.telegram_original.trim().slice(1): teller.telegram_original.trim()}`}
|
|
|
|
target="_blank"
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
>{teller.telegram}</a>
|
|
|
|
)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
const which = WHICH_OPTIONS.filter(w => w.id.toLowerCase() === teller.which.toLowerCase());
|
|
|
|
teller.which_value = ( teller.which && which.length > 0) ?
|
|
|
|
which[0].value :
|
|
|
|
'';
|
|
|
|
const infoDescription = (
|
|
|
|
<div>
|
|
|
|
<div><b>Address</b>: {teller.address}</div>
|
|
|
|
{(teller.which) && (<div><b>Which:</b>: {teller.which}</div>)}
|
|
|
|
{(teller.bitshares_address) && (<div><b>BTS Account:</b>: {teller.bitshares_address}</div>)}
|
|
|
|
{(teller.address) && (<div><b>Address:</b>: {teller.address}</div>)}
|
|
|
|
{(teller.telegram_original) && (<div><b>Telegram</b>:
|
|
|
|
<a
|
|
|
|
href={`https://t.me/${(teller.telegram_original.trim().charAt(0) === '@') ? teller.telegram_original.trim().slice(1): teller.telegram_original.trim()}`}
|
|
|
|
target="_blank"
|
|
|
|
rel="noopener noreferrer"
|
|
|
|
>{teller.telegram_original}</a>
|
|
|
|
</div>)
|
|
|
|
}
|
|
|
|
{(teller.keybase) && (<div><b>Keybase</b>: {teller.keybase}</div>)}
|
|
|
|
{(teller.whatsapp) && (<div><b>Whatsapp</b>: {teller.whatsapp}</div>)}
|
|
|
|
{(teller.viber) && (<div><b>Viber</b>: {teller.viber}</div>)}
|
|
|
|
{(teller.email) && (<div><b>Email</b>: {teller.email}</div>)}
|
|
|
|
{(teller.phone) && (<div><b>Phone</b>: {teller.phone}</div>)}
|
|
|
|
{(teller.url) && (<div><b>URL:</b>: <a target="_blank" rel="noopener noreferrer"
|
|
|
|
href={addProtocol(teller.url, getProtocol(teller.url))}>{stripProtocol(teller.url)}</a></div>)}
|
|
|
|
</div>
|
|
|
|
);
|
2018-12-03 15:26:15 +00:00
|
|
|
const marker = {
|
2019-01-15 02:23:41 +00:00
|
|
|
lat: teller.lat,
|
|
|
|
lng: teller.lon,
|
2018-12-03 15:26:15 +00:00
|
|
|
withInfo: true,
|
2019-01-15 02:23:41 +00:00
|
|
|
infoTitle: teller.gt_name,
|
2018-12-03 15:26:15 +00:00
|
|
|
infoDescription: infoDescription,
|
|
|
|
};
|
|
|
|
return marker;
|
|
|
|
});
|
|
|
|
|
|
|
|
// Once both return, update the state
|
|
|
|
app.setState({
|
|
|
|
loading: false,
|
|
|
|
tellers: markers
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2018-09-22 18:23:51 +00:00
|
|
|
handleLayerChange = name => event => {
|
|
|
|
this.setState({ [name]: event.target.checked });
|
2018-12-03 15:26:15 +00:00
|
|
|
// Update any time changes
|
2019-01-15 02:23:41 +00:00
|
|
|
this.updateMarkers();
|
2018-09-22 18:23:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
2019-01-15 02:23:41 +00:00
|
|
|
const {
|
|
|
|
ambassadors: ambassadorsProps,
|
|
|
|
merchants: merchantsProps,
|
|
|
|
tellers: tellersProps
|
|
|
|
} = this.props;
|
|
|
|
|
|
|
|
let {
|
|
|
|
ambassadors,
|
|
|
|
merchants,
|
|
|
|
tellers
|
|
|
|
} = this.state;
|
|
|
|
|
|
|
|
if(ambassadorsProps) {
|
|
|
|
ambassadors = ambassadorsProps;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(merchantsProps) {
|
|
|
|
merchants = merchantsProps;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tellersProps) {
|
|
|
|
tellers = tellersProps;
|
|
|
|
}
|
2018-09-22 18:23:51 +00:00
|
|
|
|
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
{!this.props.showControls ? (
|
|
|
|
<LayerMapSwitches
|
|
|
|
ambassadors={this.state.ambassadorLayer}
|
|
|
|
merchants={this.state.merchantLayer}
|
2018-12-03 15:26:15 +00:00
|
|
|
tellers={this.state.tellerLayer}
|
2018-09-22 18:23:51 +00:00
|
|
|
onChange={this.handleLayerChange}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<div style={{ height: 56 }}></div>
|
|
|
|
)}
|
|
|
|
<CustomLayerMap
|
2019-01-15 02:23:41 +00:00
|
|
|
ambassadors={this.state.ambassadorLayer ? ambassadors: []}
|
|
|
|
merchants={this.state.merchantLayer ? merchants: []}
|
|
|
|
tellers={this.state.tellerLayer ? tellers: []}
|
2018-09-22 18:23:51 +00:00
|
|
|
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>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-15 02:23:41 +00:00
|
|
|
// Type checking the props of the component
|
|
|
|
LayerMap.propTypes = propTypesLayerMap;
|
|
|
|
// Assign default values to the optional props
|
|
|
|
LayerMap.defaultProps = defaultPropsLayerMap;
|
|
|
|
|
2018-09-22 18:23:51 +00:00
|
|
|
export default LayerMap;
|