Browse Source

collections menu

master
azri 4 weeks ago
parent
commit
2c7c26005b

+ 9
- 0
src/App.js View File

14
 import { ThemeProvider } from '@mui/material';
14
 import { ThemeProvider } from '@mui/material';
15
 import { fetchCart, createCart } from './redux/slices/cartSlice';
15
 import { fetchCart, createCart } from './redux/slices/cartSlice';
16
 import { useSelector, useDispatch } from 'react-redux';
16
 import { useSelector, useDispatch } from 'react-redux';
17
+import Collection from './pages/Collection';
17
 
18
 
18
 const isEmptyObject = (obj) => Object.keys(obj).length === 0 && obj.constructor === Object;
19
 const isEmptyObject = (obj) => Object.keys(obj).length === 0 && obj.constructor === Object;
19
 
20
 
61
           <Route path='/newsletter' element={<Newsletter />} />
62
           <Route path='/newsletter' element={<Newsletter />} />
62
           <Route path='/cart' element={<Cart />} />
63
           <Route path='/cart' element={<Cart />} />
63
           <Route path='/checkout' element={<Checkout />} />
64
           <Route path='/checkout' element={<Checkout />} />
65
+
66
+          <Route path='collection'>
67
+            {/* All Products */}
68
+            <Route index element={<Products />} />
69
+            {/* Single Product */}
70
+            <Route path=':pid' element={<Collection />} />
71
+          </Route>
72
+
64
         </Routes>
73
         </Routes>
65
       </BrowserRouter>
74
       </BrowserRouter>
66
       <Footer />
75
       <Footer />

BIN
src/assets/images/titleBg.jpg View File


+ 71
- 0
src/components/CollectionList/CollectionList.jsx View File

1
+import { useEffect, useState } from "react";
2
+import { Box, Typography, Button } from "@mui/material";
3
+import ProductService from "../../services/ProductService";
4
+import Grid from '@mui/material/Grid2';
5
+
6
+const CollectionList = ({ collectionName }) => {
7
+
8
+  const [collections, setCollections] = useState([])
9
+
10
+  useEffect(() => {
11
+
12
+    ProductService.getCollections(collectionName).then((data) => {
13
+      setCollections(data)
14
+    })
15
+
16
+  }, [])
17
+
18
+
19
+
20
+  return (
21
+    <Box sx={{ flexGrow: 1, mt: 10 }}>
22
+      <Grid container spacing={2}>
23
+
24
+        {collections.map(({id, name, src}) => {
25
+
26
+          return (<Grid size={12}>
27
+            <Box
28
+              sx={{
29
+                position: 'relative',
30
+                width: '100%',
31
+                height: 0,
32
+                backgroundImage: `url("${src}")`,
33
+                backgroundSize: "cover",
34
+                backgroundPosition: "top center",
35
+                paddingTop: '600px', // This sets the height based on top padding
36
+                overflow: 'hidden',
37
+              }}
38
+            >
39
+              <Box
40
+                sx={{
41
+                  position: 'absolute',
42
+                  top: 0,
43
+                  left: 0,
44
+                  width: '100%',
45
+                  height: '100%',
46
+                  backgroundColor: 'rgba(0, 0, 0, 0.5)', // Filter overlay
47
+                  display: 'flex',
48
+                  flexDirection: 'column',
49
+                  justifyContent: 'center',
50
+                  alignItems: 'center',
51
+                  color: '#fff', // Text and button color for visibility
52
+                }}
53
+              >
54
+                <Typography variant="h4" gutterBottom>
55
+                  {name}
56
+                </Typography>
57
+                <Button onClick={()=>{ window.location.href = "/products" }} variant="contained" color="primary">
58
+                  SHOP NOW
59
+                </Button>
60
+              </Box>
61
+            </Box>
62
+          </Grid>)
63
+        })}
64
+
65
+
66
+      </Grid>
67
+    </Box>
68
+  );
69
+};
70
+
71
+export default CollectionList;

+ 1
- 0
src/components/CollectionList/index.js View File

1
+export { default } from "./CollectionList"

