Skip to content

Commit a92b677

Browse files
filter feature added using redux and json server api
1 parent 37a15cb commit a92b677

File tree

4 files changed

+64
-34
lines changed

4 files changed

+64
-34
lines changed

src/features/product/components/ProductList.js

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import React, { useState, Fragment, useEffect } from "react";
22
import { useSelector, useDispatch } from "react-redux";
3-
import { fetchAllProductsAsync, selectAllProducts } from "../productSlice";
3+
import {
4+
fetchAllProductsAsync,
5+
fetchProductsByFiltersAsync,
6+
selectAllProducts,
7+
} from "../productSlice";
48
import { Dialog, Disclosure, Menu, Transition } from "@headlessui/react";
59
import { StarIcon, XMarkIcon } from "@heroicons/react/24/outline";
610
import { ChevronLeftIcon, ChevronRightIcon } from "@heroicons/react/20/solid";
@@ -22,52 +26,36 @@ const sortOptions = [
2226
];
2327

2428
const filters = [
29+
{
30+
id: "category",
31+
name: "Category",
32+
options: [
33+
{ value: "beauty", label: "Beauty", checked: false },
34+
{ value: "fragrances", label: "Fragrances", checked: false },
35+
{ value: "furniture", label: "Furniture", checked: false },
36+
{ value: "groceries", label: "Groceries", checked: false },
37+
],
38+
},
2539
{
2640
id: "brand",
2741
name: "Brands",
2842
options: [
2943
{ value: "Essence", label: "Essence", checked: false },
30-
3144
{ value: "Glamour Beauty", label: "Glamour Beauty", checked: false },
32-
3345
{ value: "Velvet Touch", label: "Velvet Touch", checked: false },
34-
3546
{ value: "Chic Cosmetics", label: "Chic Cosmetics", checked: false },
36-
3747
{ value: "Nail Couture", label: "Nail Couture", checked: false },
38-
3948
{ value: "Calvin Klein", label: "Calvin Klein", checked: false },
40-
4149
{ value: "Chanel", label: "Chanel", checked: false },
42-
4350
{ value: "Dior", label: "Dior", checked: false },
44-
4551
{ value: "Dolce & Gabbana", label: "Dolce & Gabbana", checked: false },
46-
4752
{ value: "Gucci", label: "Gucci", checked: false },
48-
4953
{ value: "Annibale Colombo", label: "Annibale Colombo", checked: false },
50-
5154
{ value: "Furniture Co.", label: "Furniture Co.", checked: false },
52-
5355
{ value: "Knoll", label: "Knoll", checked: false },
54-
5556
{ value: "Bath Trends", label: "Bath Trends", checked: false },
5657
],
5758
},
58-
{
59-
id: "category",
60-
name: "Category",
61-
options: [
62-
{ value: "beauty", label: "Beauty", checked: false },
63-
64-
{ value: "fragrances", label: "Fragrances", checked: false },
65-
66-
{ value: "furniture", label: "Furniture", checked: false },
67-
68-
{ value: "groceries", label: "Groceries", checked: false },
69-
],
70-
},
7159
];
7260

7361
function classNames(...classes) {
@@ -78,10 +66,18 @@ export default function ProductList() {
7866
const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false);
7967
const products = useSelector(selectAllProducts);
8068
const dispatch = useDispatch();
69+
const [filter, setFilter] = useState({});
70+
const handleFilter = (e, section, option) => {
71+
const newFilter = { ...filter, [section.id]: option.value };
72+
setFilter(newFilter);
73+
dispatch(fetchProductsByFiltersAsync(newFilter));
74+
console.log(section.id, option.value);
75+
};
8176

8277
useEffect(() => {
8378
dispatch(fetchAllProductsAsync());
8479
}, [dispatch]);
80+
8581
return (
8682
<div className="bg-white">
8783
<div>
@@ -314,6 +310,9 @@ export default function ProductList() {
314310
defaultValue={option.value}
315311
type="checkbox"
316312
defaultChecked={option.checked}
313+
onChange={(e) => {
314+
handleFilter(e, section, option);
315+
}}
317316
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
318317
/>
319318
<label

src/features/product/productAPI.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,19 @@ export function fetchAllProducts() {
66
resolve({ data });
77
});
88
}
9+
export function fetchProductsByFilters(filter) {
10+
// filter ={"category":"frangrances"}
11+
// filter ={"brand":"Essence"}
12+
let queryString = "";
13+
for (let key in filter) {
14+
queryString += `${key}=${filter[key]}&`;
15+
}
16+
return new Promise(async (resolve) => {
17+
// TODO: we will not hard coded server url here...
18+
const response = await fetch(
19+
"http://localhost:8080/products?" + queryString
20+
);
21+
const data = await response.json();
22+
resolve({ data });
23+
});
24+
}

src/features/product/productSlice.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
2-
import { fetchAllProducts } from "./productAPI";
2+
import { fetchAllProducts, fetchProductsByFilters } from "./productAPI";
33

44
const initialState = {
55
products: [],
@@ -14,6 +14,14 @@ export const fetchAllProductsAsync = createAsyncThunk(
1414
return response.data;
1515
}
1616
);
17+
export const fetchProductsByFiltersAsync = createAsyncThunk(
18+
"product/fetchProductsByFilters",
19+
async (filter) => {
20+
const response = await fetchProductsByFilters(filter);
21+
// The value we return becomes the `fulfilled` action payload
22+
return response.data;
23+
}
24+
);
1725

1826
export const productSlice = createSlice({
1927
name: "product",
@@ -31,6 +39,13 @@ export const productSlice = createSlice({
3139
.addCase(fetchAllProductsAsync.fulfilled, (state, action) => {
3240
state.status = "idle";
3341
state.products = action.payload;
42+
})
43+
.addCase(fetchProductsByFiltersAsync.pending, (state) => {
44+
state.status = "loading";
45+
})
46+
.addCase(fetchProductsByFiltersAsync.fulfilled, (state, action) => {
47+
state.status = "idle";
48+
state.products = action.payload;
3449
});
3550
},
3651
});

test.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,13 +1772,13 @@ const products = [
17721772
},
17731773
];
17741774

1775-
// const categories = [...new Set([...products.map((p) => p.category)])];
1775+
const categories = [...new Set([...products.map((p) => p.category)])];
17761776

1777-
// categories.map((c) => ({
1778-
// value: c,
1779-
// label: c.split("-").join(" "),
1780-
// checked: false,
1781-
// }));
1777+
categories.map((c) => ({
1778+
value: c,
1779+
label: c.split("-").join(" "),
1780+
checked: false,
1781+
}));
17821782

17831783
//categories results:-
17841784
// {value: 'beauty', label: 'beauty', checked: false},

0 commit comments

Comments
 (0)