Browse Source

select product by tags

master
azri 4 weeks ago
parent
commit
cb1f00b4e9

+ 59
- 8
src/components/ProductList/ProductList.jsx View File

4
 import { styled } from "@mui/material";
4
 import { styled } from "@mui/material";
5
 //REDUX
5
 //REDUX
6
 import { useSelector, useDispatch } from 'react-redux';
6
 import { useSelector, useDispatch } from 'react-redux';
7
-import { fetchProducts, fetchProductsByCollection } from '../../redux/slices/productSlice';
7
+import { fetchProductsByTags, fetchProductsByCollection } from '../../redux/slices/productSlice';
8
 
8
 
9
 //UTIL FUNCTION
9
 //UTIL FUNCTION
10
 function getAllTags(data) {
10
 function getAllTags(data) {
14
   return uniqueTags;
14
   return uniqueTags;
15
 }
15
 }
16
 
16
 
17
+function getAllCollection(data) {
18
+  const products = data || [];
19
+  const allCollection = products.flatMap(product => product.collections.nodes);
20
+  const uniqueCollection = Array.from(
21
+    new Map(allCollection.map(item => [item.title, item])).values()
22
+  );
23
+  return uniqueCollection;
24
+}
25
+
17
 const BootstrapInput = styled(InputBase)(({ theme }) => ({
26
 const BootstrapInput = styled(InputBase)(({ theme }) => ({
18
   'label + &': {
27
   'label + &': {
19
     marginTop: theme.spacing(3),
28
     marginTop: theme.spacing(3),
44
   const products = useSelector((state) => state.products.products.data) // only used as referenced
53
   const products = useSelector((state) => state.products.products.data) // only used as referenced
45
   const [filteredProducts, setFilteredProducts] = useState([]) // this one is the actual data to be rendered
54
   const [filteredProducts, setFilteredProducts] = useState([]) // this one is the actual data to be rendered
46
   const [categoryFilterOption, setCategoryFilterOption] = useState([])
55
   const [categoryFilterOption, setCategoryFilterOption] = useState([])
56
+  const [collectionFilterOption, setCollectionFilterOption] = useState([])
47
   const dispatch = useDispatch();
57
   const dispatch = useDispatch();
48
 
58
 
49
   //filter
59
   //filter
50
   const [category, setCategory] = useState('all');
60
   const [category, setCategory] = useState('all');
61
+  const [collection, setCollection] = useState('all');
51
   const [sort, setSort] = useState('title')
62
   const [sort, setSort] = useState('title')
52
 
63
 
53
   useEffect(() => {
64
   useEffect(() => {
60
 
71
 
61
     } else if (sessionStorage.getItem('amber-select-category')) {
72
     } else if (sessionStorage.getItem('amber-select-category')) {
62
 
73
 
63
-      
74
+      let tag = sessionStorage.getItem('amber-select-category')
75
+      if(tag == 'all') tag = ""
76
+      dispatch(fetchProductsByTags({ tag }))
64
 
77
 
65
     }
78
     }
66
 
79
 
68
 
81
 
69
   useEffect(() => {
82
   useEffect(() => {
70
 
83
 
84
+    console.log(products)
71
     let productType = sessionStorage.getItem('amber-select-product-type')
85
     let productType = sessionStorage.getItem('amber-select-product-type')
72
     let newFilteredProducts = products.filter(
86
     let newFilteredProducts = products.filter(
73
       (product) => product.productType === productType
87
       (product) => product.productType === productType
74
     );
88
     );
75
 
89
 
76
-    const categoryList = getAllTags(newFilteredProducts) // yes we use tags as category, while I was coding this, this is the only way to implement category
77
-
78
     setFilteredProducts(newFilteredProducts)
90
     setFilteredProducts(newFilteredProducts)
79
-    setCategoryFilterOption(categoryList)
91
+
92
+    if (sessionStorage.getItem('amber-select-collection')){
93
+      const categoryList = getAllTags(newFilteredProducts) // yes we use tags as category, while I was coding this, this is the only way to implement category
94
+      setCategoryFilterOption(categoryList)
95
+    } else if (sessionStorage.getItem('amber-select-category')) {
96
+      const collectionList = getAllCollection(newFilteredProducts)
97
+      setCollectionFilterOption(collectionList)
98
+    }
99
+    
80
 
100
 
81
   }, [products])
101
   }, [products])
82
 
102
 
87
 
107
 
88
       let productType = sessionStorage.getItem('amber-select-product-type')
108
       let productType = sessionStorage.getItem('amber-select-product-type')
89
 
109
 
110
+      // Category
90
       let newFilteredProducts = products.filter(
111
       let newFilteredProducts = products.filter(
91
         (product) => {
112
         (product) => {
92
 
113
 
99
         }
120
         }
100
       );
121
       );
101
 
122
 
123
+      // Collection
124
+      newFilteredProducts = newFilteredProducts.filter(
125
+        (product) => {
126
+
127
+          if(collection == 'all'){
128
+            return product.productType === productType
129
+          } else {
130
+            debugger
131
+            return product.productType === productType && product.collections.nodes.some(data => data.title === collection)
132
+          }
133
+
134
+        }
135
+      );
136
+
102
       if (sort === "title") {
137
       if (sort === "title") {
103
         newFilteredProducts = newFilteredProducts.sort((a, b) => a.title.localeCompare(b.title));
138
         newFilteredProducts = newFilteredProducts.sort((a, b) => a.title.localeCompare(b.title));
104
       } else if (sort === "new") {
139
       } else if (sort === "new") {
111
 
146
 
112
     }
147
     }
113
 
148
 
114
-  }, [category, sort])
149
+  }, [category, collection, sort])
115
 
150
 
116
   useEffect(() => {
151
   useEffect(() => {
117
     if (products) console.log(products)
152
     if (products) console.log(products)
206
             lg:"row"
241
             lg:"row"
207
           }, }}>
242
           }, }}>
208
 
243
 
209
-          <FormControl sx={{ m: 1, display: "flex", flexDirection: "row" }} variant="standard">
244
+          {/* length 1, cause we know upon selecting by tags, there would be only 1 category, which mean no need to view this option */}
245
+          {(categoryFilterOption.length > 0) && <FormControl sx={{ m: 1, display: "flex", flexDirection: "row" }} variant="standard">
210
             <Typography variant="body2" sx={{ mr: 1, my: "auto" }}>Category</Typography>
246
             <Typography variant="body2" sx={{ mr: 1, my: "auto" }}>Category</Typography>
211
             <Select
247
             <Select
212
               value={category}
248
               value={category}
219
               <MenuItem value={'all'}>All</MenuItem>
255
               <MenuItem value={'all'}>All</MenuItem>
220
               {categoryFilterOption?.map((data) => (<MenuItem value={data}>{data}</MenuItem>))}
256
               {categoryFilterOption?.map((data) => (<MenuItem value={data}>{data}</MenuItem>))}
221
             </Select>
257
             </Select>
222
-          </FormControl>
258
+          </FormControl>}
259
+
260
+          {(collectionFilterOption.length > 0) && <FormControl sx={{ m: 1, display: "flex", flexDirection: "row" }} variant="standard">
261
+            <Typography variant="body2" sx={{ mr: 1, my: "auto" }}>Collection</Typography>
262
+            <Select
263
+              value={collection}
264
+              onChange={(event) => {
265
+                setCollection(event.target.value);
266
+              }}
267
+              input={<BootstrapInput />}
268
+              name="type"
269
+            >
270
+              <MenuItem value={'all'}>All</MenuItem>
271
+              {collectionFilterOption?.map(({title}) => (<MenuItem value={title}>{title}</MenuItem>))}
272
+            </Select>
273
+          </FormControl>}
223
 
274
 
224
           <FormControl sx={{ m: 1, display: "flex", flexDirection: "row" }} variant="standard">
275
           <FormControl sx={{ m: 1, display: "flex", flexDirection: "row" }} variant="standard">
225
             <Typography variant="body2" sx={{ mr: 1, my: "auto" }}>Sort</Typography>
276
             <Typography variant="body2" sx={{ mr: 1, my: "auto" }}>Sort</Typography>

+ 23
- 0
src/redux/slices/productSlice.js View File

51
   }
51
   }
52
 )
52
 )
