homeflowjs 0.9.37 → 0.9.39
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/package.json
CHANGED
package/search/index.js
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { numberWithCommas } from '../../utils';
|
|
2
|
+
const defaultPriceLabel = (price, channel, lettingsAs) => {
|
|
3
|
+
if (channel === 'lettings' && lettingsAs === 'pw') {
|
|
4
|
+
const pwPrice = Math.ceil(price / (52 / 12));
|
|
5
|
+
return `£${numberWithCommas(pwPrice)} pw (£${numberWithCommas(price)} pcm)`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
return `£${numberWithCommas(price)} ${channel === 'lettings' ? 'pcm' : ''}`;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export default defaultPriceLabel;
|
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
2
|
import { connect } from 'react-redux';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
import Select from 'react-dropdown';
|
|
5
5
|
|
|
6
6
|
import 'react-dropdown/style.css';
|
|
7
7
|
|
|
8
|
-
import { capitalizeFirstLetter
|
|
8
|
+
import { capitalizeFirstLetter } from '../../utils';
|
|
9
9
|
import { defaultSalesPrices, defaultLettingsPrices } from './default-prices';
|
|
10
10
|
import { setSearchField } from '../../actions/search.actions';
|
|
11
|
-
|
|
12
|
-
const priceLabel = (price, channel, lettingsAs) => {
|
|
13
|
-
if (channel === 'lettings' && lettingsAs === 'pw') {
|
|
14
|
-
const pwPrice = Math.ceil(price / (52 / 12));
|
|
15
|
-
return `£${numberWithCommas(pwPrice)} pw (£${numberWithCommas(price)} pcm)`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
return `£${numberWithCommas(price)} ${channel === 'lettings' ? 'pcm' : ''}`
|
|
19
|
-
};
|
|
11
|
+
import defaultPriceLabel from './default-price-label';
|
|
20
12
|
|
|
21
13
|
const NormalSelect = ({
|
|
22
14
|
type,
|
|
@@ -28,28 +20,34 @@ const NormalSelect = ({
|
|
|
28
20
|
minPrice,
|
|
29
21
|
maxPrice,
|
|
30
22
|
...otherProps
|
|
31
|
-
}) =>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
<option
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
title={price}
|
|
47
|
-
>
|
|
48
|
-
{priceLabel(price, channel, priceConfig.lettingsAs)}
|
|
23
|
+
}) => {
|
|
24
|
+
const { priceLabel } = priceConfig;
|
|
25
|
+
return (
|
|
26
|
+
<select
|
|
27
|
+
name={`${type}Price`}
|
|
28
|
+
aria-label={`${type}-price`}
|
|
29
|
+
value={selectedPrice || ''}
|
|
30
|
+
onChange={e => setSearchField({
|
|
31
|
+
[e.target.name]: e.target.value ? parseInt(e.target.value) : null,
|
|
32
|
+
})}
|
|
33
|
+
{...otherProps}
|
|
34
|
+
>
|
|
35
|
+
<option value="" title={`${type} price`}>
|
|
36
|
+
{capitalizeFirstLetter(type)}
|
|
37
|
+
. Price
|
|
49
38
|
</option>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
{prices.map(price => (
|
|
40
|
+
<option
|
|
41
|
+
key={price}
|
|
42
|
+
value={price}
|
|
43
|
+
title={price}
|
|
44
|
+
>
|
|
45
|
+
{priceLabel(price, channel, priceConfig.lettingsAs)}
|
|
46
|
+
</option>
|
|
47
|
+
))}
|
|
48
|
+
</select>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
53
51
|
|
|
54
52
|
const ReactSelect = (props) => {
|
|
55
53
|
const {
|
|
@@ -63,6 +61,8 @@ const ReactSelect = (props) => {
|
|
|
63
61
|
priceConfig,
|
|
64
62
|
} = props;
|
|
65
63
|
|
|
64
|
+
const { priceLabel } = priceConfig;
|
|
65
|
+
|
|
66
66
|
const priceOptions = prices.map(price => (
|
|
67
67
|
{ value: price, label: priceLabel(price, channel, priceConfig.lettingsAs) }
|
|
68
68
|
));
|
|
@@ -103,6 +103,25 @@ const PriceSelect = (props) => {
|
|
|
103
103
|
lettingsPrices = defaultLettingsPrices,
|
|
104
104
|
} = priceConfig;
|
|
105
105
|
|
|
106
|
+
/**
|
|
107
|
+
* If not on first render and the channel updates clear the min and
|
|
108
|
+
* and max prices in the redux store. This is to stop bugs when the
|
|
109
|
+
* uses changes between the sales and letting channels, as the minPrice
|
|
110
|
+
* and maxPrice in redux may be set to the wrong channel values. For
|
|
111
|
+
* example the user selects min and max prices the sales channel
|
|
112
|
+
* but then user updates the channel to lettings, the inputs look to
|
|
113
|
+
* have changed but the sales prices will still saved in the store.
|
|
114
|
+
* So thats why we need to clear them is the channel updates.
|
|
115
|
+
*/
|
|
116
|
+
const [firstRender, setFirstRender] = useState(true);
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (!firstRender) {
|
|
119
|
+
setSearchField({ minPrice: null });
|
|
120
|
+
setSearchField({ maxPrice: null });
|
|
121
|
+
}
|
|
122
|
+
setFirstRender(false);
|
|
123
|
+
}, [channel]);
|
|
124
|
+
|
|
106
125
|
let prices = channel === 'sales' ? salesPrices : lettingsPrices;
|
|
107
126
|
|
|
108
127
|
const selectedPrice = type === 'min' ? minPrice : maxPrice;
|
|
@@ -122,7 +141,7 @@ const PriceSelect = (props) => {
|
|
|
122
141
|
selectedPrice={selectedPrice}
|
|
123
142
|
{...props}
|
|
124
143
|
/>
|
|
125
|
-
)
|
|
144
|
+
);
|
|
126
145
|
}
|
|
127
146
|
|
|
128
147
|
return (
|
|
@@ -131,15 +150,9 @@ const PriceSelect = (props) => {
|
|
|
131
150
|
selectedPrice={selectedPrice}
|
|
132
151
|
{...props}
|
|
133
152
|
/>
|
|
134
|
-
)
|
|
153
|
+
);
|
|
135
154
|
};
|
|
136
155
|
|
|
137
|
-
// const priceConfig = {
|
|
138
|
-
// salesPrices: Homeflow.get('sales_prices'),
|
|
139
|
-
// salesPrices: Homeflow.get('lettings_prices'),
|
|
140
|
-
// lettingsAs: 'pw',
|
|
141
|
-
// }
|
|
142
|
-
|
|
143
156
|
PriceSelect.propTypes = {
|
|
144
157
|
type: PropTypes.string.isRequired,
|
|
145
158
|
channel: PropTypes.oneOf(['sales', 'lettings']).isRequired,
|
|
@@ -150,6 +163,7 @@ PriceSelect.propTypes = {
|
|
|
150
163
|
salesPrices: PropTypes.array,
|
|
151
164
|
lettingsPrices: PropTypes.array,
|
|
152
165
|
lettingsAs: PropTypes.string,
|
|
166
|
+
priceLabel: PropTypes.func,
|
|
153
167
|
}),
|
|
154
168
|
lettingsAs: PropTypes.string,
|
|
155
169
|
reactSelect: PropTypes.bool,
|
|
@@ -160,6 +174,7 @@ PriceSelect.defaultProps = {
|
|
|
160
174
|
salesPrices: defaultSalesPrices,
|
|
161
175
|
lettingsPrices: defaultLettingsPrices,
|
|
162
176
|
lettingsAs: 'pcm',
|
|
177
|
+
priceLabel: defaultPriceLabel,
|
|
163
178
|
},
|
|
164
179
|
};
|
|
165
180
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { shallow, mount } from 'enzyme';
|
|
3
|
+
import defaultPriceLabel from './default-price-label';
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
TESTPriceSelect as PriceSelect,
|
|
@@ -39,6 +40,7 @@ describe('PriceSelect', () => {
|
|
|
39
40
|
minPrice: 150000,
|
|
40
41
|
priceConfig: {
|
|
41
42
|
salesPrices: [50000, 100000, 150000, 200000],
|
|
43
|
+
priceLabel: defaultPriceLabel,
|
|
42
44
|
}
|
|
43
45
|
};
|
|
44
46
|
const wrapper = mount(<PriceSelect {...testProps} />);
|
|
@@ -55,6 +57,7 @@ describe('PriceSelect', () => {
|
|
|
55
57
|
maxPrice: 150000,
|
|
56
58
|
priceConfig: {
|
|
57
59
|
salesPrices: [50000, 100000, 150000, 200000],
|
|
60
|
+
priceLabel: defaultPriceLabel,
|
|
58
61
|
},
|
|
59
62
|
};
|
|
60
63
|
const wrapper = mount(<PriceSelect {...testProps} />);
|
|
@@ -71,6 +74,7 @@ describe('PriceSelect', () => {
|
|
|
71
74
|
maxPrice: 150000,
|
|
72
75
|
priceConfig: {
|
|
73
76
|
salesPrices: [50000, 100000, 150000, 200000],
|
|
77
|
+
priceLabel: defaultPriceLabel,
|
|
74
78
|
},
|
|
75
79
|
};
|
|
76
80
|
const wrapper = mount(<PriceSelect {...testProps} />);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { connect } from 'react-redux';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
|
-
|
|
4
|
+
import Select from 'react-dropdown';
|
|
5
|
+
import 'react-dropdown/style.css';
|
|
5
6
|
import { removeSavedSearchAsync, updateSavedSearchAsync } from '../../actions/search.actions';
|
|
6
7
|
import propertySearch from '../property-search/property-search';
|
|
7
8
|
import notify from '../../app/notify';
|
|
@@ -20,15 +21,23 @@ const SavedSearch = (props) => {
|
|
|
20
21
|
frequencyLabel,
|
|
21
22
|
visitSearchLabel,
|
|
22
23
|
removeSearchLabel,
|
|
24
|
+
reactSelect,
|
|
23
25
|
} = props;
|
|
24
26
|
|
|
27
|
+
const options = [
|
|
28
|
+
{ value: 'I', label: 'Immediately' },
|
|
29
|
+
{ value: 'W', label: 'Weekly' },
|
|
30
|
+
{ value: 'M', label: 'Monthly' },
|
|
31
|
+
{ value: 'N', label: 'Never' },
|
|
32
|
+
];
|
|
33
|
+
|
|
25
34
|
const visitSearch = (e) => {
|
|
26
35
|
e.preventDefault();
|
|
27
36
|
propertySearch(search);
|
|
28
37
|
};
|
|
29
38
|
|
|
30
|
-
const handleFrequencyChange = (
|
|
31
|
-
const newSearch = { ...search, alert_frequency:
|
|
39
|
+
const handleFrequencyChange = (value) => {
|
|
40
|
+
const newSearch = { ...search, alert_frequency: value };
|
|
32
41
|
updateSavedSearchAsync(newSearch);
|
|
33
42
|
};
|
|
34
43
|
|
|
@@ -45,16 +54,23 @@ const SavedSearch = (props) => {
|
|
|
45
54
|
{userLoggedIn && (
|
|
46
55
|
<>
|
|
47
56
|
{frequencyLabel}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
{reactSelect ? (
|
|
58
|
+
<Select
|
|
59
|
+
className={selectClass}
|
|
60
|
+
options={options}
|
|
61
|
+
value={search.alert_frequency}
|
|
62
|
+
isSearchable={false}
|
|
63
|
+
onChange={({ value }) => handleFrequencyChange(value)}
|
|
64
|
+
/>
|
|
65
|
+
) : (
|
|
66
|
+
<select
|
|
67
|
+
className={`saved-search__frequency ${selectClass}`}
|
|
68
|
+
onChange={(e) => handleFrequencyChange(e.target.value)}
|
|
69
|
+
value={search.alert_frequency}
|
|
70
|
+
>
|
|
71
|
+
{options.map((option) => <option value={option.value}>{option.label}</option>)}
|
|
72
|
+
</select>
|
|
73
|
+
)}
|
|
58
74
|
</>
|
|
59
75
|
)}
|
|
60
76
|
|
|
@@ -90,6 +106,7 @@ SavedSearch.propTypes = {
|
|
|
90
106
|
frequencyLabel: PropTypes.string,
|
|
91
107
|
visitSearchLabel: PropTypes.string,
|
|
92
108
|
removeSearchLabel: PropTypes.string,
|
|
109
|
+
reactSelect: PropTypes.bool,
|
|
93
110
|
};
|
|
94
111
|
|
|
95
112
|
SavedSearch.defaultProps = {
|
|
@@ -100,6 +117,7 @@ SavedSearch.defaultProps = {
|
|
|
100
117
|
frequencyLabel: 'Email me matching properties:',
|
|
101
118
|
visitSearchLabel: 'Visit',
|
|
102
119
|
removeSearchLabel: 'Remove',
|
|
120
|
+
reactSelect: false,
|
|
103
121
|
};
|
|
104
122
|
|
|
105
123
|
const mapStateToProps = (state) => ({
|