homeflowjs 0.13.43 → 0.13.45
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/instant-valuation/instant-valuation/instant-valuation.component.jsx +8 -0
- package/instant-valuation/result-step/result-step.component.jsx +10 -8
- package/instant-valuation/result-step/valuation-map.component.jsx +22 -6
- package/package.json +1 -1
- package/properties/properties-map/geonames-map.js +29 -11
- package/utils/index.js +36 -4
@@ -25,6 +25,8 @@ const INITIAL_STATE = {
|
|
25
25
|
properties: [],
|
26
26
|
property_type: '',
|
27
27
|
bedrooms: '',
|
28
|
+
lat: '',
|
29
|
+
lng: '',
|
28
30
|
},
|
29
31
|
lead: {
|
30
32
|
first_name: '',
|
@@ -122,6 +124,7 @@ class InstantValuation extends Component {
|
|
122
124
|
lead_url_referrer: referrerURL,
|
123
125
|
};
|
124
126
|
|
127
|
+
|
125
128
|
const params = flatten({ search: restOfSearch, lead });
|
126
129
|
|
127
130
|
const query = new URLSearchParams(params);
|
@@ -200,6 +203,11 @@ class InstantValuation extends Component {
|
|
200
203
|
...prevState.lead,
|
201
204
|
full_address: this.constructor.formatAddress(json.Addresses[0]),
|
202
205
|
},
|
206
|
+
search: {
|
207
|
+
...prevState.search,
|
208
|
+
lat: json.Latitude,
|
209
|
+
lng: json.Longitude,
|
210
|
+
},
|
203
211
|
}));
|
204
212
|
|
205
213
|
return null;
|
@@ -149,18 +149,20 @@ const ResultStep = ({
|
|
149
149
|
</div>
|
150
150
|
)}
|
151
151
|
|
152
|
-
|
152
|
+
<ValuationMap recentSales={recentSales} search={search} />
|
153
153
|
|
154
154
|
<div style={{ clear: 'both' }} />
|
155
155
|
|
156
|
-
|
157
|
-
<
|
158
|
-
|
156
|
+
{!!recentSales?.length && (
|
157
|
+
<div className="recently-sold">
|
158
|
+
<h3>Recently sold in the area</h3>
|
159
|
+
<p>These properties near you were sold recently.</p>
|
159
160
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
161
|
+
<ul id="recently-sold-list">
|
162
|
+
{recentSales?.map((property) => recentSale(property))}
|
163
|
+
</ul>
|
164
|
+
</div>
|
165
|
+
)}
|
164
166
|
|
165
167
|
<div className="clear" />
|
166
168
|
</div>
|
@@ -9,19 +9,21 @@ import {
|
|
9
9
|
|
10
10
|
import '../../properties/properties-map/leaflet.css';
|
11
11
|
|
12
|
-
const ValuationMap = ({ recentSales }) => {
|
12
|
+
const ValuationMap = ({ recentSales, search }) => {
|
13
|
+
if (!recentSales.length && !search.lat && !search.lng) return null;
|
14
|
+
|
13
15
|
const defaultIcon = L.icon({
|
14
16
|
iconRetinaUrl: '/assets/marker-icon.png',
|
15
17
|
iconUrl: '/assets/marker-icon.png',
|
16
18
|
shadowUrl: '/assets/marker-shadow.png',
|
17
19
|
});
|
18
20
|
|
19
|
-
const bounds = latLngBounds([
|
21
|
+
const bounds = recentSales?.length ? latLngBounds([
|
20
22
|
parseFloat(recentSales[0].latitude),
|
21
23
|
parseFloat(recentSales[0].longitude),
|
22
|
-
]);
|
24
|
+
]) : null;
|
23
25
|
|
24
|
-
const markers = recentSales?.map((property) => {
|
26
|
+
const markers = recentSales?.length ? recentSales?.map((property) => {
|
25
27
|
bounds.extend([property.latitude, property.longitude]);
|
26
28
|
|
27
29
|
return (
|
@@ -31,11 +33,17 @@ const ValuationMap = ({ recentSales }) => {
|
|
31
33
|
icon={defaultIcon}
|
32
34
|
/>
|
33
35
|
);
|
34
|
-
})
|
36
|
+
}) : (
|
37
|
+
<Marker
|
38
|
+
position={[search.lat, search.lng]}
|
39
|
+
icon={defaultIcon}
|
40
|
+
/>
|
41
|
+
);
|
35
42
|
|
36
43
|
return (
|
37
44
|
<MapContainer
|
38
|
-
bounds
|
45
|
+
{...(!!recentSales.length && bounds && { bounds })}
|
46
|
+
{...(!recentSales.length && { center: [search.lat, search.lng], zoom: 14 })}
|
39
47
|
scrollWheelZoom={false}
|
40
48
|
style={{ height: 300 }}
|
41
49
|
>
|
@@ -50,6 +58,14 @@ const ValuationMap = ({ recentSales }) => {
|
|
50
58
|
|
51
59
|
ValuationMap.propTypes = {
|
52
60
|
recentSales: PropTypes.array.isRequired,
|
61
|
+
search: PropTypes.shape({
|
62
|
+
lat: PropTypes.number,
|
63
|
+
lng: PropTypes.number,
|
64
|
+
}),
|
65
|
+
};
|
66
|
+
|
67
|
+
ValuationMap.defaultProps = {
|
68
|
+
search: null,
|
53
69
|
};
|
54
70
|
|
55
71
|
export default ValuationMap;
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/* eslint-disable */
|
2
2
|
import DraggableMap from './draggable-map';
|
3
3
|
import store from '../../store';
|
4
|
-
import { currentGeonameId, filterGeonames } from '../../utils/index';
|
4
|
+
import { currentGeonameId, filterGeonames, uniqueGeonamesByNameAndArea } from '../../utils/index';
|
5
5
|
import { setProperties, setGeonames, setSelectedMarker } from '../../actions/properties.actions';
|
6
6
|
import { setInitialSearch, setPlace, setSearchField } from '../../actions/search.actions';
|
7
7
|
import { buildQueryString } from '../../search/property-search/property-search';
|
@@ -283,11 +283,20 @@ export default class GeonamesMap extends DraggableMap {
|
|
283
283
|
if (json.geonames) {
|
284
284
|
this.geonames = this.concatenateDistinctObjects('geoname_id', this.geonames, json.geonames);
|
285
285
|
window.markerType = 'geonames';
|
286
|
-
|
287
|
-
const
|
288
|
-
|
289
|
-
|
290
|
-
|
286
|
+
|
287
|
+
const currentSearchPlace = store.getState().search.currentSearch?.place;
|
288
|
+
const geonamePosition = currentSearchPlace?.geoname_position || null;
|
289
|
+
const area = currentSearchPlace?.area || null;
|
290
|
+
|
291
|
+
let geonamesToDisplay = uniqueGeonamesByNameAndArea(this.geonames);
|
292
|
+
|
293
|
+
if (geonamePosition || area) {
|
294
|
+
geonamesToDisplay = filterGeonames(
|
295
|
+
this.currentGeonameIdFromLocationPath, Number(area), Number(geoname_position), geonamesToDisplay
|
296
|
+
);
|
297
|
+
|
298
|
+
}
|
299
|
+
store.dispatch(setGeonames(geonamesToDisplay));
|
291
300
|
} else if (json.properties) {
|
292
301
|
this.properties = this.concatenateDistinctObjects('property_id', this.properties, json.properties);
|
293
302
|
window.markerType = 'properties';
|
@@ -310,11 +319,20 @@ export default class GeonamesMap extends DraggableMap {
|
|
310
319
|
this.hideSuggestedDestinations();
|
311
320
|
this.markersInitialized = true;
|
312
321
|
} else if (window.markerType === 'geonames' && this.geonames?.length) {
|
313
|
-
const
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
322
|
+
const currentSearchPlace = store.getState()?.search?.currentSearch?.place;
|
323
|
+
|
324
|
+
const geonamePosition = currentSearchPlace?.geoname_position || null;
|
325
|
+
const area = currentSearchPlace?.area || null;
|
326
|
+
|
327
|
+
let geonamesToDisplay = uniqueGeonamesByNameAndArea(this.geonames);
|
328
|
+
|
329
|
+
if (geonamePosition || area) {
|
330
|
+
geonamesToDisplay = filterGeonames(
|
331
|
+
this.currentGeonameIdFromLocationPath, Number(area), Number(geonamePosition), geonamesToDisplay
|
332
|
+
);
|
333
|
+
}
|
334
|
+
|
335
|
+
geonamesToDisplay.forEach(geoname => this.setGeonameMarker(geoname));
|
318
336
|
this.showSuggestedDestinations();
|
319
337
|
this.markersInitialized = true;
|
320
338
|
}
|
package/utils/index.js
CHANGED
@@ -93,10 +93,42 @@ export const currentGeonameId = (path) => {
|
|
93
93
|
|
94
94
|
export const DEBOUNCE_DELAY = 200;
|
95
95
|
|
96
|
-
export const filterGeonames = (geonameId = null, areaId = null, geonames) => {
|
96
|
+
export const filterGeonames = (geonameId = null, areaId = null, geoPosition = null, geonames) => {
|
97
97
|
if (!geonameId) return geonames;
|
98
98
|
|
99
|
-
|
100
|
-
|
101
|
-
|
99
|
+
// Filter our same id
|
100
|
+
let filtered = geonames.filter((geoname) => geoname?.geoname_id !== geonameId);
|
101
|
+
|
102
|
+
// Filter out higher area
|
103
|
+
if (areaId && !geoPosition) filtered = filtered.filter((geoname) => geoname?.area < areaId);
|
104
|
+
|
105
|
+
// Filter out lower geoname_position
|
106
|
+
if (geoPosition) filtered = filtered.filter((geoname) => {
|
107
|
+
// Fallback to area if no geoname_position
|
108
|
+
if (
|
109
|
+
geoname?.geoname_position === 0
|
110
|
+
&& geoname?.area
|
111
|
+
&& geoname?.area !== 0
|
112
|
+
&& areaId
|
113
|
+
) return geoname?.area < areaId;
|
114
|
+
return geoname?.geoname_position > geoPosition;
|
115
|
+
});
|
116
|
+
|
117
|
+
return filtered;
|
102
118
|
};
|
119
|
+
|
120
|
+
export const uniqueGeonamesByNameAndArea = (geonames) => {
|
121
|
+
// One of the duplicated Geonames comes with geoname_position set as 0
|
122
|
+
// First set the one with geoname_position = 0 before the one with actual value, ordered by properties_count (as the response).
|
123
|
+
const sortByNameAndGeonamePosition = geonames.sort(
|
124
|
+
(first, second) => {
|
125
|
+
if (first.name === second.name) return first?.geoname_position - second?.geoname_position;
|
126
|
+
return first.properties_count > second.properties_count ? -1 : 1;
|
127
|
+
}
|
128
|
+
);
|
129
|
+
// Then remove duplicates by name
|
130
|
+
const uniqueNamesOnly = [...new Map(sortByNameAndGeonamePosition.map(item => [item['name'], item])).values()];
|
131
|
+
|
132
|
+
// Finally remove if they have the same area
|
133
|
+
return [...new Map(uniqueNamesOnly.map(item => [item['area'], item])).values()]
|
134
|
+
};
|