53
 
53
 
54
+export const fetchProductsByTags = createAsyncThunk(
55
+  'product/fetchProductsByTags',
56
+  async ({tag}) => {
57
+    const response = await ProductService.getProductsByTags(tag)
58
+    console.log(response)
59
+    return response
60
+
61
+  }
62
+)
63
+
54
 export const fetchProductsHistory = createAsyncThunk(
64
 export const fetchProductsHistory = createAsyncThunk(
55
   'product/fetchProductsHistory',
65
   'product/fetchProductsHistory',
56
   async (productIDList) => {
66
   async (productIDList) => {
106
         state.products.data = [];
116
         state.products.data = [];
107
         state.products.error = action.error.message;
117
         state.products.error = action.error.message;
108
       })
118
       })
119
+      .addCase(fetchProductsByTags.pending, (state) => {
120
+        state.products.status = 'loading';
121
+        state.products.error = null;
122
+      })
123
+      .addCase(fetchProductsByTags.fulfilled, (state, action) => {
124
+        state.products.status = 'succeeded';
125
+        state.products.data = action.payload
126
+      })
127
+      .addCase(fetchProductsByTags.rejected, (state, action) => {
128
+        state.products.status = 'failed';
129
+        state.products.data = [];
130
+        state.products.error = action.error.message;
131
+      })
109
       .addCase(fetchProductsHistory.pending, (state) => {
132
       .addCase(fetchProductsHistory.pending, (state) => {
110
         state.productsHistory.status = 'loading';
133
         state.productsHistory.status = 'loading';
111
         state.productsHistory.error = null;
134
         state.productsHistory.error = null;

+ 46
- 0
src/services/ProductService.js View File

170
   return data.collection.products.nodes
170
   return data.collection.products.nodes
171
 }
171
 }
172
 
172
 
173
+const getProductsByTags = async (tag) => {
174
+
175
+  let customQuery = `query: "tag:${tag}"`
176
+  if(tag == 'all') customQuery = ''
177
+
178
+  const query = `{
179
+    products(first: 250, ${customQuery}) {
180
+      nodes {
181
+        id
182
+        title
183
+        createdAt
184
+        productType
185
+        tags
186
+        compareAtPriceRange {
187
+          maxVariantPrice {
188
+            amount
189
+            currencyCode
190
+          }
191
+          minVariantPrice {
192
+            amount
193
+            currencyCode
194
+          }
195
+        }
196
+        images(first: 4) {
197
+          nodes {
198
+            src
199
+            url
200
+          }
201
+        }
202
+        collections(first: 5) {
203
+          nodes {
204
+            title
205
+          }
206
+        }
207
+      }
208
+    }
209
+  }`
210
+
211
+  const { data, errors, extensions } = await client.request(query, {
212
+    variables: {},
213
+  });
214
+
215
+  return data.products.nodes
216
+}
217
+
173
 const getProductTypes = async () => {
218
 const getProductTypes = async () => {
174
   const query = `{
219
   const query = `{
175
     productTypes(first: 250) {
220
     productTypes(first: 250) {
274
   getProducts,
319
   getProducts,
275
   getProduct,
320
   getProduct,
276
   getProductsByCollection,
321
   getProductsByCollection,
322
+  getProductsByTags,
277
   getProductTypes,
323
   getProductTypes,
278
   getCollections,
324
   getCollections,
279
   getTags
325
   getTags

Loading…
Cancel
Save