homeflowjs 0.7.29 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions/properties.actions.js +5 -0
- package/actions/properties.types.js +1 -0
- package/branches/branch-map/branch-map.component.jsx +7 -1
- package/package.json +1 -1
- package/properties/properties-display/properties-display.component.jsx +95 -0
- package/properties/properties-grid/properties-grid.component.jsx +10 -44
- package/properties/properties-list/properties-list.component.jsx +10 -48
- package/properties/properties-map/draggable-map.js +115 -62
- package/properties/properties-map/drawable-map.js +61 -45
- package/properties/properties-map/properties-map.component.jsx +7 -2
- package/properties/property-results/property-results.component.jsx +48 -11
- package/reducers/properties.reducer.js +21 -14
- package/reducers/properties.reducer.test.js +8 -0
- package/search/bedrooms-select/bedrooms-select.component.jsx +7 -3
- package/search/property-search/property-search.js +3 -1
- package/search/search-form/search-form.component.jsx +5 -1
|
@@ -32,6 +32,8 @@ class BranchMap extends React.Component {
|
|
|
32
32
|
zoom,
|
|
33
33
|
disableStreetview,
|
|
34
34
|
custom,
|
|
35
|
+
iconConfig,
|
|
36
|
+
fullscreenControl,
|
|
35
37
|
} = this.props;
|
|
36
38
|
|
|
37
39
|
// Should this be added to Redux?
|
|
@@ -45,6 +47,8 @@ class BranchMap extends React.Component {
|
|
|
45
47
|
scrollWheel,
|
|
46
48
|
zoom,
|
|
47
49
|
streetViewControl: !disableStreetview,
|
|
50
|
+
zoomControl: false,
|
|
51
|
+
fullscreenControl: false,
|
|
48
52
|
};
|
|
49
53
|
|
|
50
54
|
if (custom === 'simple_bw') {
|
|
@@ -52,9 +56,11 @@ class BranchMap extends React.Component {
|
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
const map = new google.maps.Map(document.getElementById('hfjs-branch-map'), options);
|
|
55
|
-
|
|
59
|
+
|
|
60
|
+
new google.maps.Marker({
|
|
56
61
|
position: { lat: branch.lat, lng: branch.lng },
|
|
57
62
|
map,
|
|
63
|
+
icon: iconConfig.iconUrl,
|
|
58
64
|
});
|
|
59
65
|
}
|
|
60
66
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { connect } from 'react-redux';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
4
|
+
|
|
5
|
+
import { handleScroll, propertiesByPage } from '../property-utils/property-utils';
|
|
6
|
+
import { uniqueKey } from '../../utils';
|
|
7
|
+
|
|
8
|
+
const ConditionalWrapper = ({ condition, wrapper, children }) => (
|
|
9
|
+
condition ? wrapper(children) : children
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const PropertiesDisplay = ({
|
|
13
|
+
properties,
|
|
14
|
+
Item,
|
|
15
|
+
displayType,
|
|
16
|
+
infiniteScroll,
|
|
17
|
+
inserts,
|
|
18
|
+
...other
|
|
19
|
+
}) => {
|
|
20
|
+
const onScroll = () => {
|
|
21
|
+
handleScroll(infiniteScroll);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
window.addEventListener('scroll', onScroll);
|
|
26
|
+
|
|
27
|
+
return function cleanUp() {
|
|
28
|
+
window.removeEventListener('scroll', onScroll);
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
if (!properties.length) {
|
|
33
|
+
return (
|
|
34
|
+
<p>There were no properties matching your search.</p>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
const addWrapper = displayType === 'list';
|
|
38
|
+
|
|
39
|
+
const items = propertiesByPage(properties).map((page) => (
|
|
40
|
+
<ConditionalWrapper
|
|
41
|
+
condition={addWrapper}
|
|
42
|
+
wrapper={(children) => (
|
|
43
|
+
<div
|
|
44
|
+
data-result-page={page[0].resultPage}
|
|
45
|
+
key={uniqueKey()}
|
|
46
|
+
className={`clearfix results-page--${displayType}`}
|
|
47
|
+
>
|
|
48
|
+
{children}
|
|
49
|
+
</div>
|
|
50
|
+
)}
|
|
51
|
+
>
|
|
52
|
+
{page.map((property, index) => {
|
|
53
|
+
/**
|
|
54
|
+
* TODO: Allow for multiple inserts
|
|
55
|
+
* This code only allows one insert from the inserts array to be show at a time
|
|
56
|
+
*/
|
|
57
|
+
if (inserts && (index % inserts[0].frequency) === 0 && index !== 0) {
|
|
58
|
+
return (
|
|
59
|
+
<>
|
|
60
|
+
{inserts[0].component}
|
|
61
|
+
<Item key={property.property_id} property={property} {...other} />
|
|
62
|
+
</>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return (
|
|
66
|
+
<Item key={property.property_id} property={property} {...other} />
|
|
67
|
+
);
|
|
68
|
+
})}
|
|
69
|
+
</ConditionalWrapper>
|
|
70
|
+
));
|
|
71
|
+
|
|
72
|
+
return (
|
|
73
|
+
<div className={`hf-property-results hf-property-results__${displayType}`}>
|
|
74
|
+
{items}
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
PropertiesDisplay.propTypes = {
|
|
80
|
+
properties: PropTypes.array.isRequired,
|
|
81
|
+
Item: PropTypes.elementType.isRequired,
|
|
82
|
+
displayType: PropTypes.string.isRequired,
|
|
83
|
+
infiniteScroll: PropTypes.bool.isRequired,
|
|
84
|
+
inserts: PropTypes.array,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
PropertiesDisplay.defaultProps = {
|
|
88
|
+
inserts: null,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const mapStateToProps = (state) => ({
|
|
92
|
+
properties: state.properties.properties || [],
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
export default connect(mapStateToProps)(PropertiesDisplay);
|
|
@@ -1,52 +1,18 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { connect } from 'react-redux';
|
|
1
|
+
import React from 'react';
|
|
3
2
|
import PropTypes from 'prop-types';
|
|
4
3
|
|
|
5
|
-
import
|
|
6
|
-
import { handleScroll, propertiesByPage } from '../property-utils/property-utils';
|
|
4
|
+
import PropertiesDisplay from '../properties-display/properties-display.component';
|
|
7
5
|
|
|
8
|
-
const PropertiesGrid = ({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return function cleanUp() {
|
|
17
|
-
window.removeEventListener('scroll', onScroll);
|
|
18
|
-
};
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
if (!properties.length) {
|
|
22
|
-
return (
|
|
23
|
-
<p>There were no properties matching your search.</p>
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const items = propertiesByPage(properties).map((page) =>
|
|
28
|
-
page.map((property) => (
|
|
29
|
-
<GridItem key={property.property_id} property={property} />
|
|
30
|
-
)
|
|
31
|
-
)).flat();
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<div className="hf-property-results hf-property-results__list">
|
|
35
|
-
<div className="clearfix results-page--grid">
|
|
36
|
-
{items}
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
};
|
|
6
|
+
const PropertiesGrid = ({ GridItem, ...other }) => (
|
|
7
|
+
<PropertiesDisplay
|
|
8
|
+
Item={GridItem}
|
|
9
|
+
displayType="grid"
|
|
10
|
+
{...other}
|
|
11
|
+
/>
|
|
12
|
+
);
|
|
41
13
|
|
|
42
14
|
PropertiesGrid.propTypes = {
|
|
43
|
-
properties: PropTypes.array.isRequired,
|
|
44
15
|
GridItem: PropTypes.elementType.isRequired,
|
|
45
|
-
infiniteScroll: PropTypes.bool.isRequired,
|
|
46
16
|
};
|
|
47
17
|
|
|
48
|
-
|
|
49
|
-
properties: state.properties.properties,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
export default connect(mapStateToProps)(PropertiesGrid);
|
|
18
|
+
export default PropertiesGrid;
|
|
@@ -1,56 +1,18 @@
|
|
|
1
|
-
import React
|
|
2
|
-
import { connect } from 'react-redux';
|
|
1
|
+
import React from 'react';
|
|
3
2
|
import PropTypes from 'prop-types';
|
|
4
3
|
|
|
5
|
-
import
|
|
6
|
-
import { uniqueKey } from '../../utils';
|
|
4
|
+
import PropertiesDisplay from '../properties-display/properties-display.component'
|
|
7
5
|
|
|
8
|
-
const PropertiesList = ({
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return function cleanUp() {
|
|
17
|
-
window.removeEventListener('scroll', onScroll);
|
|
18
|
-
};
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
const propertiesToRender = properties || [];
|
|
22
|
-
|
|
23
|
-
const items = propertiesByPage(propertiesToRender).map((page) => (
|
|
24
|
-
<div
|
|
25
|
-
data-result-page={page[0].resultPage}
|
|
26
|
-
key={uniqueKey()}
|
|
27
|
-
className="clearfix results-page--list"
|
|
28
|
-
>
|
|
29
|
-
{page.map((property) => (
|
|
30
|
-
<ListItem key={property.property_id} property={property} />
|
|
31
|
-
))}
|
|
32
|
-
</div>
|
|
33
|
-
));
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<div className="hf-property-results hf-property-results__list">
|
|
37
|
-
{items}
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
};
|
|
6
|
+
const PropertiesList = ({ ListItem, ...other}) => (
|
|
7
|
+
<PropertiesDisplay
|
|
8
|
+
Item={ListItem}
|
|
9
|
+
displayType="list"
|
|
10
|
+
{...other}
|
|
11
|
+
/>
|
|
12
|
+
);
|
|
41
13
|
|
|
42
14
|
PropertiesList.propTypes = {
|
|
43
|
-
properties: PropTypes.array,
|
|
44
15
|
ListItem: PropTypes.elementType.isRequired,
|
|
45
|
-
infiniteScroll: PropTypes.bool.isRequired,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
PropertiesList.defaultProps = {
|
|
49
|
-
properties: [],
|
|
50
16
|
};
|
|
51
17
|
|
|
52
|
-
|
|
53
|
-
properties: state.properties.properties,
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
export default connect(mapStateToProps)(PropertiesList);
|
|
18
|
+
export default PropertiesList;
|
|
@@ -5,7 +5,7 @@ import base64 from '../../utils/base64';
|
|
|
5
5
|
import store from '../../store';
|
|
6
6
|
import { buildQueryString } from '../../search/property-search/property-search';
|
|
7
7
|
import { setPlace, setSearchField } from '../../actions/search.actions';
|
|
8
|
-
import { setProperties } from '../../actions/properties.actions';
|
|
8
|
+
import { setProperties, setSelectedMarker } from '../../actions/properties.actions';
|
|
9
9
|
import { setLoading } from '../../actions/app.actions';
|
|
10
10
|
|
|
11
11
|
const element = function (X, Y) {
|
|
@@ -23,6 +23,18 @@ export default class DraggableMap {
|
|
|
23
23
|
this.render = this.render.bind(this);
|
|
24
24
|
this.generateMap = this.generateMap.bind(this);
|
|
25
25
|
this.properties = this.getProperties();
|
|
26
|
+
if (Homeflow.get('select_marker_on_click')) {
|
|
27
|
+
this.selectedMarker = null;
|
|
28
|
+
store.subscribe(() => {
|
|
29
|
+
const newSelectedMarker = store.getState().properties.selectedMarker;
|
|
30
|
+
const newSelectedPropertyID = newSelectedMarker ? newSelectedMarker.property.property_id : null;
|
|
31
|
+
const stateSelectedPropertyID = this.selectedMarker ? this.selectedMarker.property.property_id : null;
|
|
32
|
+
|
|
33
|
+
if (newSelectedPropertyID !== stateSelectedPropertyID) {
|
|
34
|
+
this.activateMarker(newSelectedMarker);
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
}
|
|
26
38
|
}
|
|
27
39
|
|
|
28
40
|
getSearch() {
|
|
@@ -42,7 +54,9 @@ export default class DraggableMap {
|
|
|
42
54
|
this.render();
|
|
43
55
|
this.buildPolygon();
|
|
44
56
|
const properties = this.properties;
|
|
45
|
-
if (properties != null) {
|
|
57
|
+
if (properties != null) {
|
|
58
|
+
this.setMarkersFor(properties);
|
|
59
|
+
}
|
|
46
60
|
if (this.noLocationfound) { this.setToMarkeredBounds(); }
|
|
47
61
|
if (Homeflow.get('custom_map_zoom')) {
|
|
48
62
|
this.map.setZoom(Homeflow.get('custom_map_zoom'));
|
|
@@ -58,10 +72,12 @@ export default class DraggableMap {
|
|
|
58
72
|
// if (lastSearch = Ctesius.getUserHistoryCollection().last()) {
|
|
59
73
|
// Ctesius.storedPlace = lastSearch.get('place');
|
|
60
74
|
// }
|
|
75
|
+
|
|
61
76
|
this.generateMap();
|
|
62
77
|
if (!Homeflow.get('free_text_search')) { this.map.on('zoomend', () => (this.onMapDrag())); }
|
|
63
78
|
this.map.on('dragend', () => (this.onMapDrag()));
|
|
64
79
|
const _this = this;
|
|
80
|
+
|
|
65
81
|
return this.map.on('popupopen', function (e) {
|
|
66
82
|
Homeflow.kickEvent('map_marker_opened', e);
|
|
67
83
|
const px = _this.map.project(e.popup._latlng);
|
|
@@ -72,28 +88,39 @@ export default class DraggableMap {
|
|
|
72
88
|
});
|
|
73
89
|
}
|
|
74
90
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
91
|
+
activateMarker(marker) {
|
|
92
|
+
if (this.selectedMarker) {
|
|
93
|
+
this.selectedMarker.setIcon(this.generateMarkerIcon(this.selectedMarker.property));
|
|
94
|
+
}
|
|
95
|
+
this.selectedMarker = marker;
|
|
96
|
+
if (this.selectedMarker) this.selectedMarker.setIcon(this.generateMarkerIcon(marker.property));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
generateMarkerIcon(property) {
|
|
78
100
|
if (Homeflow.get('custom_property_pin') != null) {
|
|
79
|
-
|
|
101
|
+
return Homeflow.get('custom_property_pin')(property);
|
|
80
102
|
} else {
|
|
81
|
-
let left, left1, left2, left3, left4;
|
|
103
|
+
let left, left1, left2, left3, left4, left5;
|
|
82
104
|
const markerIconImage = (left = Homeflow.get('custom_map_icon')) != null ? left : '/assets/leaflet/marker-icon.png';
|
|
83
105
|
const markerIconSize = (left1 = Homeflow.get('custom_map_icon_size')) != null ? left1 : [25, 41];
|
|
84
106
|
const markerShadowUrl = (left2 = Homeflow.get('custom_map_shadow')) != null ? left2 : '/assets/leaflet/marker-shadow.png';
|
|
85
107
|
const markerShadowSize = (left3 = Homeflow.get('custom_map_shadow_icon_size')) != null ? left3 : [41, 41];
|
|
86
108
|
const pinAnchor = (left4 = Homeflow.get('custom_map_icon_offset')) != null ? left4 : [12, 41];
|
|
87
|
-
|
|
109
|
+
const shadowAnchor = (left5 = Homeflow.get('custom_map_shadow_anchor')) != null ? left5 : [12, 41];
|
|
110
|
+
|
|
111
|
+
return new L.Icon.Default({
|
|
88
112
|
iconUrl: markerIconImage,
|
|
89
113
|
iconSize: markerIconSize,
|
|
114
|
+
iconAnchor: pinAnchor,
|
|
90
115
|
shadowUrl: markerShadowUrl,
|
|
91
116
|
shadowSize: markerShadowSize,
|
|
92
|
-
|
|
117
|
+
shadowAnchor: shadowAnchor,
|
|
93
118
|
});
|
|
94
119
|
}
|
|
120
|
+
}
|
|
95
121
|
|
|
96
|
-
|
|
122
|
+
generateMarker(property) {
|
|
123
|
+
const marker = L.marker([property.lat, property.lng], { icon: this.generateMarkerIcon(property) });
|
|
97
124
|
|
|
98
125
|
// add the property to marker attributes so they can be accessed on click
|
|
99
126
|
marker.property = property;
|
|
@@ -115,11 +142,12 @@ export default class DraggableMap {
|
|
|
115
142
|
}
|
|
116
143
|
|
|
117
144
|
marker.on('click', e => Homeflow.kickEvent('map_marker_clicked', e.target));
|
|
118
|
-
|
|
145
|
+
if (Homeflow.get('select_marker_on_click')) {
|
|
146
|
+
marker.on('click', e => store.dispatch(setSelectedMarker(e.target)));
|
|
147
|
+
}
|
|
119
148
|
return window['map_marker_' + property.property_id] = marker;
|
|
120
149
|
}
|
|
121
150
|
|
|
122
|
-
|
|
123
151
|
generateGeoFeature(geo_feature) {
|
|
124
152
|
let left, left1, left2, left3;
|
|
125
153
|
const markerIconImage = (left = Homeflow.get('custom_map_icon')) != null ? left : (Homeflow.get('root_url') + 'assets/leaflet/marker-icon.png');
|
|
@@ -164,8 +192,11 @@ export default class DraggableMap {
|
|
|
164
192
|
|
|
165
193
|
generateMap(map_options) {
|
|
166
194
|
const zoomMax = Homeflow.get('custom_max_zoom') ? Homeflow.get('custom_max_zoom') : 16;
|
|
195
|
+
const zoomPosition = Homeflow.get('custom_map_zoom_location') ? Homeflow.get('custom_map_zoom_location') : '';
|
|
196
|
+
|
|
167
197
|
if (map_options == null) {
|
|
168
198
|
map_options = {
|
|
199
|
+
...(zoomPosition !== '') && {zoomControl: false},
|
|
169
200
|
minZoom: 6,
|
|
170
201
|
maxZoom: zoomMax,
|
|
171
202
|
scrollWheelZoom: Homeflow.get('enable_scroll_wheel_zoom'),
|
|
@@ -174,6 +205,7 @@ export default class DraggableMap {
|
|
|
174
205
|
}
|
|
175
206
|
|
|
176
207
|
this.map = new L.Map(this.element, map_options);
|
|
208
|
+
if (zoomPosition !== '') new L.Control.Zoom({ position: zoomPosition }).addTo(this.map);
|
|
177
209
|
|
|
178
210
|
const tileLayer = Homeflow.get('leaflet_layer');
|
|
179
211
|
let layer;
|
|
@@ -205,8 +237,10 @@ export default class DraggableMap {
|
|
|
205
237
|
}
|
|
206
238
|
}
|
|
207
239
|
|
|
208
|
-
|
|
240
|
+
setMarkersFor(properties) {
|
|
209
241
|
let bounds;
|
|
242
|
+
if (this.marker_layer != null) { this.map.removeLayer(this.marker_layer); }
|
|
243
|
+
if (!properties) { return null }
|
|
210
244
|
|
|
211
245
|
if (Homeflow.get('pin_clustering')) {
|
|
212
246
|
let radius = Homeflow.get('custom_clustering_radius');
|
|
@@ -247,23 +281,69 @@ export default class DraggableMap {
|
|
|
247
281
|
}
|
|
248
282
|
}
|
|
249
283
|
|
|
284
|
+
buildSubPolygon(polygon, extraPolygon, style = null) {
|
|
285
|
+
let bounds = [];
|
|
286
|
+
const points = [];
|
|
287
|
+
polygon.forEach(ar => {
|
|
288
|
+
const a = new L.LatLng(ar[1], ar[0]);
|
|
289
|
+
bounds.push(a);
|
|
290
|
+
return points.push(a);
|
|
291
|
+
});
|
|
292
|
+
polygon = new L.Polygon(points,
|
|
293
|
+
{ weight: 10, fill: true }
|
|
294
|
+
);
|
|
295
|
+
// @drawnItems.addLayer polygon
|
|
296
|
+
this.map.fire("draw:created", {
|
|
297
|
+
layer: polygon,
|
|
298
|
+
layerType: polygon.type,
|
|
299
|
+
i: 0,
|
|
300
|
+
placePoly: true, //Build subPolygon(s) is only used to draw place polygon or extended radius polygons so no need to update the search state with poly
|
|
301
|
+
additionalDrawing: extraPolygon,
|
|
302
|
+
polyStyle: style,
|
|
303
|
+
});
|
|
304
|
+
return new L.LatLngBounds(bounds);
|
|
305
|
+
}
|
|
306
|
+
buildSubPolygons(polygons) {
|
|
307
|
+
//TODO: Clear existing polygons
|
|
308
|
+
let bounds = null;
|
|
309
|
+
let extraPolygon = false;
|
|
310
|
+
polygons.forEach(polygon => {
|
|
311
|
+
const extraBounds = this.buildSubPolygon(polygon, extraPolygon);
|
|
312
|
+
extraPolygon = true;
|
|
313
|
+
if (bounds === null) {
|
|
314
|
+
bounds = extraBounds;
|
|
315
|
+
} else {
|
|
316
|
+
bounds.extend(extraBounds)
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
return bounds;
|
|
320
|
+
}
|
|
250
321
|
|
|
251
322
|
buildPolygon() {
|
|
252
|
-
|
|
253
|
-
if (Homeflow.get('enable_draw_a_map') && (
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
323
|
+
const search = this.getSearch();
|
|
324
|
+
if (Homeflow.get('enable_draw_a_map') && (search.poly != null)) {
|
|
325
|
+
const polygon = new L.Polygon.fromEncoded(search.poly);
|
|
326
|
+
const polygonBounds = polygon.getBounds();
|
|
327
|
+
|
|
257
328
|
this.map.fire("draw:created", {
|
|
258
329
|
layer: polygon,
|
|
259
|
-
layerType: polygon.type
|
|
260
|
-
|
|
261
|
-
);
|
|
262
|
-
return this.map.fitBounds(
|
|
330
|
+
layerType: polygon.type,
|
|
331
|
+
placePoly: false.valueOf,
|
|
332
|
+
});
|
|
333
|
+
return this.map.fitBounds(polygonBounds);
|
|
334
|
+
|
|
263
335
|
} else if (Homeflow.get('place') != null) {
|
|
264
336
|
let center;
|
|
265
337
|
const place = Homeflow.get('place');
|
|
266
|
-
if (
|
|
338
|
+
if (search.expandedPolygon && Homeflow.get('enable_polygon_radius_search')) {
|
|
339
|
+
const expandedStyle = { weight: 2, dashArray: "8 8", color: '#000' }
|
|
340
|
+
if (place.polygon.length === 1) this.buildSubPolygons(place.polygon);
|
|
341
|
+
|
|
342
|
+
const bounds = this.buildSubPolygon(search.expandedPolygon, true, expandedStyle);
|
|
343
|
+
|
|
344
|
+
return this.map.fitBounds(bounds);
|
|
345
|
+
|
|
346
|
+
} else if ((place.radius != null) && (place.radius !== '')) {
|
|
267
347
|
this.circle = new L.circle([place.lat, place.lng], place.radius * 1000, {
|
|
268
348
|
fill: false,
|
|
269
349
|
weight: 0
|
|
@@ -271,33 +351,16 @@ export default class DraggableMap {
|
|
|
271
351
|
this.map.addLayer(this.circle);
|
|
272
352
|
center = new L.LatLng(place.lat, place.lng);
|
|
273
353
|
return this.map.fitBounds(this.circle.getBounds());
|
|
354
|
+
|
|
274
355
|
} else if ((place.polygon != null) && (place.polygon.length > 0)) {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
polygon.forEach(ar => {
|
|
279
|
-
const a = new L.LatLng(ar[1], ar[0]);
|
|
280
|
-
bounds.push(a);
|
|
281
|
-
return points.push(a);
|
|
282
|
-
});
|
|
283
|
-
polygon = new L.Polygon(points,
|
|
284
|
-
{ weight: 10, fill: true }
|
|
285
|
-
);
|
|
286
|
-
// @drawnItems.addLayer polygon
|
|
287
|
-
return this.map.fire("draw:created", {
|
|
288
|
-
layer: polygon,
|
|
289
|
-
layerType: polygon.type,
|
|
290
|
-
i: 0
|
|
291
|
-
}
|
|
292
|
-
);
|
|
293
|
-
});
|
|
294
|
-
return this.map.fitBounds(new L.LatLngBounds(bounds));
|
|
356
|
+
const placeBounds = this.buildSubPolygons(place.polygon)
|
|
357
|
+
return this.map.fitBounds(placeBounds);
|
|
358
|
+
|
|
295
359
|
} else {
|
|
296
360
|
center = new L.LatLng(place.lat, place.lng);
|
|
297
361
|
return this.map.setView(center, 12);
|
|
298
362
|
}
|
|
299
363
|
} else {
|
|
300
|
-
//@map.setView([51.505, -0.09], 12)
|
|
301
364
|
return this.noLocationfound = true;
|
|
302
365
|
}
|
|
303
366
|
}
|
|
@@ -307,7 +370,8 @@ export default class DraggableMap {
|
|
|
307
370
|
if (!Homeflow.get('disable_draggable_map')) {
|
|
308
371
|
let url;
|
|
309
372
|
const bounds = this.getSearchableBounds();
|
|
310
|
-
|
|
373
|
+
const has_expanded = this.getSearch().expandedPolygon;
|
|
374
|
+
if (this.mapLoadedTimes === 1 || has_expanded ) {
|
|
311
375
|
url = `/search.ljson?${buildQueryString(this.getSearch())}/view-${bounds.toBBoxString()}&count=50`;
|
|
312
376
|
} else {
|
|
313
377
|
// unset place
|
|
@@ -327,20 +391,19 @@ export default class DraggableMap {
|
|
|
327
391
|
if (Homeflow.get('map_branch_id') != null) {
|
|
328
392
|
url = url + "&branch_id=" + Homeflow.get('map_branch_id');
|
|
329
393
|
}
|
|
330
|
-
Homeflow.kickEvent('before_draggable_map_updated');
|
|
394
|
+
Homeflow.kickEvent('before_draggable_map_updated');
|
|
331
395
|
return fetch(url)
|
|
332
396
|
.then((response) => response.json())
|
|
333
397
|
.then(json => {
|
|
334
398
|
Homeflow.kickEvent('draggable_map_updated', json);
|
|
335
399
|
this._running_update = false;
|
|
336
|
-
|
|
400
|
+
|
|
337
401
|
this.properties = json.properties;
|
|
338
402
|
// TODO: figure out what 'tile view' is
|
|
339
403
|
// if (this.tile_view != null) {
|
|
340
404
|
// this.tile_view = new Ctesius.Views.Tiles({ collection: this.collection });
|
|
341
405
|
// }
|
|
342
|
-
|
|
343
|
-
return this.addMarkersFor(this.properties);
|
|
406
|
+
return this.setMarkersFor(this.properties);
|
|
344
407
|
});
|
|
345
408
|
}
|
|
346
409
|
}
|
|
@@ -449,30 +512,22 @@ export default class DraggableMap {
|
|
|
449
512
|
return params.join("/");
|
|
450
513
|
}
|
|
451
514
|
|
|
452
|
-
|
|
453
515
|
updateURL() {
|
|
454
516
|
let new_location = window.location.pathname.replace(/(.*\/sales|lettings).*/, '$1');
|
|
455
517
|
new_location = new_location + '/' + this.searchToHomeflowUrlParams(true) + window.location.hash;
|
|
456
518
|
return window.history.replaceState("NaN", document.title, new_location);
|
|
457
519
|
}
|
|
458
520
|
|
|
459
|
-
|
|
460
|
-
|
|
461
521
|
onPolygonDrawn(layer, with_update) {
|
|
462
522
|
let geo_url, url;
|
|
463
523
|
if (with_update == null) { with_update = true; }
|
|
464
524
|
const s = this.getSearch();
|
|
465
|
-
|
|
466
|
-
if (with_update && ((this.first != null) && (this.first === false))) {
|
|
525
|
+
if (with_update) {
|
|
467
526
|
const encodedPoly = L.PolylineUtil.encode(this.buildDrawnPolygon(layer));
|
|
468
527
|
store.dispatch(setSearchField({ poly: encodedPoly }));
|
|
469
528
|
s.poly = encodedPoly;
|
|
470
|
-
// store.dispatch(setSearchField({ poly: L.PolylineUtil.encode(this.buildDrawnPolygon(layer)) }));
|
|
471
|
-
// s.poly = L.PolylineUtil.encode(this.buildDrawnPolygon(layer));
|
|
472
529
|
}
|
|
473
530
|
|
|
474
|
-
// debugger;
|
|
475
|
-
|
|
476
531
|
if (s.poly) {
|
|
477
532
|
url = `/search.ljson?${buildQueryString(s)}&count=50`;
|
|
478
533
|
geo_url = `geo_features.ljson?${buildQueryString(s)}&count=50`;
|
|
@@ -494,7 +549,6 @@ export default class DraggableMap {
|
|
|
494
549
|
// return this.addGeoMarkers(res);
|
|
495
550
|
// });
|
|
496
551
|
// }
|
|
497
|
-
this.addMarkersFor(this.properties);
|
|
498
552
|
|
|
499
553
|
// TODO: Rewrite this to use fetch() and update redux store
|
|
500
554
|
fetch(url)
|
|
@@ -506,14 +560,13 @@ export default class DraggableMap {
|
|
|
506
560
|
Homeflow.kickEvent('clear_search_box');
|
|
507
561
|
Homeflow.kickEvent('draggable_map_updated', json);
|
|
508
562
|
this._running_update = false;
|
|
509
|
-
if (this.marker_layer != null) { this.map.removeLayer(this.marker_layer); }
|
|
510
563
|
this.properties = json.properties;
|
|
511
564
|
|
|
512
565
|
// if (this.tile_view != null) {
|
|
513
566
|
// this.tile_view = new Ctesius.Views.Tiles({ collection: this.collection });
|
|
514
567
|
// }
|
|
515
568
|
|
|
516
|
-
return this.
|
|
569
|
+
return this.setMarkersFor(json.properties);
|
|
517
570
|
})
|
|
518
571
|
// return $.get(url, (res, status, xhr) => {
|
|
519
572
|
// s.set('performed_data', res);
|
|
@@ -529,7 +582,7 @@ export default class DraggableMap {
|
|
|
529
582
|
// }
|
|
530
583
|
// else { }
|
|
531
584
|
// //@tile_view.collection(@collection)
|
|
532
|
-
// return this.
|
|
585
|
+
// return this.setMarkersFor(this.collection.models);
|
|
533
586
|
// });
|
|
534
587
|
}
|
|
535
588
|
|
|
@@ -27,12 +27,12 @@ export default class DrawableMap extends DraggableMap {
|
|
|
27
27
|
if (this.drawnItems.getLayers().length === 0) {
|
|
28
28
|
return super.onMapDrag();
|
|
29
29
|
} else {
|
|
30
|
-
return this.onPolygonDrawn(this.drawnItems.getLayers()[0],
|
|
30
|
+
return this.onPolygonDrawn(this.drawnItems.getLayers()[0], false);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
repositionDrawControls() {
|
|
35
|
-
let newControlsContainer =
|
|
35
|
+
let newControlsContainer = Homeflow.get('draw_controls_container');
|
|
36
36
|
if (newControlsContainer) {
|
|
37
37
|
const oldControlsContainer = this.drawControl.getContainer().parentNode;
|
|
38
38
|
newControlsContainer = document.getElementById(newControlsContainer);
|
|
@@ -47,65 +47,81 @@ export default class DrawableMap extends DraggableMap {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
generateMap(map_options) {
|
|
50
|
-
const zoomMax =
|
|
50
|
+
const zoomMax = Homeflow.get('custom_max_zoom') ? Homeflow.get('custom_max_zoom') : 16;
|
|
51
|
+
const drawLocation = Homeflow.get('custom_map_draw_location') ? Homeflow.get('custom_map_draw_location') : 'bottomleft';
|
|
52
|
+
|
|
51
53
|
map_options = {
|
|
52
54
|
minZoom: 6,
|
|
53
55
|
maxZoom: zoomMax,
|
|
54
|
-
scrollWheelZoom:
|
|
56
|
+
scrollWheelZoom: Homeflow.get('enable_scroll_wheel_zoom'),
|
|
55
57
|
'zoomControl': false,
|
|
56
|
-
dragging: !
|
|
58
|
+
dragging: !Homeflow.get('disable_drag_for_drawable_map')
|
|
57
59
|
};
|
|
60
|
+
if (!Homeflow.get('custom_map_zoom_location')) Homeflow.set('custom_map_zoom_location', 'topright');
|
|
61
|
+
|
|
58
62
|
super.generateMap(map_options);
|
|
59
63
|
this.drawnItems = new L.FeatureGroup();
|
|
60
64
|
this.map.addLayer(this.drawnItems);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
edit: {
|
|
69
|
-
featureGroup: this.drawnItems,
|
|
70
|
-
remove: true,
|
|
71
|
-
},
|
|
72
|
-
draw: {
|
|
73
|
-
freehand: {
|
|
65
|
+
if (!Homeflow.get('disable_draw_a_search')) {
|
|
66
|
+
this.titleControl = new L.Control.Title({position: drawLocation});
|
|
67
|
+
this.map.addControl(this.titleControl);
|
|
68
|
+
|
|
69
|
+
this.drawControl = new L.Control.Draw({
|
|
70
|
+
position: drawLocation,
|
|
71
|
+
edit: {
|
|
74
72
|
featureGroup: this.drawnItems,
|
|
75
|
-
|
|
73
|
+
remove: true,
|
|
74
|
+
},
|
|
75
|
+
draw: {
|
|
76
|
+
freehand: {
|
|
77
|
+
featureGroup: this.drawnItems,
|
|
78
|
+
simplifyFunction: Hull.parseVertices
|
|
79
|
+
}
|
|
76
80
|
}
|
|
77
|
-
}
|
|
78
|
-
});
|
|
81
|
+
});
|
|
79
82
|
|
|
80
|
-
|
|
83
|
+
this.map.addControl(this.drawControl);
|
|
84
|
+
}
|
|
81
85
|
|
|
82
86
|
this.map.on("draw:created", e => {
|
|
83
|
-
|
|
84
|
-
if (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
const { additionalDrawing, layer, polyStyle } = e
|
|
88
|
+
if (!additionalDrawing) {
|
|
89
|
+
this.drawnItems.clearLayers();
|
|
90
|
+
if (this.marker_layer) { this.map.removeLayer(this.marker_layer); }
|
|
91
|
+
if (this.geo_marker_layer != null) { this.map.removeLayer(this.geo_marker_layer); }
|
|
92
|
+
if (this.circle != null) { this.map.removeLayer(this.circle); }
|
|
93
|
+
}
|
|
87
94
|
// TODO: where does `poly` come from?
|
|
88
95
|
// const poly_updater = map => Ctesius.getSearch().set('poly', decodeURIComponent(poly));
|
|
89
|
-
|
|
96
|
+
if (!e.placePoly) {
|
|
97
|
+
const poly_updater = map => store.dispatch(setSearchField({ poly: base64.encode(poly) }));
|
|
98
|
+
Homeflow.registerEvent('properties_map_toggle_view_displayed', poly_updater, 1);
|
|
99
|
+
}
|
|
100
|
+
if (polyStyle) {
|
|
101
|
+
if (polyStyle.color) layer.options.color = polyStyle.color;
|
|
102
|
+
if (polyStyle.weight) layer.options.weight = polyStyle.weight;
|
|
103
|
+
if (polyStyle.dashArray) layer.options.dashArray = polyStyle.dashArray;
|
|
104
|
+
if (polyStyle.fillColor) layer.options.fillColor = polyStyle.fillColor;
|
|
105
|
+
else layer.options.fill = false;
|
|
106
|
+
if (polyStyle.fillOpacity) layer.options.fillOpacity = polyStyle.fillOpacity;
|
|
90
107
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
layer
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
layer.options.fillOpacity = 0.1;
|
|
99
|
-
if (Ctesius.getConfig('polygon_stroke_weight')) {
|
|
100
|
-
layer.options.weight = Ctesius.getConfig('polygon_stroke_weight');
|
|
108
|
+
} else {
|
|
109
|
+
layer.options.color = Homeflow.get('polygon_color');
|
|
110
|
+
layer.options.fillColor = Homeflow.get('polygon_fill_color');
|
|
111
|
+
layer.options.fillOpacity = 0.1;
|
|
112
|
+
if (Homeflow.get('polygon_stroke_weight')) {
|
|
113
|
+
layer.options.weight = Homeflow.get('polygon_stroke_weight');
|
|
114
|
+
}
|
|
101
115
|
}
|
|
102
116
|
|
|
103
117
|
var poly = layer.encodePath();
|
|
104
118
|
poly = encodeURIComponent(poly);
|
|
105
119
|
this.drawnItems.addLayer(layer);
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
|
|
121
|
+
this.onPolygonDrawn(layer, !e.placePoly);
|
|
122
|
+
if (!this.first && !e.placePoly) {
|
|
108
123
|
this.updateURL();
|
|
124
|
+
if (this.first) { this.first = false; }
|
|
109
125
|
|
|
110
126
|
// TODO: why do we need to make this request that doesn't do anything?
|
|
111
127
|
// $.get(window.location);
|
|
@@ -118,8 +134,6 @@ export default class DrawableMap extends DraggableMap {
|
|
|
118
134
|
}
|
|
119
135
|
|
|
120
136
|
Homeflow.kickEvent('poly_url_refresh');
|
|
121
|
-
|
|
122
|
-
if (this.first) { this.first = false; }
|
|
123
137
|
});
|
|
124
138
|
|
|
125
139
|
|
|
@@ -141,7 +155,7 @@ export default class DrawableMap extends DraggableMap {
|
|
|
141
155
|
});
|
|
142
156
|
|
|
143
157
|
this.map.on("draw:drawstop", e => {
|
|
144
|
-
if (
|
|
158
|
+
if (Homeflow.get('fit_bounds_after_draw')) {
|
|
145
159
|
setTimeout((() => {
|
|
146
160
|
if (this.marker_layer.getLayers().length > 0) {
|
|
147
161
|
const bounds = [this.drawnItems.getBounds()];
|
|
@@ -176,12 +190,13 @@ export default class DrawableMap extends DraggableMap {
|
|
|
176
190
|
theMap.removeLayer(layer);
|
|
177
191
|
}
|
|
178
192
|
});
|
|
179
|
-
this.
|
|
193
|
+
this.onPolygonDrawn(this.drawnItems.getLayers()[0], true);
|
|
194
|
+
|
|
180
195
|
return Homeflow.kickEvent('editbannertoggled');
|
|
181
196
|
});
|
|
182
197
|
|
|
183
198
|
this.map.on("draw:deletestart", e => {
|
|
184
|
-
if (
|
|
199
|
+
if (Homeflow.get('instant_delete_polygon')) {
|
|
185
200
|
this.drawnItems.clearLayers();
|
|
186
201
|
if (this.marker_layer) { this.map.removeLayer(this.marker_layer); }
|
|
187
202
|
if (this.geo_marker_layer != null) { return this.map.removeLayer(this.geo_marker_layer); }
|
|
@@ -197,7 +212,8 @@ export default class DrawableMap extends DraggableMap {
|
|
|
197
212
|
let countOfEditedLayers = 0;
|
|
198
213
|
layers.eachLayer(layer => {
|
|
199
214
|
const poly = encodeURIComponent(layer.encodePath());
|
|
200
|
-
|
|
215
|
+
|
|
216
|
+
this.onPolygonDrawn(layer, true);
|
|
201
217
|
this.updateURL();
|
|
202
218
|
window.location.hash = "map/" + poly;
|
|
203
219
|
countOfEditedLayers++;
|
|
@@ -48,9 +48,10 @@ window.$ = () => ({
|
|
|
48
48
|
// )
|
|
49
49
|
// end
|
|
50
50
|
|
|
51
|
-
const PropertiesMap = ({ leaflet, gmapKey }) => {
|
|
51
|
+
const PropertiesMap = ({ leaflet, gmapKey, googleLayer }) => {
|
|
52
52
|
const addLegacyMaps = () => {
|
|
53
|
-
|
|
53
|
+
const needsGoogle = !leaflet || googleLayer;
|
|
54
|
+
if (needsGoogle && !document.getElementById('hfjs-gmaps') && gmapKey) {
|
|
54
55
|
const gmapScript = document.createElement('script');
|
|
55
56
|
gmapScript.setAttribute('src', `https://maps.google.com/maps/api/js?key=${gmapKey}`);
|
|
56
57
|
gmapScript.setAttribute('id', 'hfjs-gmaps');
|
|
@@ -63,6 +64,8 @@ const PropertiesMap = ({ leaflet, gmapKey }) => {
|
|
|
63
64
|
script.setAttribute('id', 'hfjs-legacy-maps');
|
|
64
65
|
script.setAttribute('onload', 'window.initLegacyMap()');
|
|
65
66
|
document.head.appendChild(script);
|
|
67
|
+
} else {
|
|
68
|
+
window.initLegacyMap();
|
|
66
69
|
}
|
|
67
70
|
};
|
|
68
71
|
|
|
@@ -81,11 +84,13 @@ const PropertiesMap = ({ leaflet, gmapKey }) => {
|
|
|
81
84
|
PropertiesMap.propTypes = {
|
|
82
85
|
gmapKey: PropTypes.string,
|
|
83
86
|
leaflet: PropTypes.bool,
|
|
87
|
+
googleLayer: PropTypes.bool,
|
|
84
88
|
};
|
|
85
89
|
|
|
86
90
|
PropertiesMap.defaultProps = {
|
|
87
91
|
gmapKey: null,
|
|
88
92
|
leaflet: false,
|
|
93
|
+
googleLayer: false,
|
|
89
94
|
};
|
|
90
95
|
|
|
91
96
|
const mapStateToProps = (state) => ({
|
|
@@ -6,8 +6,7 @@ import {
|
|
|
6
6
|
} from 'react-router-dom';
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
8
8
|
|
|
9
|
-
import
|
|
10
|
-
import PropertiesGrid from '../properties-grid/properties-grid.component';
|
|
9
|
+
import PropertiesDisplay from '../properties-display/properties-display.component';
|
|
11
10
|
|
|
12
11
|
import './property-results.styles.scss';
|
|
13
12
|
|
|
@@ -22,34 +21,68 @@ const LazyPropertiesMap = (props) => (
|
|
|
22
21
|
const PropertyResults = ({
|
|
23
22
|
GridItem,
|
|
24
23
|
ListItem,
|
|
24
|
+
MapItem,
|
|
25
25
|
defaultView,
|
|
26
26
|
infiniteScroll,
|
|
27
27
|
noMap,
|
|
28
|
+
inserts,
|
|
29
|
+
...other
|
|
28
30
|
}) => (
|
|
29
31
|
<Router>
|
|
30
32
|
<Switch>
|
|
31
33
|
<Route path="/list">
|
|
32
|
-
<
|
|
34
|
+
<PropertiesDisplay
|
|
35
|
+
Item={ListItem}
|
|
36
|
+
displayType="list"
|
|
37
|
+
infiniteScroll={infiniteScroll}
|
|
38
|
+
inserts={inserts}
|
|
39
|
+
{...other}
|
|
40
|
+
/>
|
|
33
41
|
</Route>
|
|
34
42
|
|
|
35
43
|
<Route path="/grid">
|
|
36
|
-
<
|
|
44
|
+
<PropertiesDisplay
|
|
45
|
+
Item={GridItem}
|
|
46
|
+
displayType="grid"
|
|
47
|
+
infiniteScroll={infiniteScroll}
|
|
48
|
+
inserts={inserts}
|
|
49
|
+
{...other}
|
|
50
|
+
/>
|
|
37
51
|
</Route>
|
|
38
52
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
53
|
+
<Route path="/map">
|
|
54
|
+
{noMap ? (
|
|
55
|
+
<PropertiesDisplay
|
|
56
|
+
Item={MapItem}
|
|
57
|
+
displayType="map"
|
|
58
|
+
infiniteScroll={infiniteScroll}
|
|
59
|
+
inserts={inserts}
|
|
60
|
+
{...other}
|
|
61
|
+
/>
|
|
62
|
+
) : (
|
|
42
63
|
<LazyPropertiesMap />
|
|
43
|
-
|
|
44
|
-
|
|
64
|
+
)}
|
|
65
|
+
</Route>
|
|
45
66
|
|
|
46
67
|
{defaultView === 'grid' ? (
|
|
47
68
|
<Route>
|
|
48
|
-
<
|
|
69
|
+
<PropertiesDisplay
|
|
70
|
+
Item={GridItem}
|
|
71
|
+
displayType="grid"
|
|
72
|
+
infiniteScroll={infiniteScroll}
|
|
73
|
+
inserts={inserts}
|
|
74
|
+
{...other}
|
|
75
|
+
/>
|
|
49
76
|
</Route>
|
|
50
77
|
) : (
|
|
51
78
|
<Route>
|
|
52
|
-
<
|
|
79
|
+
<PropertiesDisplay
|
|
80
|
+
Item={ListItem}
|
|
81
|
+
displayType="list"
|
|
82
|
+
infiniteScroll={infiniteScroll}
|
|
83
|
+
inserts={inserts}
|
|
84
|
+
{...other}
|
|
85
|
+
/>
|
|
53
86
|
</Route>
|
|
54
87
|
)}
|
|
55
88
|
</Switch>
|
|
@@ -59,17 +92,21 @@ const PropertyResults = ({
|
|
|
59
92
|
PropertyResults.propTypes = {
|
|
60
93
|
GridItem: PropTypes.elementType,
|
|
61
94
|
ListItem: PropTypes.elementType,
|
|
95
|
+
MapItem: PropTypes.elementType,
|
|
62
96
|
defaultView: PropTypes.string,
|
|
63
97
|
infiniteScroll: PropTypes.bool,
|
|
64
98
|
noMap: PropTypes.bool,
|
|
99
|
+
inserts: PropTypes.array,
|
|
65
100
|
};
|
|
66
101
|
|
|
67
102
|
PropertyResults.defaultProps = {
|
|
68
103
|
GridItem: null,
|
|
69
104
|
ListItem: null,
|
|
105
|
+
MapItem: null,
|
|
70
106
|
defaultView: 'list',
|
|
71
107
|
infiniteScroll: false,
|
|
72
108
|
noMap: false,
|
|
109
|
+
inserts: null,
|
|
73
110
|
};
|
|
74
111
|
|
|
75
112
|
export default PropertyResults;
|
|
@@ -4,6 +4,7 @@ const INITIAL_STATE = {
|
|
|
4
4
|
properties: [],
|
|
5
5
|
savedProperties: [],
|
|
6
6
|
pagination: {},
|
|
7
|
+
selectedMarker: null,
|
|
7
8
|
propertyLinks: {
|
|
8
9
|
next: '',
|
|
9
10
|
previous: '',
|
|
@@ -37,11 +38,11 @@ const propertiesReducer = (state = INITIAL_STATE, action) => {
|
|
|
37
38
|
...state,
|
|
38
39
|
propertyLinks: action.payload,
|
|
39
40
|
};
|
|
40
|
-
case PropertiesActionTypes.TOGGLE_SAVED_PROPERTY:
|
|
41
|
+
case PropertiesActionTypes.TOGGLE_SAVED_PROPERTY: {
|
|
41
42
|
const propertyId = parseInt(action.payload.propertyId, 10);
|
|
42
43
|
const newSavedProperties = [...state.savedProperties];
|
|
43
44
|
|
|
44
|
-
const index = newSavedProperties.findIndex(({ property_id }) =>
|
|
45
|
+
const index = newSavedProperties.findIndex(({ property_id: searchId }) => searchId === propertyId);
|
|
45
46
|
|
|
46
47
|
if (index > -1) {
|
|
47
48
|
newSavedProperties.splice(index, 1);
|
|
@@ -53,22 +54,28 @@ const propertiesReducer = (state = INITIAL_STATE, action) => {
|
|
|
53
54
|
return {
|
|
54
55
|
...state,
|
|
55
56
|
savedProperties: newSavedProperties,
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
// need to find the property from the propertiesReducer and add it here
|
|
59
|
-
const property = state.properties.find(({ property_id }) => property_id === propertyId);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
60
59
|
|
|
61
|
-
|
|
60
|
+
// need to find the property from the propertiesReducer and add it here
|
|
61
|
+
const property = state.properties.find(({ property_id: searchId }) => searchId === propertyId);
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
localStorage.setItem('savedProperties', JSON.stringify(newSavedProperties));
|
|
65
|
-
}
|
|
63
|
+
newSavedProperties.push(property || state.property);
|
|
66
64
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
savedProperties: newSavedProperties,
|
|
70
|
-
}
|
|
65
|
+
if (!action.payload.userLoggedIn) {
|
|
66
|
+
localStorage.setItem('savedProperties', JSON.stringify(newSavedProperties));
|
|
71
67
|
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
...state,
|
|
71
|
+
savedProperties: newSavedProperties,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
case PropertiesActionTypes.SET_SELECTED_MARKER:
|
|
75
|
+
return {
|
|
76
|
+
...state,
|
|
77
|
+
selectedMarker: action.payload,
|
|
78
|
+
};
|
|
72
79
|
default:
|
|
73
80
|
return state;
|
|
74
81
|
}
|
|
@@ -15,6 +15,14 @@ describe('propertiesReducer', () => {
|
|
|
15
15
|
expect(reducedState.pagination).toEqual({ page: 2 });
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
+
it('Sets the selected propertymarker when it receives the SET_SELECTED_MARKER action', () => {
|
|
19
|
+
const state = {};
|
|
20
|
+
const leafletMaker = { lat: 1, lng: 2 };
|
|
21
|
+
const reducedState = propertiesReducer(state, { type: 'SET_SELECTED_MARKER', payload: leafletMaker });
|
|
22
|
+
|
|
23
|
+
expect(reducedState.selectedMarker).toEqual(leafletMaker);
|
|
24
|
+
});
|
|
25
|
+
|
|
18
26
|
it('Sets the saved properties when it receives the SET_SAVED_PROPERTIES action', () => {
|
|
19
27
|
const state = { savedProperties: [] };
|
|
20
28
|
const reducedState = propertiesReducer(state, { type: 'SET_SAVED_PROPERTIES', payload: [1, 2, 3, 4, 5] });
|
|
@@ -17,6 +17,7 @@ const NormalSelect = ({
|
|
|
17
17
|
optionClass,
|
|
18
18
|
minBeds,
|
|
19
19
|
maxBeds,
|
|
20
|
+
placeholder,
|
|
20
21
|
...otherProps
|
|
21
22
|
}) => (
|
|
22
23
|
<select
|
|
@@ -32,7 +33,7 @@ const NormalSelect = ({
|
|
|
32
33
|
title={`${type} beds`}
|
|
33
34
|
className={optionClass}
|
|
34
35
|
>
|
|
35
|
-
{capitalizeFirstLetter(type)}. bedrooms
|
|
36
|
+
{placeholder || `${capitalizeFirstLetter(type)}. bedrooms`}
|
|
36
37
|
</option>
|
|
37
38
|
{bedValues.map((_, i) => (
|
|
38
39
|
<option
|
|
@@ -55,6 +56,7 @@ const ReactSelect = (props) => {
|
|
|
55
56
|
className,
|
|
56
57
|
styles,
|
|
57
58
|
value,
|
|
59
|
+
placeholder,
|
|
58
60
|
} = props;
|
|
59
61
|
|
|
60
62
|
const bedOptions = bedValues.map(bedValue => (
|
|
@@ -69,7 +71,7 @@ const ReactSelect = (props) => {
|
|
|
69
71
|
className={className}
|
|
70
72
|
options={bedOptions}
|
|
71
73
|
styles={styles}
|
|
72
|
-
placeholder={`${capitalizeFirstLetter(type)} bedrooms`}
|
|
74
|
+
placeholder={placeholder || `${capitalizeFirstLetter(type)} bedrooms`}
|
|
73
75
|
value={bedOptions.find(option => option.value === value)}
|
|
74
76
|
setValue={() => value}
|
|
75
77
|
isSearchable={false}
|
|
@@ -118,12 +120,14 @@ BedroomsSelect.propTypes = {
|
|
|
118
120
|
maxBeds: PropTypes.number,
|
|
119
121
|
setSearchField: PropTypes.func.isRequired,
|
|
120
122
|
optionClass: PropTypes.string,
|
|
123
|
+
placeholder: PropTypes.string,
|
|
121
124
|
};
|
|
122
125
|
|
|
123
126
|
BedroomsSelect.defaultProps = {
|
|
124
127
|
bedValues: defaultBedrooms,
|
|
125
128
|
optionClass: '',
|
|
126
|
-
|
|
129
|
+
placeholder: null,
|
|
130
|
+
};
|
|
127
131
|
|
|
128
132
|
const mapStateToProps = ({ search: { currentSearch } }) => ({
|
|
129
133
|
minBeds: currentSearch.minBeds,
|
|
@@ -27,7 +27,9 @@ export const buildQueryString = (search) => {
|
|
|
27
27
|
if (Array.isArray(value) && !value.length) continue;
|
|
28
28
|
// only include either q or place ID
|
|
29
29
|
if (key === 'q' && !search.isQuerySearch
|
|
30
|
-
|| key === 'placeId' && search.isQuerySearch
|
|
30
|
+
|| key === 'placeId' && search.isQuerySearch
|
|
31
|
+
|| key === 'place' && search.isQuerySearch
|
|
32
|
+
|| key === 'poly' && search.isQuerySearch) continue;
|
|
31
33
|
|
|
32
34
|
// Don't include branch_id if a search term has been entered
|
|
33
35
|
if (key === 'branch_id' && search.isQuerySearch) continue;
|
|
@@ -45,6 +45,11 @@ class SearchForm extends Component {
|
|
|
45
45
|
q: place.name + (place.county_name ? `, ${place.county_name}` : ''),
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
|
+
const expandedPolygon = Homeflow.get('expanded_polygon');
|
|
49
|
+
if (expandedPolygon) {
|
|
50
|
+
setSearchField({ expandedPolygon });
|
|
51
|
+
setInitialSearch({ expandedPolygon });
|
|
52
|
+
}
|
|
48
53
|
|
|
49
54
|
if (defaultChannel) setSearchField({ channel: defaultChannel });
|
|
50
55
|
|
|
@@ -55,7 +60,6 @@ class SearchForm extends Component {
|
|
|
55
60
|
|
|
56
61
|
handleSubmit(e) {
|
|
57
62
|
const { search, submitCallback } = this.props;
|
|
58
|
-
|
|
59
63
|
e.preventDefault();
|
|
60
64
|
|
|
61
65
|
if (submitCallback) submitCallback();
|