homeflowjs 0.7.13 → 0.7.17
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/__tests__/instant-valuation.test.jsx +1 -1
- package/actions/properties.actions.js +5 -0
- package/actions/properties.actions.test.js +13 -0
- package/actions/properties.types.js +1 -0
- package/actions/user.actions.js +3 -3
- package/actions/user.actions.test.js +1 -0
- package/app/notify.js +7 -6
- package/bin/test +6 -0
- package/cookie-consent/cookie-consent.js +1 -1
- package/package.json +4 -2
- package/properties/properties-grid/properties-grid.component.jsx +8 -12
- package/properties/sort-order-select/sort-order-select.component.jsx +2 -2
- package/properties/stamp-duty-calculator/default-calculator.component.jsx +39 -19
- package/reducers/properties.reducer.js +8 -2
- package/reducers/properties.reducer.test.js +16 -0
- package/search/location-input/location-input.test.js +1 -1
- package/search/radius-select/radius-select.test.js +1 -0
- package/search/search-form/search-form.component.jsx +1 -0
- package/store.js +3 -1
- package/user/index.js +2 -0
- package/utils/index.js +4 -0
- package/utils/index.test.js +21 -0
|
@@ -61,7 +61,7 @@ describe('Instant Valuation', () => {
|
|
|
61
61
|
}),
|
|
62
62
|
);
|
|
63
63
|
|
|
64
|
-
const message = await screen.
|
|
64
|
+
const message = await screen.getByText('Please fill out the required fields');
|
|
65
65
|
expect(message).toBeInTheDocument();
|
|
66
66
|
});
|
|
67
67
|
});
|
|
@@ -91,6 +91,11 @@ export const setPropertyLinksAsync = () => (dispatch) => {
|
|
|
91
91
|
});
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
+
export const setProperty = (payload) => ({
|
|
95
|
+
type: PropertiesActionTypes.SET_PROPERTY,
|
|
96
|
+
payload,
|
|
97
|
+
});
|
|
98
|
+
|
|
94
99
|
export const setProperties = (payload) => ({
|
|
95
100
|
type: PropertiesActionTypes.SET_PROPERTIES,
|
|
96
101
|
payload,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import store from '../store';
|
|
2
|
+
import * as actions from './properties.actions';
|
|
3
|
+
|
|
4
|
+
describe('Properties action creators', () => {
|
|
5
|
+
it('creates correct action for setProperty', () => {
|
|
6
|
+
const expectedAction = {
|
|
7
|
+
type: 'SET_PROPERTY',
|
|
8
|
+
payload: { property_ref: 'ABC123', postcode: 'AB1 1AA' },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
expect(actions.setProperty({ property_ref: 'ABC123', postcode: 'AB1 1AA' })).toEqual(expectedAction);
|
|
12
|
+
});
|
|
13
|
+
});
|
package/actions/user.actions.js
CHANGED
|
@@ -3,7 +3,7 @@ import { fetchSavedProperties, setSavedProperties } from './properties.actions';
|
|
|
3
3
|
import { fetchSavedSearches, setSavedSearches } from './search.actions';
|
|
4
4
|
import { setLoading } from './app.actions';
|
|
5
5
|
import { INITIAL_USER_DATA } from '../reducers/user.reducer';
|
|
6
|
-
import { objectDiff } from '../utils';
|
|
6
|
+
import { objectDiff, compact } from '../utils';
|
|
7
7
|
|
|
8
8
|
export const setCurrentUser = (payload) => ({
|
|
9
9
|
type: UserActionTypes.SET_CURRENT_USER,
|
|
@@ -33,10 +33,10 @@ export const fetchUser = () => (dispatch) => {
|
|
|
33
33
|
const serializedSavedProperties = localStorage.getItem('savedProperties');
|
|
34
34
|
|
|
35
35
|
if (serializedSavedSearches) {
|
|
36
|
-
dispatch(setSavedSearches(JSON.parse(serializedSavedSearches)));
|
|
36
|
+
dispatch(setSavedSearches(compact(JSON.parse(serializedSavedSearches))));
|
|
37
37
|
}
|
|
38
38
|
if (serializedSavedProperties) {
|
|
39
|
-
dispatch(setSavedProperties(JSON.parse(serializedSavedProperties)));
|
|
39
|
+
dispatch(setSavedProperties(compact(JSON.parse(serializedSavedProperties))));
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
|
package/app/notify.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import Toastify from 'toastify-js';
|
|
2
2
|
import 'toastify-js/src/toastify.css';
|
|
3
3
|
|
|
4
|
+
import { sanitizeText } from '../utils/index';
|
|
5
|
+
|
|
4
6
|
const notify = (message, type, config = {}) => {
|
|
5
|
-
|
|
7
|
+
if (!message) return;
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
color = '#dc3545';
|
|
9
|
-
}
|
|
9
|
+
const color = { error: '#dc3545' }[type] || '#28a745'; // default is success
|
|
10
10
|
|
|
11
11
|
Toastify({
|
|
12
12
|
duration: 3000,
|
|
@@ -14,8 +14,9 @@ const notify = (message, type, config = {}) => {
|
|
|
14
14
|
gravity: 'top',
|
|
15
15
|
position: 'center',
|
|
16
16
|
stopOnFocus: true,
|
|
17
|
-
text: message,
|
|
18
|
-
|
|
17
|
+
text: sanitizeText(message),
|
|
18
|
+
escapeMarkup: false,
|
|
19
|
+
style: { background: color },
|
|
19
20
|
...config,
|
|
20
21
|
}).showToast();
|
|
21
22
|
};
|
package/bin/test
ADDED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homeflowjs",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.17",
|
|
4
4
|
"description": "JavaScript toolkit for Homeflow themes",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "
|
|
7
|
+
"test": "bin/test"
|
|
8
8
|
},
|
|
9
9
|
"author": "",
|
|
10
10
|
"license": "ISC",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"react": "^16.14.0",
|
|
40
40
|
"react-dom": "^16.14.0",
|
|
41
41
|
"react-redux": "^7.2.1",
|
|
42
|
+
"react-router-dom": "^6.0.2",
|
|
42
43
|
"redux": "^4.0.5"
|
|
43
44
|
},
|
|
44
45
|
"devDependencies": {
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
"babel-jest": "^26.6.0",
|
|
50
51
|
"enzyme": "^3.11.0",
|
|
51
52
|
"enzyme-adapter-react-16": "^1.15.5",
|
|
53
|
+
"es-abstract": "^1.19.1",
|
|
52
54
|
"eslint": "^7.18.0",
|
|
53
55
|
"eslint-config-airbnb": "^18.2.1",
|
|
54
56
|
"eslint-config-airbnb-base": "^14.2.1",
|
|
@@ -24,21 +24,17 @@ const PropertiesGrid = ({ properties, GridItem, infiniteScroll }) => {
|
|
|
24
24
|
);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
const items = propertiesByPage(properties).map((page) =>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
>
|
|
33
|
-
{page.map((property) => (
|
|
34
|
-
<GridItem key={property.property_id} property={property} />
|
|
35
|
-
))}
|
|
36
|
-
</div>
|
|
37
|
-
));
|
|
27
|
+
const items = propertiesByPage(properties).map((page) =>
|
|
28
|
+
page.map((property) => (
|
|
29
|
+
<GridItem key={property.property_id} property={property} />
|
|
30
|
+
)
|
|
31
|
+
)).flat();
|
|
38
32
|
|
|
39
33
|
return (
|
|
40
34
|
<div className="hf-property-results hf-property-results__list">
|
|
41
|
-
|
|
35
|
+
<div className="clearfix results-page--grid">
|
|
36
|
+
{items}
|
|
37
|
+
</div>
|
|
42
38
|
</div>
|
|
43
39
|
);
|
|
44
40
|
};
|
|
@@ -20,7 +20,7 @@ const SortOrderSelect = (props) => {
|
|
|
20
20
|
|
|
21
21
|
if (reactSelect) {
|
|
22
22
|
const handleChange = ({ value }) => {
|
|
23
|
-
const newSearch = { ...search
|
|
23
|
+
const newSearch = { ...search };
|
|
24
24
|
newSearch.sorted = value;
|
|
25
25
|
|
|
26
26
|
propertySearch(newSearch);
|
|
@@ -49,7 +49,7 @@ const SortOrderSelect = (props) => {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
const handleChange = (e) => {
|
|
52
|
-
const newSearch = { ...search
|
|
52
|
+
const newSearch = { ...search };
|
|
53
53
|
newSearch.sorted = e.target.value;
|
|
54
54
|
|
|
55
55
|
propertySearch(newSearch);
|
|
@@ -10,6 +10,7 @@ const DefaultCalculator = ({ purchasePrice, setPurchasePrice }) => {
|
|
|
10
10
|
const [rate2, setRate2] = useState();
|
|
11
11
|
const [rate3, setRate3] = useState();
|
|
12
12
|
const [rate4, setRate4] = useState();
|
|
13
|
+
const [rate5, setRate5] = useState();
|
|
13
14
|
|
|
14
15
|
const calculateStampDuty = (price) => {
|
|
15
16
|
if (!price) {
|
|
@@ -17,6 +18,7 @@ const DefaultCalculator = ({ purchasePrice, setPurchasePrice }) => {
|
|
|
17
18
|
setRate2(0);
|
|
18
19
|
setRate3(0);
|
|
19
20
|
setRate4(0);
|
|
21
|
+
setRate5(0);
|
|
20
22
|
setTotalRate(0);
|
|
21
23
|
setEffectiveRate(Math.round(0));
|
|
22
24
|
|
|
@@ -29,29 +31,38 @@ const DefaultCalculator = ({ purchasePrice, setPurchasePrice }) => {
|
|
|
29
31
|
let rate2 = 0;
|
|
30
32
|
let rate3 = 0;
|
|
31
33
|
let rate4 = 0;
|
|
34
|
+
let rate5 = 0;
|
|
32
35
|
|
|
33
|
-
if (price -
|
|
34
|
-
rate2 = (price -
|
|
35
|
-
rate2 *= 0.
|
|
36
|
-
if (rate2 >
|
|
37
|
-
rate2 =
|
|
36
|
+
if (price - 125000 > 0) {
|
|
37
|
+
rate2 = (price - 125000);
|
|
38
|
+
rate2 *= 0.02;
|
|
39
|
+
if (rate2 > 125000 * 0.02) {
|
|
40
|
+
rate2 = 125000 * 0.02;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (price - 250000 > 0) {
|
|
45
|
+
rate3 = (price - 250000);
|
|
46
|
+
rate3 *= 0.05;
|
|
47
|
+
if (rate3 > 675000 * 0.05) {
|
|
48
|
+
rate3 = 675000 * 0.05;
|
|
38
49
|
}
|
|
39
50
|
}
|
|
40
51
|
|
|
41
52
|
if (price - 925000 > 0) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (
|
|
45
|
-
|
|
53
|
+
rate4 = (price - 925000);
|
|
54
|
+
rate4 *= 0.10;
|
|
55
|
+
if (rate4 > 575000 * 0.10) {
|
|
56
|
+
rate4 = 575000 * 0.10;
|
|
46
57
|
}
|
|
47
58
|
}
|
|
48
59
|
|
|
49
60
|
if (price - 1500000 > 0) {
|
|
50
|
-
|
|
51
|
-
|
|
61
|
+
rate5 = (price - 1500000);
|
|
62
|
+
rate5 *= 0.12;
|
|
52
63
|
}
|
|
53
64
|
|
|
54
|
-
totalRate = rate1 + rate2 + rate3 + rate4;
|
|
65
|
+
totalRate = rate1 + rate2 + rate3 + rate4 + rate5;
|
|
55
66
|
effectiveRate = totalRate / price;
|
|
56
67
|
effectiveRate *= 100;
|
|
57
68
|
|
|
@@ -59,6 +70,7 @@ const DefaultCalculator = ({ purchasePrice, setPurchasePrice }) => {
|
|
|
59
70
|
setRate2(rate2);
|
|
60
71
|
setRate3(rate3);
|
|
61
72
|
setRate4(rate4);
|
|
73
|
+
setRate5(rate5);
|
|
62
74
|
setTotalRate(totalRate);
|
|
63
75
|
setEffectiveRate(Math.round(effectiveRate * 10) / 10);
|
|
64
76
|
|
|
@@ -128,7 +140,7 @@ const DefaultCalculator = ({ purchasePrice, setPurchasePrice }) => {
|
|
|
128
140
|
</thead>
|
|
129
141
|
<tbody>
|
|
130
142
|
<tr>
|
|
131
|
-
<td>Between £0 and £
|
|
143
|
+
<td>Between £0 and £125,000</td>
|
|
132
144
|
<td> 0% </td>
|
|
133
145
|
<td className="rate1">
|
|
134
146
|
£
|
|
@@ -136,29 +148,37 @@ const DefaultCalculator = ({ purchasePrice, setPurchasePrice }) => {
|
|
|
136
148
|
</td>
|
|
137
149
|
</tr>
|
|
138
150
|
<tr>
|
|
139
|
-
<td>Between £
|
|
140
|
-
<td>
|
|
151
|
+
<td>Between £125,000 and £250,000</td>
|
|
152
|
+
<td> 2% </td>
|
|
141
153
|
<td className="rate2">
|
|
142
154
|
£
|
|
143
155
|
{Number(rate2).toLocaleString()}
|
|
144
156
|
</td>
|
|
145
157
|
</tr>
|
|
146
158
|
<tr>
|
|
147
|
-
<td>Between £
|
|
148
|
-
<td>
|
|
159
|
+
<td>Between £250,000 and £925,000</td>
|
|
160
|
+
<td> 5% </td>
|
|
149
161
|
<td className="rate3">
|
|
150
162
|
£
|
|
151
163
|
{Number(rate3).toLocaleString()}
|
|
152
164
|
</td>
|
|
153
165
|
</tr>
|
|
154
166
|
<tr>
|
|
155
|
-
<td>
|
|
156
|
-
<td>
|
|
167
|
+
<td>Between £925,000 and £1,500,000 </td>
|
|
168
|
+
<td> 10% </td>
|
|
157
169
|
<td className="rate4">
|
|
158
170
|
£
|
|
159
171
|
{Number(rate4).toLocaleString()}
|
|
160
172
|
</td>
|
|
161
173
|
</tr>
|
|
174
|
+
<tr>
|
|
175
|
+
<td>Over £1,500,000 </td>
|
|
176
|
+
<td> 12% </td>
|
|
177
|
+
<td className="rate5">
|
|
178
|
+
£
|
|
179
|
+
{Number(rate5).toLocaleString()}
|
|
180
|
+
</td>
|
|
181
|
+
</tr>
|
|
162
182
|
<tr className="totals">
|
|
163
183
|
<td>Total</td>
|
|
164
184
|
<td className="effectiveRate">
|
|
@@ -12,10 +12,15 @@ const INITIAL_STATE = {
|
|
|
12
12
|
|
|
13
13
|
const propertiesReducer = (state = INITIAL_STATE, action) => {
|
|
14
14
|
switch (action.type) {
|
|
15
|
+
case PropertiesActionTypes.SET_PROPERTY:
|
|
16
|
+
return {
|
|
17
|
+
...state,
|
|
18
|
+
property: action.payload,
|
|
19
|
+
};
|
|
15
20
|
case PropertiesActionTypes.SET_PROPERTIES:
|
|
16
21
|
return {
|
|
17
22
|
...state,
|
|
18
|
-
properties: action.payload
|
|
23
|
+
properties: action.payload,
|
|
19
24
|
};
|
|
20
25
|
case PropertiesActionTypes.SET_PAGINATION:
|
|
21
26
|
return {
|
|
@@ -52,7 +57,8 @@ const propertiesReducer = (state = INITIAL_STATE, action) => {
|
|
|
52
57
|
} else {
|
|
53
58
|
// need to find the property from the propertiesReducer and add it here
|
|
54
59
|
const property = state.properties.find(({ property_id }) => property_id === propertyId);
|
|
55
|
-
|
|
60
|
+
|
|
61
|
+
newSavedProperties.push(property || state.property);
|
|
56
62
|
|
|
57
63
|
if (!action.payload.userLoggedIn) {
|
|
58
64
|
localStorage.setItem('savedProperties', JSON.stringify(newSavedProperties));
|
|
@@ -35,4 +35,20 @@ describe('propertiesReducer', () => {
|
|
|
35
35
|
|
|
36
36
|
expect(reducedState.savedProperties.length).toEqual(0);
|
|
37
37
|
});
|
|
38
|
+
|
|
39
|
+
it('Sets the current property when it receives the SET_PROPERTY action', () => {
|
|
40
|
+
const property = { id: '123456789', property_ref: 'ABC12345', postcode: 'AB1 1AA' };
|
|
41
|
+
const state = { properties: [], savedProperties: [], pagination: {}, propertyLinks: { next: '', previous: '' } };
|
|
42
|
+
const reducedState = propertiesReducer(state, { type: 'SET_PROPERTY', payload: property });
|
|
43
|
+
|
|
44
|
+
expect(reducedState.property).toEqual(property);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('Retains initial state when it receives the SET_PROPERTY action', () => {
|
|
48
|
+
const property = { id: '123456789', property_ref: 'ABC12345', postcode: 'AB1 1AA' };
|
|
49
|
+
const state = { properties: [], savedProperties: [], pagination: {}, propertyLinks: { next: '', previous: '' } };
|
|
50
|
+
const reducedState = propertiesReducer(state, { type: 'SET_PROPERTY', payload: property });
|
|
51
|
+
|
|
52
|
+
expect(reducedState).toMatchObject(state);
|
|
53
|
+
});
|
|
38
54
|
});
|
package/store.js
CHANGED
|
@@ -5,7 +5,8 @@ import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly';
|
|
|
5
5
|
import rootReducer from './reducers';
|
|
6
6
|
import { setThemePreferences, setThemeSettings, setAuthenticityToken } from './actions/app.actions';
|
|
7
7
|
import { fetchUser } from './actions/user.actions';
|
|
8
|
-
import { setProperties, setPagination, setPropertyLinksAsync } from './actions/properties.actions';
|
|
8
|
+
import { setProperties, setPagination, setProperty, setPropertyLinksAsync } from './actions/properties.actions';
|
|
9
|
+
// import { fetchCompanyPreferences } from './actions/company-preferences.actions';
|
|
9
10
|
// import { fetchCompanyPreferences } from './actions/company-preferences.actions';
|
|
10
11
|
|
|
11
12
|
const middleware = [thunk];
|
|
@@ -29,6 +30,7 @@ window.addEventListener('DOMContentLoaded', () => {
|
|
|
29
30
|
// TODO: This should use data set inline for use setCompanyPreferences.
|
|
30
31
|
// store.dispatch(fetchCompanyPreferences());
|
|
31
32
|
|
|
33
|
+
store.dispatch(setProperty(Homeflow.get('property')));
|
|
32
34
|
store.dispatch(setProperties(Homeflow.get('properties')));
|
|
33
35
|
store.dispatch(setPagination(Homeflow.get('pagination')));
|
|
34
36
|
store.dispatch(setThemePreferences(Homeflow.get('theme_preferences')));
|
package/user/index.js
CHANGED
|
@@ -6,12 +6,14 @@ import SignInInput from './user-sign-in-form/sign-in-input.component';
|
|
|
6
6
|
import SignOutButton from './sign-out-button/sign-out-button.component';
|
|
7
7
|
import MarketingPreferencesForm from './marketing-preferences-form/marketing-preferences-form.component';
|
|
8
8
|
import ForgottenPasswordForm from './forgotten-password-form/forgotten-password-form.component';
|
|
9
|
+
import UserEditForm from './user-edit-form/user-edit-form.component';
|
|
9
10
|
|
|
10
11
|
export {
|
|
11
12
|
withUser,
|
|
12
13
|
UserRegisterForm,
|
|
13
14
|
UserInput,
|
|
14
15
|
UserSignInForm,
|
|
16
|
+
UserEditForm,
|
|
15
17
|
SignInInput,
|
|
16
18
|
SignOutButton,
|
|
17
19
|
MarketingPreferencesForm,
|
package/utils/index.js
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as utils from './index';
|
|
2
|
+
|
|
3
|
+
describe('compact', () => {
|
|
4
|
+
it('removes null elements from array', () => {
|
|
5
|
+
expect(utils.compact([1, null, 2, 3, null, 4, null, 5])).toEqual([1, 2, 3, 4, 5]);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it('removes undefined elements from array', () => {
|
|
9
|
+
expect(utils.compact([1, undefined, 2, 3, undefined, 4, undefined, 5])).toEqual([1, 2, 3, 4, 5]);
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
describe('sanitizeText', () => {
|
|
14
|
+
it('converts < and > to < and >', () => {
|
|
15
|
+
expect(utils.sanitizeText('<hello>')).toEqual('<hello>');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('converts & to &', () => {
|
|
19
|
+
expect(utils.sanitizeText('<hello>')).toEqual('<hello>');
|
|
20
|
+
});
|
|
21
|
+
});
|