123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- import { useEffect, useState } from 'react';
- import { Box, Typography, Button, FormControl, Select, MenuItem, InputBase } from '@mui/material';
- import Grid from '@mui/material/Grid2';
- import { styled } from "@mui/material";
- //REDUX
- import { useSelector, useDispatch } from 'react-redux';
- import { fetchProducts } from '../../redux/slices/productSlice';
-
- //UTIL FUNCTION
- function getAllTags(data) {
- const products = data || [];
- const allTags = products.flatMap(product => product.tags);
- const uniqueTags = [...new Set(allTags)];
- return uniqueTags;
- }
-
- function getAllCollection(data) {
- const products = data || [];
- const allCollection = products.flatMap(product => product.collections);
- const uniqueCollection = Array.from(
- new Map(allCollection.map(item => [item.title, item])).values()
- );
- return uniqueCollection;
- }
-
- const BootstrapInput = styled(InputBase)(({ theme }) => ({
- 'label + &': {
- marginTop: theme.spacing(3),
- },
- '& .MuiInputBase-input': {
- position: 'relative',
- backgroundColor: "#2E2E2E",
- border: '1px solid #ced4da',
- color: "#FFF",
- fontSize: 13,
- padding: '5px 0',
- paddingRight: '50px !important',
- paddingLeft: "10px",
- transition: theme.transitions.create(['border-color', 'box-shadow']),
- '&:focus': {
- borderRadius: 4,
- borderColor: '#80bdff',
- boxShadow: '0 0 0 0.2rem rgba(0,123,255,.25)',
- },
- },
- '& .MuiSvgIcon-root': {
- color: "#FFF !important"
- },
- }));
-
- const ProductList = ({ size = 99999 }) => {
-
- const products = useSelector((state) => state.products.products.data) // only used as referenced
- const [filteredProducts, setFilteredProducts] = useState([]) // this one is the actual data to be rendered
- const [tagFilterOption, setTagFilterOption] = useState([])
- const [collectionFilterOption, setCollectionFilterOption] = useState([])
- const dispatch = useDispatch();
-
- //filter
- const [tags, setTags] = useState('all');
- const [collection, setCollection] = useState('all');
- const [sort, setSort] = useState('title')
-
- useEffect(() => {
-
- dispatch(fetchProducts())
-
- }, [])
-
-
- useEffect(() => {
-
- console.log("Products: ", products)
- if (products.length > 0) {
- let productType = sessionStorage.getItem('amber-select-product-type')
- let newFilteredProducts = products.filter(
- (product) => product.productType === productType
- );
-
- setFilteredProducts(newFilteredProducts)
-
- const tagList = getAllTags(newFilteredProducts);
- setTagFilterOption(tagList);
-
-
- // Filter will only exist if the user haven't click on collection
- if (!sessionStorage.getItem('amber-select-collection')) {
- const collectionList = getAllCollection(newFilteredProducts);
- setCollectionFilterOption(collectionList);
- } else {
- setCollection(sessionStorage.getItem('amber-select-collection'))
- }
-
- }
-
-
- }, [products])
-
-
- useEffect(() => {
-
- if (products?.length > 0) {
-
- let productType = sessionStorage.getItem('amber-select-product-type')
-
- let newFilteredProducts = products.filter(
- (product) => product.productType === productType
- );
-
- // Tags
- newFilteredProducts = newFilteredProducts.filter(
- (product) => {
- if (tags == 'all') {
- return product.productType === productType
- } else {
- return product.productType === productType && product.tags.includes(tags)
- }
-
- }
- );
-
- // Collection
- newFilteredProducts = newFilteredProducts.filter(
- (product) => {
-
- if (collection == 'all') {
- return product.productType === productType
- } else {
- return product.productType === productType && product.collections.some(data => data.title === collection)
- }
-
- }
- );
-
-
- if (sort === "title") {
- newFilteredProducts = newFilteredProducts.sort((a, b) => a.title.localeCompare(b.title));
- } else if (sort === "new") {
- newFilteredProducts = newFilteredProducts.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
- } else if (sort === "old") {
- newFilteredProducts = newFilteredProducts.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt));
- }
-
- setFilteredProducts(newFilteredProducts)
-
- }
-
- }, [tags, collection, sort])
-
- const handleChange = (event) => {
- //setInput({ ...input, [event.target.name]: event.target.value });
- };
-
- const renderProduct = (handle, img_url, title, collection_name, minPrice, minPriceCurrency, maxPrice, maxPriceCurrency, extra_desc) => {
-
- return (
- <Grid className="animate__animated animate__fadeIn" item size={{ xs: 6, sm: 6, md: 3 }}>
-
- <a href={`/products/${handle}`} style={{textDecoration:"none",color:"#000"}}>
- <Box
- sx={{
- overflow: 'hidden',
- position: 'relative',
- cursor: 'pointer'
- }}
-
- >
- <img
- src={img_url}
- alt={title}
- style={{
- width: '100%',
- aspectRatio: '3 / 4',
- objectFit: 'cover',
- objectPosition: 'top center'
- }}
- />
-
- {/* <Button sx={{ position: "absolute", top: 20, left: 20, boxShadow: 0 }} variant="contained">
- NEW
- </Button> */}
-
- <Box sx={{ pb: 5, pt: 3, width: "80%" }}>
- <Typography variant="body1" sx={{ fontWeight: "400", mb: 1 }}>
- {collection_name}
- </Typography>
- <Typography variant="h5" sx={{ fontWeight: "bolder", mb: 1 }}>
- {title}
- </Typography>
- <Typography variant="body1" sx={{ fontWeight: "400" }}>
- {`${minPriceCurrency} ${parseFloat(minPrice).toFixed(2)}`}
- </Typography>
- <Typography variant="body1" sx={{ mt: 2 }}>
- {extra_desc}
- </Typography>
- </Box>
- </Box>
- </a>
- </Grid>
- )
-
- }
-
- return (
- <>
- {/* FILTER */}
- <Box
- sx={{
- display: "flex",
- justifyContent: "space-between",
- py: 0,
- flexDirection: {
- xs: "column",
- sm: "row",
- md: "row",
- lg: "row"
- },
- alignItems: "center",
- backgroundColor: "background.black",
- color: "white",
- px: 2, // Add padding around the box
- my: 4
- }}
- >
- {/* Left Side: Page Title */}
- <Typography variant="body2" sx={{ fontSize: 10, mt: { xs: 1, sm: 1, md: 0 } }}>
- {`${filteredProducts.length} Item`}
- </Typography>
-
- {/* Right Side: Option Inputs */}
- <Box sx={{
- display: "flex", gap: 2, flexDirection: {
- xs: "column",
- sm: "row",
- md: "row",
- lg: "row"
- },
- }}>
-
- {(tagFilterOption.length > 0) && <FormControl sx={{ m: 1, display: "flex", flexDirection: "row" }} variant="standard">
- <Typography variant="body2" sx={{ mr: 1, my: "auto" }}>Tag</Typography>
- <Select
- value={tags}
- onChange={(event) => {
- setTags(event.target.value);
- }}
- sx={{
- '& .MuiSelect-select': {
- border: "none"
- }
- }}
- input={<BootstrapInput />}
- name="type"
- >
- <MenuItem value={'all'}>All</MenuItem>
- {tagFilterOption?.map((data) => (<MenuItem value={data}>{data}</MenuItem>))}
- </Select>
- </FormControl>}
-
- {(collectionFilterOption.length > 0) && <FormControl sx={{ m: 1, display: "flex", flexDirection: "row" }} variant="standard">
- <Typography variant="body2" sx={{ mr: 1, my: "auto" }}>Collection</Typography>
- <Select
- value={collection}
- onChange={(event) => {
- setCollection(event.target.value);
- }}
- sx={{
- '& .MuiSelect-select': {
- border: "none"
- }
- }}
- input={<BootstrapInput />}
- name="type"
- >
- <MenuItem value={'all'}>All</MenuItem>
- {collectionFilterOption?.map(({ title }) => (<MenuItem value={title}>{title}</MenuItem>))}
- </Select>
- </FormControl>}
-
- <FormControl sx={{ m: 1, display: "flex", flexDirection: "row" }} variant="standard">
- <Typography variant="body2" sx={{ mr: 1, my: "auto" }}>Sort</Typography>
- <Select
- value={sort}
- onChange={(event) => {
- setSort(event.target.value);
- }}
- sx={{
- '& .MuiSelect-select': {
- border: "none"
- }
- }}
- input={<BootstrapInput />}
- name="sort"
- >
- <MenuItem defaultValue value={'title'}>Title</MenuItem>
- <MenuItem defaultValue value={'new'}>Newest</MenuItem>
- <MenuItem defaultValue value={'old'}>Oldest</MenuItem>
- </Select>
- </FormControl>
-
- </Box>
- </Box>
-
- {/* LIST */}
- <Box sx={{ mb: 5 }}>
- <Grid container spacing={0.5} columns={12}>
- {filteredProducts.map((product, index) => {
-
- let { handle, title, images, collections, minVariantPrice, maxVariantPrice, productType, variants } = product
-
- let minPrice = minVariantPrice.amount
- let minPriceCurrency = minVariantPrice.currencyCode
- let maxPrice = maxVariantPrice.amount
- let maxPriceCurrency = maxVariantPrice.currencyCode
-
- let img_url = images[0].url
- let collection_name = collections[0].title
-
- if (index < size) {
- return renderProduct(handle, img_url, title, collection_name, minPrice, minPriceCurrency, maxPrice, maxPriceCurrency, "")
- }
-
- })}
- </Grid>
- </Box>
- </>
- );
- };
-
- export default ProductList;
|