import React, { Component, Fragment } from 'react'; import { Map, InfoWindow, Marker, GoogleApiWrapper } from 'google-maps-react'; import moment from 'moment'; import Typography from '@material-ui/core/Typography'; import firebase from '../utilities/firebase.js'; // Google Maps API Key const API_KEY = 'AIzaSyAZ_0J01bA6wCbIPK4UBq2RUBC-hIqG4mM'; // Map container styles const mapStyles = { width: '100%', height: '100%' }; /** * Types of sightings. Label is what is * viewed in the application, value is * what is stored in the database. */ const sightingTypes = [ { value: 'visual', label: 'Visual', }, { value: 'roadkill', label: 'Roadkill', }, { value: 'trapped', label: 'Trapped', }, { value: 'viewed_tracks', label: 'Viewed Tracks', }, { value: 'photo', label: 'Photo', }, { value: 'other', label: 'Other', }, ]; /** * Types of sightings. Label is what is * viewed in the application, value is * what is stored in the database. */ const timeTypes = [ { value: 'unknown', label: 'Unknown', }, { value: 'morning', label: 'Morning', }, { value: 'midday', label: 'Midday', }, { value: 'evening', label: 'Evening', }, { value: 'night', label: 'Night', }, ]; /** * Levels of confidence. Label is what is * viewed in the application, value is * what is stored in the database. */ const confidenceLevels = [ { value: '1', label: '1 - Strongly disagree', }, { value: '2', label: '2 - Disagree', }, { value: '3', label: '3 - Neutral', }, { value: '4', label: '4 - Agree', }, { value: '5', label: '5 - Strongly agree', }, ]; export class MapContainer extends Component { // Get the user's location using Google's geolocation getLocation = () => { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition((position) => { this.setState({ myLatLng: { lat: position.coords.latitude, lng: position.coords.longitude } }); }); } else { // If browser doesn't support geolocation or if user does not allow it, // center map on Grand Rapids, Michigan this.setState({ myLatLng: { lat: 43.8666776, lng: -85.9667325 } }); } } /** * Gets formatted type value. */ getType = item => { for (var i = 0; i < sightingTypes.length; i++) { if (sightingTypes[i].value === item) { return sightingTypes[i].label; } } } /** * Gets formatted time value. */ getTime = item => { for (var i = 0; i < timeTypes.length; i++) { if (timeTypes[i].value === item) { return timeTypes[i].label; } } } /** * Gets formatted confidence value. */ getConfidence = item => { for (var i = 0; i < confidenceLevels.length; i++) { if (confidenceLevels[i].value === item) { return confidenceLevels[i].label; } } } // When the component has mounted to the DOM, get the user's location componentDidMount() { this.getLocation(); const sightingsRef = firebase.database().ref('sightings'); sightingsRef.on('value', (snapshot) => { let sightings = snapshot.val(); let newState = []; for (let sighting in sightings) { newState.push({ id: sighting, lat: sightings[sighting].lat, lng: sightings[sighting].lng, desc: sightings[sighting].desc, type: sightings[sighting].type, confidence: sightings[sighting].confidence, date: sightings[sighting].date, time: sightings[sighting].time }); } this.setState({ sightings: newState }); }); } // When the user clicks on a marker, pass the props related to that marker // and show the related info window onMarkerClick = (props, marker) => { this.setState({ selectedPlace: props, activeMarker: marker, showingInfoWindow: true }); } onMapClick = (props, map, e) => { if (this.state.showingInfoWindow) { this.setState({ showingInfoWindow: false, activeMarker: null }); } } /** * Determines marker icon based on the * sighting type. */ sightingIcon = (type) => { let pinIcon; switch(type) { case 'visual': pinIcon = '/map-icons/marten-icon.png'; break; case 'roadkill': pinIcon = '/map-icons/tire-icon.png'; break; case 'viewed_tracks': pinIcon = '/map-icons/paws.png'; break; case 'trapped': pinIcon = '/map-icons/cage.png'; break; case 'photo': pinIcon = '/map-icons/photo-icon.png'; break; case 'other': pinIcon = '/map-icons/other-icon.png'; break; default: break; } return pinIcon; } /** * Formats date using Moment.js. */ formatDate = date => { return (moment(date, "YYYY-MM").format("MMMM YYYY").toString()) } // Set the state of the component to contain user coordinates and initial // marker and info window information state = { myLatLng: { lat: 43.8666776, lng: -85.9667325 }, showingInfoWindow: false, activeMarker: {}, selectedPlace: {}, sightings: [] }; render() { const {google} = this.props; return ( // Render the Google Map, Marker, and InfoWindow components
{this.state.sightings.map((sighting) => { let pinIcon = this.sightingIcon(sighting.type) return ( Date: {this.formatDate(sighting.date)}} time={Time: {this.getTime(sighting.time)}} confidence={I am confident of my sighting: {this.getConfidence(sighting.confidence)}} description={Description: {sighting.desc}} icon={{ url: pinIcon, anchor: new google.maps.Point(48,48), scaledSize: new google.maps.Size(48,48) }} /> ) })} {this.state.selectedPlace.type} {this.state.selectedPlace.date} {this.state.selectedPlace.time} {this.state.selectedPlace.confidence} {this.state.selectedPlace.description}
); } } // Send the Google Map API Key with the MapContainer component export default GoogleApiWrapper({ apiKey: (API_KEY) })(MapContainer);