Skip to content

Commit 96d118e

Browse files
Move the filter states from redux to query string.
1 parent a23476e commit 96d118e

File tree

27 files changed

+388
-440
lines changed

27 files changed

+388
-440
lines changed

client/src/actions/index.js

Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -252,74 +252,80 @@ export const sendPaymentToken = (token) => async dispatch => {
252252
}
253253

254254

255-
export const getDataViaAPI = (type, uri, query) => async dispatch => {
256-
if (uri) {
257-
if(query) {
258-
uri += query
255+
export const getDataViaAPI = (type, route, query, synchronous = true) => async dispatch => {
256+
if (route) {
257+
if (query) {
258+
route += query
259259
}
260260

261-
log.info(`[ACTION]: invokeAndDispatchAPIData Calling API = ${uri}.`)
262-
263-
// uri = uri.replace(/\s/g, '')
264-
let responseError = false
265-
const response = await commonServiceAPI.get(uri)
266-
.catch(err => {
267-
log.info(`[ACTION]: unable to fetch response for API = ${uri}`)
268-
dispatch({type: type, payload: {isLoading: false, statusCode: INTERNAL_SERVER_ERROR_CODE}});
269-
responseError = true
270-
});
271-
272-
if (responseError) {
273-
return
274-
}
275-
276-
if (response != null) {
277-
log.debug(`[ACTION]: Data = ${JSON.parse(JSON.stringify(response.data))}.`)
278-
let payload = {isLoading: false, data: JSON.parse(JSON.stringify(response.data))}
279-
if(query) {
280-
dispatch({
281-
type: type, payload:
282-
{...payload, query: query}
261+
log.info(`[ACTION]: invokeAndDispatchAPIData Calling API = ${route}.`)
262+
let isFetchError = false
263+
if (synchronous) {
264+
await commonServiceAPI.get(route)
265+
.then(response => processResponse(response, query, type, route))
266+
.catch(err => {
267+
isFetchError = true
283268
});
284-
} else {
285-
dispatch({
286-
type: type, payload: payload
269+
} else {
270+
commonServiceAPI.get(route)
271+
.then(response => processResponse(response, query, type, route, dispatch))
272+
.catch(err => {
273+
isFetchError = true
287274
});
288-
}
275+
}
289276

277+
if (isFetchError) {
278+
log.info(`[ACTION]: unable to fetch response for API = ${route}`)
279+
dispatch({type: type, payload: {isLoading: false, statusCode: INTERNAL_SERVER_ERROR_CODE}});
280+
}
281+
}
282+
}
290283

291-
if (LOAD_FILTER_PRODUCTS.localeCompare(type) === 0 &&
292-
window.location.search.localeCompare(uri.split("/products")[1]) !== 0) {
293-
history.push(uri)
294-
}
284+
export const processResponse = (response, query, type, uri, dispatch) => {
285+
log.debug(`[ACTION]: Data = ${JSON.parse(JSON.stringify(response.data))}.`)
286+
if (response.data !== null) {
287+
let payload = {isLoading: false, data: JSON.parse(JSON.stringify(response.data))}
288+
if (query) {
289+
dispatch({
290+
type: type, payload:
291+
{...payload, query: query}
292+
});
295293
} else {
296-
dispatch({type: type, payload: {isLoading: false, statusCode: BAD_REQUEST_ERROR_CODE}});
294+
dispatch({
295+
type: type, payload: payload
296+
});
297+
}
298+
299+
if (LOAD_FILTER_PRODUCTS.localeCompare(type) === 0 &&
300+
window.location.search.localeCompare(uri.split("/products")[1]) !== 0) {
301+
history.push(uri)
297302
}
303+
} else {
304+
dispatch({type: type, payload: {isLoading: false, statusCode: BAD_REQUEST_ERROR_CODE}});
298305
}
299306
}
300307

301-
export const loadFilterAttributes = filterQuery => async dispatch => {
308+
export const loadFilterAttributes = filterQuery => dispatch => {
302309
log.info(`[ACTION]: loadFilterAttributes Calling Filter API filterQuery = ${filterQuery}`)
303310

304311
if (filterQuery) {
305312
let uri = `/filter${filterQuery}`
306-
const response = await commonServiceAPI.get(uri);
307-
if (response != null) {
308-
log.trace(`[ACTION]: Filter = ${JSON.stringify(response.data)}`)
313+
commonServiceAPI.get(uri)
314+
.then(response => {
315+
dispatch({
316+
type: LOAD_FILTER_ATTRIBUTES,
317+
payload: JSON.parse(JSON.stringify(
318+
{
319+
...response.data,
320+
"query": filterQuery.slice(3)
321+
}))
322+
});
309323

310-
dispatch({
311-
type: LOAD_FILTER_ATTRIBUTES,
312-
payload: JSON.parse(JSON.stringify(
313-
{
314-
...response.data,
315-
"query": filterQuery.slice(3)
316-
}))
324+
return JSON.parse(JSON.stringify(response.data))
325+
})
326+
.catch(error => {
327+
log.info(`[ACTION]: unable to fetch response for Filter API`)
317328
});
318-
319-
return JSON.parse(JSON.stringify(response.data))
320-
} else {
321-
log.info(`[ACTION]: unable to fetch response for Filter API`)
322-
}
323329
}
324330
};
325331

client/src/actions/types.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const LOAD_FILTER_ATTRIBUTES = "LOAD_FILTER_ATTRIBUTES";
1717
export const LOAD_SHOPPING_BAG_PRODUCTS = "LOAD_SHOPPING_BAG_PRODUCTS";
1818
export const RESET_SHOPPING_BAG_PRODUCTS = "RESET_SHOPPING_BAG_PRODUCTS";
1919
export const LOAD_TABS_DATA = "LOAD_TABS_DATA";
20+
export const CLEAR_ALL_FILTERS = "CLEAR_ALL_FILTERS";
2021

2122
export const REMOVE_FILTER_ATTRIBUTES = "REMOVE_FILTER_ATTRIBUTES";
2223
export const SELECT_SORT_CATEGORY = "SELECT_SORT_CATEGORY";

client/src/components/routes/home/home.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const Home = props => {
2626
log.info("[Home]: component did mount.")
2727

2828
if(!homeAPIData.hasOwnProperty("data")) {
29-
props.getDataViaAPI(LOAD_HOME_PAGE, HOME_PAGE_DATA_API);
29+
props.getDataViaAPI(LOAD_HOME_PAGE, HOME_PAGE_DATA_API, null, false);
3030
}
3131

3232
// eslint-disable-next-line

client/src/components/routes/navbar/navBar.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ const NavBar = props => {
118118

119119
// tabs data is not loaded then load it.
120120
if (!tabsAPIData.hasOwnProperty("data")) {
121-
props.getDataViaAPI(LOAD_TABS_DATA, TABS_DATA_API)
121+
props.getDataViaAPI(LOAD_TABS_DATA, TABS_DATA_API, null, false)
122122
}
123123

124124
// set the cart values

client/src/components/routes/navbar/searchBar.js

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
import React, {useEffect, useState} from 'react';
1+
import React, {useState} from 'react';
22
import TextField from '@material-ui/core/TextField';
33
import Autocomplete from '@material-ui/lab/Autocomplete';
44
import CloseIcon from '@material-ui/icons/Close';
55
import ArrowBackIcon from '@material-ui/icons/ArrowBack';
66
import {Grid} from "@material-ui/core";
77
import log from 'loglevel';
88
import {connect, useSelector} from "react-redux";
9-
import {getSearchSuggestions, getDataViaAPI} from "../../../actions";
9+
import {getSearchSuggestions} from "../../../actions";
1010
import {makeStyles} from "@material-ui/core/styles";
11-
import {LOAD_FILTER_PRODUCTS} from "../../../actions/types";
12-
import {Loader} from "semantic-ui-react";
13-
import {StyledSearchBarDimmer} from "../../../styles/semanticUI/customStyles";
11+
import history from "../../../history";
1412
import {PRODUCT_BY_CATEGORY_DATA_API} from "../../../constants/api_routes";
1513

1614
export const useSearchBarStyles = makeStyles((theme) => ({
@@ -30,16 +28,9 @@ export const useSearchBarStyles = makeStyles((theme) => ({
3028
function SearchBar(props) {
3129
const [value, setValue] = useState(null);
3230
const searchSuggestions = useSelector(state => state.searchKeywordReducer)
33-
const filterProductsReducer = useSelector(state => state.filterProductsReducer)
3431
const classes = useSearchBarStyles()
35-
const [isLoading, setIsLoading] = useState(false)
3632
let selectedValue = null
3733

38-
useEffect(() => {
39-
log.info(`[SearchBar] Component did mount`)
40-
setIsLoading(false)
41-
}, [filterProductsReducer])
42-
4334
const getSearchKeyword = () => {
4435
return document.querySelector('input[id="free-solo"]').value
4536
}
@@ -59,21 +50,22 @@ function SearchBar(props) {
5950
}
6051
}
6152

62-
log.info(`queryLink = ${queryLink}, value = ${value}`)
53+
log.info(`=======> queryLink = ${queryLink}, value = ${value}, history = ${JSON.stringify(history)}`)
6354
if (queryLink) {
64-
setIsLoading(true)
65-
props.getDataViaAPI(LOAD_FILTER_PRODUCTS,
66-
`${PRODUCT_BY_CATEGORY_DATA_API}?q=${queryLink}`)
55+
history.push(`${PRODUCT_BY_CATEGORY_DATA_API}?q=${queryLink}`)
6756
}
6857
}
6958
}
7059

71-
const handleClose = () => {
72-
let finalSelectedValue = selectedValue
73-
if (!selectedValue) {
74-
finalSelectedValue = getSearchKeyword()
60+
const handleClose = (event, reason) => {
61+
if(reason === "select-option") {
62+
let finalSelectedValue = selectedValue
63+
if (!selectedValue) {
64+
finalSelectedValue = getSearchKeyword()
65+
}
66+
log.info("Coming here------1 = " + reason)
67+
searchKeyword(finalSelectedValue)
7568
}
76-
searchKeyword(finalSelectedValue)
7769
}
7870

7971
const renderDesktopTextField = (params) => {
@@ -125,6 +117,7 @@ function SearchBar(props) {
125117
onInputChange={handleInputChange}
126118
selectOnFocus
127119
clearOnBlur
120+
blurOnSelect={true}
128121
handleHomeEndKeys
129122
closeIcon={<CloseIcon/>}
130123
id="free-solo"
@@ -150,13 +143,8 @@ function SearchBar(props) {
150143
renderInput={(params) =>
151144
props.device ? renderMobileTextField(params) : renderDesktopTextField(params)}
152145
/>
153-
{isLoading ?
154-
<StyledSearchBarDimmer active inverted>
155-
<Loader inverted>Loading</Loader>
156-
</StyledSearchBarDimmer> : null}
157-
158146
</Grid>
159147
);
160148
}
161149

162-
export default connect(null, {getSearchSuggestions, getDataViaAPI})(SearchBar);
150+
export default connect(null, {getSearchSuggestions})(SearchBar);

client/src/components/routes/product/filterChips.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import Chip from "@material-ui/core/Chip";
44
import Box from '@material-ui/core/Box';
55
import log from "loglevel";
66
import {ADD_SELECTED_CATEGORY} from "../../../actions/types";
7+
import history from "../../../history";
8+
import {PRODUCT_BY_CATEGORY_DATA_API} from "../../../constants/api_routes";
9+
import {toggleId} from "../../../helper/toggleId";
10+
import {updateQueryString} from "../../../helper/updateQueryString";
711

812
const FilterChips = () => {
913
const selectedGenders = useSelector(state => state.selectedFilterAttributesReducer.genders)
@@ -98,6 +102,9 @@ const FilterChips = () => {
98102
newQuery: null
99103
}
100104
})
105+
106+
const {list, ids} = toggleId(selectedAttrList[i].id, selectedAttrList[i].value, selectedAttrList)
107+
history.push(updateQueryString(history, attributeName, selectedAttrList[i].id, ids))
101108
return
102109
}
103110
}

client/src/components/routes/product/filterDropdown.js

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,45 @@
1-
import React from 'react';
1+
import React, {useEffect, useState} from 'react';
22
import log from 'loglevel';
33
import {useDispatch, useSelector} from "react-redux";
44
import {SELECT_SORT_CATEGORY} from "../../../actions/types";
55
import DropdownSection from "../../ui/dropDown";
6-
import {SORT_ATTRIBUTE} from "../../../constants/constants";
6+
import {MAX_PRODUCTS_PER_PAGE, SORT_ATTRIBUTE} from "../../../constants/constants";
7+
import history from "../../../history";
78

89
export default function FilterDropdown() {
9-
const dispatch = useDispatch()
10-
const sortList = useSelector(state => state.filterAttributesReducer?
11-
state.filterAttributesReducer[SORT_ATTRIBUTE] : null)
12-
const selectedSortValue = useSelector(state => state.selectSortReducer)
10+
const sortList = useSelector(state => state.filterAttributesReducer.data ?
11+
state.filterAttributesReducer.data[SORT_ATTRIBUTE] : null)
12+
const selectedSort = useSelector(state => state.selectSortReducer)
13+
const [sortValue, setSortValue] = useState({id:1, value: ""})
14+
15+
useEffect(() => {
16+
if (selectedSort != null) {
17+
setSortValue(selectedSort)
18+
}
19+
}, [selectedSort])
1320

1421
if (!sortList) {
1522
return null
1623
}
1724

1825
const onChangeHandler = (id, value) => {
1926
log.info(`[FilterDropdown] onChangeHandler id = ${id}, value = ${value}`)
20-
dispatch({
21-
type: SELECT_SORT_CATEGORY,
22-
payload: {
23-
id, value,
24-
isLoadedFromURL: false
25-
}
26-
})
27+
setSortValue({id, value})
28+
let route = history.location.pathname
29+
let queryStr = history.location.search
30+
if (history.location.search.search("sortby") === -1) {
31+
history.push(`${route}${queryStr}::sortby=${id}`)
32+
} else {
33+
history.push(`${route}${queryStr.replace(new RegExp(`sortby=[0-9]`), `sortby=${id}`)}`)
34+
}
2735
}
2836

29-
log.info(`[FilterDropdown] Rendering FilterDropdown Component selectedSortValue = ${JSON.stringify(selectedSortValue)}`)
37+
log.info(`[FilterDropdown] Rendering FilterDropdown Component`)
3038

3139
return (
3240
<DropdownSection
3341
attrList={sortList}
34-
selectedValue={selectedSortValue}
42+
selectedValue={sortValue}
3543
appendText="Sort by:"
3644
title="sortby"
3745
size="lg"

client/src/components/routes/product/filterPagination.js

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,42 @@
1-
import React from 'react';
1+
import React, {useEffect, useState} from 'react';
22
import Grid from "@material-ui/core/Grid";
33
import log from 'loglevel';
44
import {useDispatch, useSelector} from "react-redux";
55
import {SELECT_PRODUCT_PAGE} from "../../../actions/types";
66
import Pagination from "@material-ui/lab/Pagination";
77
import {MAX_PRODUCTS_PER_PAGE} from "../../../constants/constants";
8+
import {toggleId} from "../../../helper/toggleId";
9+
import history from "../../../history";
10+
import {updateQueryString} from "../../../helper/updateQueryString";
811

912
export default function FilterPagination() {
10-
const dispatch = useDispatch()
1113
const selectedPage = useSelector(state => state.selectPageReducer)
1214
const filterProductsReducer = useSelector(state => state.filterProductsReducer)
15+
const [page, setPage] = useState(1)
1316
let totalProducts = 0
1417

18+
useEffect(() => {
19+
if(selectedPage != null) {
20+
setPage(selectedPage.pageNumber)
21+
}
22+
}, [selectedPage])
23+
1524
const handleChangePage = (event, page) => {
1625
log.info(`[FilterPagination] dispatching SELECT_PRODUCT_PAGE for page = ${page}`)
17-
dispatch({
18-
type: SELECT_PRODUCT_PAGE,
19-
payload: {
20-
pageNumber: page,
21-
maxProducts: MAX_PRODUCTS_PER_PAGE,
22-
isLoadedFromURL: false
23-
}
24-
})
26+
27+
setPage(page)
28+
let route = history.location.pathname
29+
let queryStr = history.location.search
30+
if (history.location.search.search("page") === -1) {
31+
history.push(`${route}${queryStr}::page=${page-1},${MAX_PRODUCTS_PER_PAGE}`)
32+
} else {
33+
history.push(`${route}${queryStr.replace(new RegExp(`page=[0-9]+,${MAX_PRODUCTS_PER_PAGE}`),
34+
`page=${page-1},${MAX_PRODUCTS_PER_PAGE}`)}`)
35+
}
2536
}
2637

2738
// if we got data from the server side
28-
if(!filterProductsReducer || filterProductsReducer.hasOwnProperty("data") === false ||
39+
if (!filterProductsReducer || filterProductsReducer.hasOwnProperty("data") === false ||
2940
filterProductsReducer.data.hasOwnProperty("totalCount") === false) {
3041
log.info(`[FilterPagination] totalProducts = ${totalProducts}`)
3142
return null
@@ -42,8 +53,8 @@ export default function FilterPagination() {
4253
justify="center"
4354
style={{padding: "30px 0 100px 0"}}>
4455
<Pagination onChange={handleChangePage}
45-
page={selectedPage.pageNumber}
46-
count={totalProducts <= MAX_PRODUCTS_PER_PAGE? 1: Math.floor(totalProducts/MAX_PRODUCTS_PER_PAGE)}
56+
page={page}
57+
count={totalProducts <= MAX_PRODUCTS_PER_PAGE ? 1 : Math.floor(totalProducts / MAX_PRODUCTS_PER_PAGE)}
4758
color="secondary"/>
4859
</Grid>
4960
);

0 commit comments

Comments
 (0)