374 lines
9.0 KiB
JavaScript
374 lines
9.0 KiB
JavaScript
import React from 'react';
|
|
import Filters from './Filters';
|
|
import Listings from './Listings';
|
|
import ListingDetails from './ListingDetails';
|
|
import { pacSelectFirst } from '../helpers/googleMaps';
|
|
import {loadProperties} from '../lib/api'
|
|
import {handleMessage} from '../lib/handlers'
|
|
|
|
class Main extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.state = {
|
|
listingDetails: false,
|
|
listings: (new Map()),
|
|
imageIndex: 0,
|
|
filters: {
|
|
rooms: {},
|
|
category: {}
|
|
}
|
|
};
|
|
}
|
|
|
|
dispatch ({type, action = {}}) {
|
|
handleMessage({type, action}, this);
|
|
}
|
|
|
|
componentDidMount() {
|
|
const uluru = {lat: 43.845031, lng: 18.4019262};
|
|
const map = new google.maps.Map(this.refs.map, {
|
|
zoom: 13,
|
|
center: uluru,
|
|
streetViewControl: false,
|
|
mapTypeControl: false
|
|
});
|
|
|
|
//const marker = new google.maps.Marker({
|
|
//position: uluru,
|
|
//map: map
|
|
//});
|
|
|
|
var control = document.createElement('div');
|
|
control.classList.add('filters-btn-toggle');
|
|
control.innerHTML = '<button>Filters</button>';
|
|
//control.style = "top: 200px;"
|
|
control["style"]= "top: 200px;"
|
|
|
|
var input = document.getElementById('gmaps-places-input');
|
|
|
|
pacSelectFirst(input);
|
|
var options = {
|
|
componentRestrictions: {country: "BA"}
|
|
};
|
|
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);
|
|
}
|
|
console.log(map.getBounds());
|
|
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;
|
|
|
|
map.addListener('zoom_changed', () => {
|
|
console.log('zoom_changed');
|
|
this.removeAllMarkers();
|
|
this.markers = [];
|
|
});
|
|
|
|
map.addListener('idle', () => {
|
|
console.log('idle');
|
|
this.refreshListings();
|
|
});
|
|
}
|
|
|
|
removeAllMarkers () {
|
|
if (this.markers) {
|
|
console.log('removeAllMarkers');
|
|
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];
|
|
}
|
|
|
|
/*
|
|
* Refreshes search
|
|
*/
|
|
refreshListings() {
|
|
console.log('refreshListings');
|
|
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
|
|
});
|
|
|
|
|
|
const markerExists = (id) => {
|
|
return this.findMarker(id) != null;
|
|
}
|
|
|
|
properties.then(p => p.text()).then(p => {
|
|
|
|
const data = JSON.parse(p);
|
|
console.log('results_received');
|
|
|
|
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);
|
|
}
|
|
});
|
|
console.log('markers_removed');
|
|
}
|
|
|
|
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.defaultMarkerIcon(),
|
|
id : prop._id
|
|
});
|
|
|
|
marker.addListener('mouseover', () => {
|
|
if (marker.id !== this.state.listingId) {
|
|
marker.setIcon(this.hoveredMarkerIcon());
|
|
}
|
|
});
|
|
|
|
marker.addListener('mouseout', () => {
|
|
if (marker.id !== this.state.listingId) {
|
|
marker.setIcon(this.defaultMarkerIcon());
|
|
}
|
|
});
|
|
|
|
marker.addListener('click', () => {
|
|
console.log('clicking...', prop._id);
|
|
if (this.state.listingId) {
|
|
const prevSelected = this.findMarker(this.state.listingId);
|
|
if (prevSelected) {
|
|
console.log('prevselected', prevSelected);
|
|
prevSelected.marker.setIcon(this.defaultMarkerIcon());
|
|
}
|
|
}
|
|
|
|
marker.setIcon(this.selectedMarkerIcon());
|
|
this.dispatch({type: 'VIEW_LISTING_DETAILS', action: {
|
|
id: prop._id
|
|
}});
|
|
});
|
|
|
|
newMarkers.push({
|
|
marker,
|
|
id: prop._id
|
|
});
|
|
}
|
|
}
|
|
|
|
this.dispatch({
|
|
type: 'LISTINGS_LOADED',
|
|
action: {
|
|
listings: data,
|
|
newMarkers
|
|
}
|
|
});
|
|
})
|
|
}
|
|
|
|
onListingClick() {
|
|
this.setState({
|
|
listingDetails: true
|
|
})
|
|
}
|
|
|
|
onBackClick() {
|
|
this.setState({
|
|
listingDetails: false
|
|
})
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
/*
|
|
* 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) {
|
|
console.log('CURRENT LISTINGS', this.state.listings);
|
|
const listing = this.state.listings.get(this.state.listingId);
|
|
console.log(this.state);
|
|
children.push(<ListingDetails
|
|
listing={listing}
|
|
imageIndex={this.state.imageIndex}
|
|
dispatch={this.dispatch.bind(this)}
|
|
descriptionExpanded={this.state.descriptionExpanded}
|
|
onBackClick={this.onBackClick.bind(this)}/>);
|
|
} else {
|
|
children.push(<Filters filters={this.state.filters} dispatch={this.dispatch.bind(this)} onClose={this.onCloseClick.bind(this)}/>);
|
|
children.push(<Listings
|
|
listings={this.state.listings}
|
|
dispatch={this.dispatch.bind(this)}
|
|
onListingClick={this.onListingClick.bind(this)}/>);
|
|
}
|
|
const content = (
|
|
<div className="right-content">
|
|
{children}
|
|
</div>);
|
|
|
|
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 (
|
|
<div id="container">
|
|
<div id="header">
|
|
<a className="hamburger-menu">K</a>
|
|
<span className="title">Kiwi</span>
|
|
<input
|
|
id="gmaps-places-input"
|
|
placeholder="Unesite adresu, naselje ili grad"
|
|
className="where-to"
|
|
type="text"></input>
|
|
<div className="view-types">
|
|
<a className="view-type-left">
|
|
<i className="btn-select-map fa fa-list"></i>
|
|
</a>
|
|
<a className="view-type-right">
|
|
<i className="view-type-map-icon fa fa-map-marker"></i>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="right" style={rightStyle} className={rightClass}>
|
|
{this.renderRightContent()}
|
|
</div>
|
|
|
|
<div id="left" style={leftStyle} className={leftClass}>
|
|
<div id="map" ref="map">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
}
|
|
export default Main;
|