diff --git a/src/components/LayerMap.js b/src/components/LayerMap.js index e57a992..a8d9463 100644 --- a/src/components/LayerMap.js +++ b/src/components/LayerMap.js @@ -10,15 +10,21 @@ import { } from 'react-google-maps'; import { MarkerClusterer } from 'react-google-maps/lib/components/addons/MarkerClusterer'; +// Helpers +import Client from '../utils/feathers'; +import { stripProtocol } from '../utils/url'; +import Countries from 'country-list'; + // Custom Components import LayerMapSwitches from './LayerMapSwitches'; // Helpers -import GOOGLE_MAPS_API from '../utils/constants'; +import { GOOGLE_MAPS_API } from '../utils/constants'; // Images import MerchantPin from '../assets/img/map/merchant_pin.png'; import AmbassadorPin from '../assets/img/map/ambassador_pin.png'; +import TellerPin from '../assets/img/map/teller_pin.png'; import ambs_m1 from '../assets/img/map/cluster/ambassadors/m1.png'; import ambs_m2 from '../assets/img/map/cluster/ambassadors/m2.png'; @@ -32,6 +38,15 @@ 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'; +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'; + +// List of countries +const countries = Countries(); + /** * This object is used for type checking the props of the component. */ @@ -59,6 +74,9 @@ const defaultProps = { mapElement:
, // Fix google maps modal problem showControls: true, + ambassadors: [], + merchants: [], + tellers: [] }; defaultProps['markers'] = [ defaultProps.mapCenter @@ -153,6 +171,7 @@ const CustomLayerMap = compose( ) ))} + + + + {props.tellers.map( (marker, index) => ( + marker.withInfo ? ( + props.onToggleAmbassadorOpen(index)} + > + {props.isOpenAmbassadorObj[index] && props.onToggleAmbassadorOpen(index)}> +
+
{marker.infoTitle}
+
+
{marker.infoDescription}
+
+
} +
+ ) : ( + + ) + ))} +
+ ); @@ -234,21 +318,234 @@ const propTypesLayerMap = { mapHeight: PropTypes.string, ambassadors: PropTypes.array, merchants: PropTypes.array, + tellers: PropTypes.array, }; +// Type checking the props of the component +CustomLayerMap.propTypes = propTypes; +// Assign default values to the optional props +CustomLayerMap.defaultProps = defaultProps; + class LayerMap extends Component { constructor(props) { super(props); this.state = { ambassadors: [], merchants: [], + tellers: [], ambassadorLayer: this.props.ambassadorsLayer, - merchantLayer: this.props.merchantsLayer + merchantLayer: this.props.merchantsLayer, + tellerLayer: this.props.tellersLayer, }; } + /** + * @description Lifecycle event handler called just after the App loads into the DOM. + */ + UNSAFE_componentWillMount() { + this.getAmbassadors(); + this.getMerchants(); + this.getTellers(); + } + + 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 =
+
Location: {(city.name).replace(/(^|\s)\S/g, l => l.toUpperCase())} - {countries.getName(city.country)}
+ {(ambassador.nickname) && (
Nickname: {ambassador.nickname}
)} + {(ambassador.telegram) && (
Telegram: + {ambassador.telegram} +
)} + {(ambassador.keybase) && (
Keybase: {ambassador.keybase}
)} + {(ambassador.email) && (
Email: {ambassador.email}
)} + {(ambassador.phone) && (
Phone: {ambassador.phone}
)} + {(ambassador.url) && (
URL:: {stripProtocol(ambassador.url)}
)} +
; + 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 =
+
Address: {merchant.address}
+ {(merchant.phone) && (
Phone: {merchant.phone}
)} + {(merchant.telegram) && (
Telegram: + {merchant.telegram} +
)} + {(merchant.website) && (
Website:: {stripProtocol(merchant.website)}
)} +
; + 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); + }); + + const markers = result.data.map(merchant => { + const infoDescription =
+
Address: {merchant.address}
+ {(merchant.phone) && (
Phone: {merchant.phone}
)} + {(merchant.telegram) && (
Telegram: + {merchant.telegram} +
)} + {(merchant.url) && (
Website:: {stripProtocol(merchant.url)}
)} +
; + const marker = { + lat: merchant.lat, + lng: merchant.lon, + withInfo: true, + infoTitle: merchant.gt_name, + infoDescription: infoDescription, + }; + return marker; + }); + + // Once both return, update the state + app.setState({ + loading: false, + tellers: markers + }); + }; + handleLayerChange = name => event => { this.setState({ [name]: event.target.checked }); + // Update any time changes + this.getAmbassadors(); + this.getMerchants(); + this.getTellers(); }; render() { @@ -260,15 +557,16 @@ class LayerMap extends Component { ) : (
)} } @@ -280,7 +578,4 @@ class LayerMap extends Component { } } -// Type checking the props of the component -LayerMap.propTypes = propTypesLayerMap; - export default LayerMap; diff --git a/src/components/LayerMapSwitches.js b/src/components/LayerMapSwitches.js index 7670614..590ac29 100644 --- a/src/components/LayerMapSwitches.js +++ b/src/components/LayerMapSwitches.js @@ -42,6 +42,18 @@ const styles = theme => ({ easing: theme.transitions.easing.sharp, }), }, + iOSSwitchBaseYellow: { + '&$iOSChecked': { + color: theme.palette.common.white, + '& + $iOSBar': { + backgroundColor: "#fdcf09", + }, + }, + transition: theme.transitions.create('transform', { + duration: theme.transitions.duration.shortest, + easing: theme.transitions.easing.sharp, + }), + }, iOSChecked: { transform: 'translateX(15px)', '& + $iOSBar': { @@ -116,6 +128,24 @@ class LayerMapSwitches extends React.Component { } label="Merchants" /> + + } + label="Tellers" + />
); @@ -126,12 +156,14 @@ LayerMapSwitches.propTypes = { classes: PropTypes.object.isRequired, ambassadors: PropTypes.bool, merchants: PropTypes.bool, + tellers: PropTypes.bool, onChange: PropTypes.func.isRequired, }; LayerMapSwitches.defaultProps = { ambassadors: true, - merchants: true + merchants: true, + tellers: true }; export default withStyles(styles)(LayerMapSwitches); diff --git a/src/components/PreviewMap.js b/src/components/PreviewMap.js index cd5526f..4b2ccb7 100644 --- a/src/components/PreviewMap.js +++ b/src/components/PreviewMap.js @@ -1,6 +1,6 @@ import React from "react"; import PropTypes from 'prop-types'; -import GOOGLE_MAPS_API from '../utils/constants'; +import { GOOGLE_MAPS_API } from '../utils/constants'; import { compose, withStateHandlers } from 'recompose'; import { withScriptjs, diff --git a/src/components/pages/MerchantsPage.js b/src/components/pages/MerchantsPage.js index ad42e68..140df5d 100644 --- a/src/components/pages/MerchantsPage.js +++ b/src/components/pages/MerchantsPage.js @@ -21,6 +21,8 @@ import Countries from 'country-list'; import LoadingGif from '../../assets/img/loading_icon.gif'; import MerchantPin from '../../assets/img/map/merchant_pin.png'; +import { WHICH_OPTIONS } from '../../utils/constants'; + import "./MerchantsPage.css"; // List of countries @@ -78,6 +80,7 @@ class MerchantsPage extends Component { }, merchantsSearch: [], ambassadorsMarkers: [], + tellersMarkers: [], loading: true, rowsPerPage: [100,200,300], numberOfRows: 100, @@ -168,6 +171,128 @@ class MerchantsPage extends Component { app.setState({ ambassadorsMarkers: markers }); }; + /** + * @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); + }); + + result.data.map(teller => { + const infoDescription =
+
Address: {teller.address}
+ {(teller.phone) && (
Phone: {teller.phone}
)} +
; + if(teller.telegram){ + teller.telegram_original = teller.telegram; + teller.telegram = { + searchText: teller.telegram_original, + value: ( + {teller.telegram} + ) + }; + } + + teller.link = { + searchText: stripProtocol(teller.url), + value: ( + {stripProtocol(teller.url)} + ) + }; + teller.location = { + searchText: `${teller.country} - ${teller.city}`, + value: (teller.city) ? `${teller.city} - ${teller.country}`: teller.country + } + teller.map = ; + return teller; + }); + + // Once both return, update the state + app.setState({ + loading: false, + tellersMarkers: result.data + }); + }; + + getTellerMarker = (teller) => { + 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 = ( +
+
Address: {teller.address}
+ {(teller.which) && (
Which:: {teller.which}
)} + {(teller.bitshares_address) && (
BTS Account:: {teller.bitshares_address}
)} + {(teller.address) && (
Address:: {teller.address}
)} + {(teller.telegram_original) && (
Telegram: + {teller.telegram_original} +
) + } + {(teller.keybase) && (
Keybase: {teller.keybase}
)} + {(teller.whatsapp) && (
Whatsapp: {teller.whatsapp}
)} + {(teller.viber) && (
Viber: {teller.viber}
)} + {(teller.email) && (
Email: {teller.email}
)} + {(teller.phone) && (
Phone: {teller.phone}
)} + {(teller.url) && (
URL:: {stripProtocol(teller.url)}
)} +
+ ); + const marker = { + lat: teller.lat, + lng: teller.lon, + withInfo: true, + infoTitle: teller.gt_name, + infoDescription: infoDescription, + }; + return marker; + }; + /** * @description Get merchants from the web service * @param {number} [limit=10] - Max items to be returned.