+ 41
- 0
src/components/CollectionViewer/ProductType.jsx View File

1
+import React from 'react';
2
+import { Box, Button, Typography } from '@mui/material';
3
+
4
+const ProductType = () => {
5
+  return (
6
+    <Box
7
+      sx={{
8
+        position: 'relative',
9
+        width: '100%',
10
+        height: 0,
11
+        paddingTop: '600px', // This sets the height based on top padding
12
+        overflow: 'hidden',
13
+      }}
14
+    >
15
+      <Box
16
+        sx={{
17
+          position: 'absolute',
18
+          top: 0,
19
+          left: 0,
20
+          width: '100%',
21
+          height: '100%',
22
+          backgroundColor: 'rgba(0, 0, 0, 0.5)', // Filter overlay
23
+          display: 'flex',
24
+          flexDirection: 'column',
25
+          justifyContent: 'center',
26
+          alignItems: 'center',
27
+          color: '#fff', // Text and button color for visibility
28
+        }}
29
+      >
30
+        <Typography variant="h4" gutterBottom>
31
+          Some Type
32
+        </Typography>
33
+        <Button variant="contained" color="primary">
34
+          SHOP NOW
35
+        </Button>
36
+      </Box>
37
+    </Box>
38
+  );
39
+};
40
+
41
+export default ProductType;

+ 1
- 0
src/components/CollectionViewer/index.js View File

1
+export { default } from './ProductType'

+ 24
- 21
src/components/Navbar/Navbar.jsx View File

19
 import LoyaltyIcon from '@mui/icons-material/Loyalty';
19
 import LoyaltyIcon from '@mui/icons-material/Loyalty';
20
 import Grid from '@mui/material/Grid2';
20
 import Grid from '@mui/material/Grid2';
21
 import { useSelector } from 'react-redux';
21
 import { useSelector } from 'react-redux';
22
+import ProductService from "../../services/ProductService";
22
 
23
 
23
 function calculateTotalQuantity(cartItems) {
24
 function calculateTotalQuantity(cartItems) {
24
   return cartItems.reduce((total, item) => total + item.quantity, 0);
25
   return cartItems.reduce((total, item) => total + item.quantity, 0);
55
   },
56
   },
56
 }));
57
 }));
57
 
58
 
