import React from 'react'; import Filters from './Filters'; import Listings from './Listings'; import ListingDetails from './ListingDetails'; import { pacSelectFirst } from '../helpers/googleMaps'; import { loadProperties, loadSeen, loadListing} from '../lib/api' import { handleMessage } from '../lib/handlers' import Router from '../lib/router'; class Main extends React.Component { constructor(props) { super(props); const state = { listingDetails: false, listings: (new Map()), imageIndex: 0, page: 0, sort: 'relevance', filters: { rooms: {}, category: {} } } if (props.initialState) { props.initialState.sort = props.initialState.sort || state.sort; state.filters.rooms = props.initialState.rooms; state.filters.category = props.initialState.category; state.sort = props.initialState.sort || state.sort; state.listingId = props.initialState.listingId; state.bounds = props.initialState.bounds; state.zoom = props.initialState.zoom; if (state.listingId) { state.listingDetails = true; } state.filters.minSize = props.initialState.minSize; state.filters.maxSize = props.initialState.maxSize; state.filters.minPrice = props.initialState.minPrice; state.filters.maxPrice = props.initialState.maxPrice; } this.state = state; this.router = new Router(this, props.initialState); } dispatch ({type, action = {}}) { handleMessage({type, action}, this); } componentDidMount() { const uluru = {lat: 43.845031, lng: 18.4019262}; const opts = { //zoom: 13, //center: uluru, streetViewControl: false, mapTypeControl: false }; if (!this.state.bounds) { opts.zoom = 13; opts.center= uluru; }; const map = new google.maps.Map(this.refs.map, opts); window.gmap = map; //const marker = new google.maps.Marker({ //position: uluru, //map: map //}); var control = document.createElement('div'); control.classList.add('filters-btn-toggle'); control.innerHTML = 'Filters'; //control.style = "top: 200px;" control["style"]= "top: 200px;" var input = document.getElementById('gmaps-places-input'); pacSelectFirst(input); var options = { componentRestrictions: {country: "BA"} }; const regularIdle = () => { this.dispatch({type: 'UPDATE_ROUTE', action: {params: { bounds: map.getBounds().toUrlValue(), zoom: map.getZoom() }}}); this.dispatch({type: 'MAP_IDLE'}); }; // Check if initial bounds are passed-in google.maps.event.addListenerOnce(map, 'idle', () => { if (this.state.bounds) { const [ lat1, lng1, lat2, lng2 ] = this.state.bounds.split(","); const sw = new google.maps.LatLng({lat: parseFloat(lat1), lng: parseFloat(lng1)}); const ne = new google.maps.LatLng({lat: parseFloat(lat2), lng: parseFloat(lng2)}); const initialBounds = new google.maps.LatLngBounds(sw, ne); //map.fitBounds(initialBounds); const originalMaxZoom = map.maxZoom; const originalMinZoom = map.minZoom; map.setOptions({maxZoom: parseInt(this.state.zoom), minZoom: parseInt(this.state.zoom)}); map.fitBounds(initialBounds); map.setOptions({maxZoom: originalMaxZoom, minZoom: originalMinZoom}); } }); map.addListener('idle', regularIdle); var searchBox = new google.maps.places.Autocomplete(input, options); searchBox.addListener('place_changed', () => { var place = searchBox.getPlace(); if (!place.geometry) { return; } if (place.geometry.viewport) { map.fitBounds(place.geometry.viewport); } else { map.setCenter(place.geometry.location); map.setZoom(18); } this.dispatch({type: 'SEARCH_PLACE_CHANGED'}); }); control.addEventListener('click', (e) => { this.setState({ mapClicked: true }); }); control.index = 1; map.controls[google.maps.ControlPosition.TOP_RIGHT].push(control); this.map = map; // TODO: if state contains listingId reload if (this.state.listingId) { loadListing(this.state.listingId).then(l => l.text()).then(l => { this.dispatch({type: 'VIEW_LISTING_DETAILS', action: { id: this.state.listingId, listing: JSON.parse(l) }}); }); } } removeAllMarkers () { if (this.markers) { this.markers.forEach((m) => m.marker.setMap(null)); } } onCloseClick(e) { if (this.state.mapClicked) { setTimeout(() => { google.maps.event.trigger(this.map, 'resize'); }, 100); } this.setState({ mapClicked: false }); } findMarker (id) { if (!this.markers) { return null; } const index = this.markers.findIndex(m => m.id === id); return this.markers[index]; } isSeen (id) { const seen = loadSeen(); return seen.findIndex(s => s === id) !== -1 } loadPins () { const map = this.map; const { rooms, minSize, maxSize, minPrice, maxPrice, category } = this.state.filters; const bounds = map.getBounds(); const properties = loadProperties({ bounds: bounds.toUrlValue(), rooms, minSize, maxSize, minPrice, maxPrice, category, page: this.state.page, pins: true }); const markerExists = (id) => { return this.findMarker(id) != null; } properties .then(p => { return { body: p.text(), totalCount: p.headers.get('X-Total-Count') }; }) .then(({body, totalCount}) => { body.then(p => { const data = JSON.parse(p); const listingExists = (id) => { return data.findIndex(l => l._id === id) !== -1 }; const newMarkers = []; if (this.markers) { this.markers.forEach((m) => { if (!listingExists(m.id)) { m.marker.setMap(null); } else { newMarkers.push(m); } }); } for(const [index, prop] of data.entries()) { const myLatLng = {lat: prop.loc[0], lng: prop.loc[1]}; if (!markerExists(prop._id)) { const marker = new google.maps.Marker({ position : myLatLng, map : map, //title : prop.title, icon : this.isSeen(prop._id) ? this.visitedMarkerIcon() : this.defaultMarkerIcon(), id : prop._id }); marker.addListener('mouseover', () => { if (marker.id !== this.state.listingId) { if (this.isSeen(marker.id)) { marker.setIcon(this.visitedHoveredMarkerIcon()); } else { marker.setIcon(this.hoveredMarkerIcon()); } } }); marker.addListener('mouseout', () => { if (marker.id !== this.state.listingId) { if (this.isSeen(marker.id)) { marker.setIcon(this.visitedMarkerIcon()); } else { marker.setIcon(this.defaultMarkerIcon()); } } }); marker.addListener('click', () => { // Maybe move out and call when popping state if (this.state.listingId) { const prevSelected = this.findMarker(this.state.listingId); if (prevSelected) { prevSelected.marker.setIcon(this.visitedMarkerIcon()); } } marker.setIcon(this.selectedMarkerIcon()); loadListing(prop._id).then(l => l.text()).then(l => { this.dispatch({type: 'UPDATE_ROUTE', action: { toDispatch: { type: 'VIEW_LISTING_DETAILS', action: { id: prop._id, listing: JSON.parse(l) } }, params: { listingId: prop._id } }}); //this.dispatch({type: 'UPDATE_ROUTE', action: {type: 'VIEW_LISTING_DETAILS', action: { //id: prop._id, //listing: JSON.parse(l) //}}}); this.dispatch({type: 'VIEW_LISTING_DETAILS', action: { id: prop._id, listing: JSON.parse(l) }}); }); }); newMarkers.push({ marker, id: prop._id }); } } this.dispatch({ type: 'PINS_LOADED', action: { newMarkers } }); }); }) } /* * Refreshes search */ refreshListings(more = false) { // TODO: move somewhere else if (!more && this.state.listingId) { loadListing(this.state.listingId).then(l => l.text()).then(l => { this.dispatch({type: 'VIEW_LISTING_DETAILS', action: { id: this.state.listingId, listing: JSON.parse(l) }}); }); } if (!more) { this.loadPins(); } const map = this.map; const { rooms, minSize, maxSize, minPrice, maxPrice, category } = this.state.filters; const bounds = map.getBounds(); const properties = loadProperties({ bounds: bounds.toUrlValue(), rooms, minSize, maxSize, minPrice, maxPrice, category, page: this.state.page, sort: this.state.sort }); properties .then(p => { return { body: p.text(), totalCount: p.headers.get('X-Total-Count') }; }) .then(({body, totalCount}) => { body.then(p => { const data = JSON.parse(p); this.dispatch({ type: 'LISTINGS_LOADED', action: { listings: data, more, totalCount } }); }); }) } /* * Get default marker icon */ defaultMarkerIcon () { const sf = 0.5; const width = 48; const height = 64; const icon = { url : "static/images/pins_sprite.png", size : new google.maps.Size(width * sf, height * sf), scaledSize : new google.maps.Size(730 * sf, 102 * sf), origin : new google.maps.Point(0, 36 * sf) } return icon; } /* * Get visited marker icon */ visitedMarkerIcon () { const sf = 0.5; const width = 48; const height = 64; const icon = { url : "static/images/pins_sprite.png", size : new google.maps.Size(width * sf, height * sf), scaledSize : new google.maps.Size(730 * sf, 102 * sf), origin : new google.maps.Point(152 * sf, 36 * sf) } return icon; } /* * Visited hovered marker icon */ visitedHoveredMarkerIcon () { const sf = 0.5; const width = 61; const height = 82; const icon = { url : "static/images/pins_sprite.png", size : new google.maps.Size(width * sf, height * sf), scaledSize : new google.maps.Size(730 * sf, 102 * sf), origin : new google.maps.Point(480 * sf, 18 * sf) } return icon; } /* * Hovered marker icon */ hoveredMarkerIcon () { const sf = 0.5; const width = 61; const height = 82; const icon = { url : "static/images/pins_sprite.png", size : new google.maps.Size(width * sf, height * sf), scaledSize : new google.maps.Size(730 * sf, 102 * sf), origin : new google.maps.Point(303 * sf, 18 * sf) } return icon; } /* * Selected marker icon */ selectedMarkerIcon () { const sf = 0.5; const width = 73; const height = 100; const icon = { url : "static/images/pins_sprite.png", size : new google.maps.Size(width * sf, height * sf), scaledSize : new google.maps.Size(730 * sf, 102 * sf), origin : new google.maps.Point(655 * sf, 1 * sf) } return icon; } renderRightContent() { const children = []; if (this.state.listingDetails) { const listing = this.state.listing; //this.state.listings.get(this.state.listingId); children.push(); } else { children.push(); children.push(); } const content = ( {children} ); return content; } render() { const leftStyle = {}; const rightStyle = {}; const listingDetails = true; let leftClass = 'left-base'; let rightClass = 'right-base'; if (this.state.mapClicked) { leftClass = 'left-hidden'; rightClass = 'right-shown'; } return ( K Kiwi {this.renderRightContent()} ) } } export default Main;