58
-const navItem = [
59
-  {
60
-    title: "DISCOVER",
61
-    link: "/products",
62
-    icon: <CategoryIcon />
63
-  },
64
-  {
65
-    title: "HOME",
66
-    link: "/products",
67
-    icon: <HomeIcon />
68
-  },
69
-  {
70
-    title: "BEAUTY",
71
-    link: "/products",
72
-    icon: <BrushIcon />
73
-  }
74
-]
75
-
76
-
77
 const Navbar = () => {
59
 const Navbar = () => {
78
 
60
 
79
   const [showHeader, setShowHeader] = useState(true);
61
   const [showHeader, setShowHeader] = useState(true);
84
   const [cartAmount, setCartAmount] = useState(0);
66
   const [cartAmount, setCartAmount] = useState(0);
85
 
67
 
86
   const [open, setOpen] = React.useState(false);
68
   const [open, setOpen] = React.useState(false);
69
+  const [navItem, setNavItem] = useState([])
70
+
71
+  useEffect(()=>{
72
+    fetchProductTypes()
73
+  },[])
74
+
75
+  const fetchProductTypes = async () => {
76
+    try {
77
+      const data = await ProductService.getProductTypes();
78
+  
79
+      if (Array.isArray(data)) {
80
+
81
+        let navItemData = data.map(({node})=>({title:`${node.toUpperCase()}`, link:`/collection/${node}` }))
82
+        setNavItem(navItemData);
83
+
84
+      } else {
85
+        setNavItem([]); 
86
+      }
87
+    } catch (error) {
88
+      console.error("Error fetching product types:", error);
89
+      setNavItem([]); // Handle error by setting fallback empty array
90
+    }
91
+  };
87
 
92
 
88
   useEffect(() => {
93
   useEffect(() => {
89
 
94
 
93
 
98
 
94
   }, [cart])
99
   }, [cart])
95
 
100
 
96
-
97
-
98
   const handleChange = (event) => {
101
   const handleChange = (event) => {
99
     setLanguage(event.target.value);
102
     setLanguage(event.target.value);
100
   };
103
   };

+ 1
- 2
src/components/Navbar/components/MobileNav/MobileNav.jsx View File

40
       {/* Main Navigation */}
40
       {/* Main Navigation */}
41
       <Box sx={{ width: 250 }} role="presentation">
41
       <Box sx={{ width: 250 }} role="presentation">
42
         <List>
42
         <List>
43
-          {menu.map(({ title, link, icon }) => (
43
+          {menu.map(({ title, link }) => (
44
             <ListItem key={title} disablePadding>
44
             <ListItem key={title} disablePadding>
45
               <ListItemButton
45
               <ListItemButton
46
                 onClick={() => { window.location.href = link }}
46
                 onClick={() => { window.location.href = link }}
52
                   },
52
                   },
53
                 }}
53
                 }}
54
               >
54
               >
55
-                {icon}
56
                 <ListItemText sx={{ ml: 2 }} primary={title} />
55
                 <ListItemText sx={{ ml: 2 }} primary={title} />
57
               </ListItemButton>
56
               </ListItemButton>
58
             </ListItem>
57
             </ListItem>

+ 6
- 4
src/components/PageTitle/PageTitle.jsx View File

1
 import React from "react";
1
 import React from "react";
2
 import Box from "@mui/material/Box";
2
 import Box from "@mui/material/Box";
3
+
3
 import Typography from "@mui/material/Typography";
4
 import Typography from "@mui/material/Typography";
4
 
5
 
5
-const PageTitle = () => {
6
+const PageTitle = ({title = "", image = ""}) => {
7
+
6
   return (
8
   return (
7
     <Box
9
     <Box
8
       sx={{
10
       sx={{
9
         position: "relative",
11
         position: "relative",
10
         minHeight: "300px",
12
         minHeight: "300px",
11
-        backgroundImage: `url("https://p16-va.lemon8cdn.com/tos-alisg-v-a3e477-sg/1bab0c0797934592bb5a705ad62ed4c4~tplv-tej9nj120t-origin.webp")`,
13
+        backgroundImage: `url("${image}")`,
12
         backgroundSize: "cover",
14
         backgroundSize: "cover",
13
-        backgroundPosition: "center",
15
+        backgroundPosition: "top center",
14
         color: "white",
16
         color: "white",
15
         textAlign: "center",
17
         textAlign: "center",
16
         overflow: "hidden", // Ensures the dim layer stays inside the box
18
         overflow: "hidden", // Ensures the dim layer stays inside the box
39
           margin:"auto auto"
41
           margin:"auto auto"
40
         }}
42
         }}
41
       >
43
       >
42
-        ATMA SARI COLLECTION
44
+        {title.toUpperCase() || " "}
43
       </Typography>
45
       </Typography>
44
     </Box>
46
     </Box>
45
   );
47
   );

+ 1
- 1
src/components/ProductSelected/ProductSelected.jsx View File

11
 
11
 
12
   useEffect(() => {
12
   useEffect(() => {
13
 
13
 
14
-    dispatch(fetchProducts())
14
+    dispatch(fetchProducts({maxResults: 4, sortBy:'TITLE', customQuery:"tag:new"}))
15
 
15
 
16
   }, [])
16
   }, [])
17
 
17
 

+ 5
- 5
src/pages/Cart.jsx View File

138
 
138
 
139
                     </TableCell>
139
                     </TableCell>
140
 
140
 
141
+                    <TableCell align='center'>
142
+                      <Typography variant='body2' sx={{ fontWeight: "bold" }} >{title}</Typography>
143
+                    </TableCell>
144
+
141
                     <TableCell align='center'>
145
                     <TableCell align='center'>
142
                       <Box sx={{ display: "flex", justifyContent: "center" }}>
146
                       <Box sx={{ display: "flex", justifyContent: "center" }}>
143
 
147
 
159
 
163
 
160
                       </Box>
164
                       </Box>
161
                     </TableCell>
165
                     </TableCell>
162
-                    
163
-                    <TableCell align='center'>
164
-                      <Typography variant='body2' sx={{ fontWeight: "bold" }} >{title}</Typography>
165
-                    </TableCell>
166
 
166
 
167
                     <TableCell align='center'>
167
                     <TableCell align='center'>
168
                       <Typography variant='h6' sx={{ fontWeight: "bold" }}>{`${currencyCode} ${parseFloat(amount).toFixed(2)}`}</Typography>
168
                       <Typography variant='h6' sx={{ fontWeight: "bold" }}>{`${currencyCode} ${parseFloat(amount).toFixed(2)}`}</Typography>
169
                     </TableCell>
169
                     </TableCell>
170
-
170
+                    
171
                   </TableRow>
171
                   </TableRow>
172
                 )
172
                 )
173
 
173
 

+ 46
- 0
src/pages/Collection.jsx View File

1
+import { useEffect } from 'react'
2
+import { useParams } from 'react-router-dom'
3
+import PageTitle from '../components/PageTitle'
4
+import Filter from '../components/Filter'
5
+import ProductList from '../components/ProductList'
6
+import { Box } from '@mui/material'
7
+import SocialMedia from '../components/SocialMedia'
8
+import Feature from '../components/Feature'
9
+import { useSelector, useDispatch } from 'react-redux'
10
+import { fetchProducts } from '../redux/slices/productSlice'
11
+import image from "../assets/images/titleBg.jpg"
12
+import CollectionList from '../components/CollectionList/CollectionList'
13
+
14
+const Collection = () => {
15
+
16
+  let { pid } = useParams();
17
+  const dispatch = useDispatch();
18
+
19
+  useEffect(()=>{
20
+
21
+   //dispatch(fetchProducts(250, 'created_at',  `product_type:${pid}`))
22
+
23
+  }, [])
24
+
25
+  return (
26
+    <>
27
+      <PageTitle title={`${pid} COLLECTIONS`} image={image} />
28
+      <CollectionList collectionName={pid}/>
29
+      <Box sx={{
30
+        px: {
31
+          xs: 2,
32
+          md: 12,
33
+          lg: 20
34
+        },
35
+        mb: {
36
+          xs: 0,
37
+          md: 5,
38
+          lg: 10
39
+        }
40
+      }}>
41
+      </Box>
42
+    </>
43
+  )
44
+}
45
+
46
+export default Collection

+ 1
- 1
src/pages/Home.jsx View File

58
           </Grid>
58
           </Grid>
59
 
59
 
60
           <Grid size={{xs:12, md:2}} sx={{display:"flex", alignItems:"center", py:{xs:2, md:0} }}>
60
           <Grid size={{xs:12, md:2}} sx={{display:"flex", alignItems:"center", py:{xs:2, md:0} }}>
61
-            <Link href="#" sx={{ color:"#000", textDecoration: "underline", m:{xs:"auto auto auto auto", md:"0 0 0 auto"}}}>VIEW ALL</Link>
61
+            <Link href="/product" sx={{ color:"#000", textDecoration: "underline", m:{xs:"auto auto auto auto", md:"0 0 0 auto"}}}>VIEW ALL</Link>
62
           </Grid>
62
           </Grid>
63
 
63
 
64
         </Grid>
64
         </Grid>

+ 0
- 1
src/pages/Products/Product.jsx View File

18
   const product = useSelector((state) => state.products.product.data)
18
   const product = useSelector((state) => state.products.product.data)
19
   const dispatch = useDispatch();
19
   const dispatch = useDispatch();
20
   
20
   
21
-
22
   useEffect(() => {
21
   useEffect(() => {
23
 
22
 
24
     dispatch(fetchProduct(pid))
23
     dispatch(fetchProduct(pid))

+ 3
- 2
src/redux/slices/productSlice.js View File

33
 
33
 
34
 export const fetchProducts = createAsyncThunk(
34
 export const fetchProducts = createAsyncThunk(
35
   'product/fetchProducts',
35
   'product/fetchProducts',
36
-  async () => {
37
-    const response = await ProductService.getProducts()
36
+  async ({maxResults, sortBy, customQuery}) => {
37
+
38
+    const response = await ProductService.getProducts(maxResults, sortBy, customQuery)
38
     return response
39
     return response
39
 
40
 
40
   }
41
   }

+ 69
- 3
src/services/ProductService.js View File

2
 import { REACT_APP_ACCESS_TOKEN, REACT_APP_SHOP_NAME } from '../utils/httpCommon'
2
 import { REACT_APP_ACCESS_TOKEN, REACT_APP_SHOP_NAME } from '../utils/httpCommon'
3
 
3
 
4
 const defaultQuery = 'status:active, product_type:clothing, product_categroy:dresses';
4
 const defaultQuery = 'status:active, product_type:clothing, product_categroy:dresses';
5
-const defaultResult = 10;
5
+const defaultResult = 250;
6
 const defaultSortBy = 'TITLE';
6
 const defaultSortBy = 'TITLE';
7
 
7
 
8
 const client = createStorefrontApiClient({
8
 const client = createStorefrontApiClient({
15
 const getProducts = async (maxResults = defaultResult, sortBy = defaultSortBy, customQuery = defaultQuery) => {
15
 const getProducts = async (maxResults = defaultResult, sortBy = defaultSortBy, customQuery = defaultQuery) => {
16
 
16
 
17
   const query = `{
17
   const query = `{
18
-    products(first: ${maxResults}, query: "${customQuery}", sortKey: ${sortBy}) {
18
+    products(first: ${maxResults}, query: "${customQuery}", sortKey:${sortBy}) {
19
       nodes {
19
       nodes {
20
         id
20
         id
21
         title
21
         title
65
     },
65
     },
66
   });
66
   });
67
 
67
 
68
+  debugger
69
+
68
   return data.products.nodes
70
   return data.products.nodes
69
 
71
 
70
 }
72
 }
126
 
128
 
127
 }
129
 }
128
 
130
 
131
+const getProductTypes = async () => {
132
+  const query = `{
133
+    productTypes(first: 250) {
134
+      edges {
135
+        node
136
+      }
137
+    }  
138
+  }`
139
+
140
+  const { data, errors, extensions } = await client.request(query, {
141
+    variables: {},
142
+  });
143
+
144
+  return data.productTypes.edges
145
+}
146
+
147
+const getCollections = async (name) => {
148
+
149
+  const query = `{
150
+    products(first: 250, query: "product_type:${name}") {
151
+      nodes {
152
+        createdAt
153
+        productType
154
+        collections(first: 1) {
155
+          nodes {
156
+            title
157
+            id
158
+            image {
159
+              src
160
+            }
161
+          }
162
+        }
163
+      }
164
+    }
165
+  }`
166
+
167
+  const { data, errors, extensions } = await client.request(query, {
168
+    variables: {},
169
+  });
170
+
171
+  const uniqueCollections = new Map();
172
+
173
+  // Iterate through all products
174
+  data.products.nodes.forEach((product) => {
175
+    // Iterate through each collection within a product
176
+    product.collections.nodes.forEach((collection) => {
177
+      const { title, id, image } = collection;
178
+
179
+      // Use the collection ID as a unique key to avoid duplicates
180
+      if (!uniqueCollections.has(id)) {
181
+        uniqueCollections.set(id, {
182
+          name: title,
183
+          id,
184
+          src: image ? image.src : null, // Handle null image gracefully
185
+        });
186
+      }
187
+    });
188
+  });
189
+
190
+  return Array.from(uniqueCollections.values());
191
+
192
+}
129
 
193
 
130
 const ProductService = {
194
 const ProductService = {
131
   getProducts,
195
   getProducts,
132
-  getProduct
196
+  getProduct,
197
+  getProductTypes,
198
+  getCollections
133
 }
199
 }
134
 
200
 
135
 export default ProductService
201
 export default ProductService

Loading…
Cancel
Save