123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328 |
- import Breadcrumb from "../components/Breadcrumbs";
- import {
- Accordion,
- AccordionDetails,
- AccordionSummary, Box, Button,
- Card, CardActionArea, CardActions, CardContent, CardMedia,
- Container, Divider, FormControl,
- Grid, MenuItem, Select,
- Typography,
- useMediaQuery
- } from "@mui/material";
- import {connect} from "react-redux";
- import {actionFullCatById, actionFullRootCats} from "../actions/ActionCategory";
- import Link from "react-router-dom/es/Link";
- import Route from "react-router-dom/es/Route";
- import Switch from "react-router-dom/es/Switch";
- import {useEffect, useState} from "react";
- import {backURL} from "../actions/PathDB";
- import {actionCardRemove, actionCartAdd} from "../reducers/CartReducer";
- import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
- import FavoriteBorderIcon from "@mui/icons-material/FavoriteBorder";
- import AddShoppingCartIcon from '@mui/icons-material/AddShoppingCart';
- import {Pagination} from "@mui/material";
- import {actionWishListAdd, actionWishListRemove} from "../reducers/WishListReducer";
- import FavoriteIcon from '@mui/icons-material/Favorite';
- import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
- import imgNotFound from "../img/catalog/imgNotFound.png";
- import {NotFoundBlock} from "../components/NotFoundBlock";
- const CategoryItem = ({object: {_id, name, subCategories}={}}) => {
- const [expanded, setExpanded] = useState(false);
- const handleChange = (panel) => (event, isExpanded) => {
- setExpanded(isExpanded ? panel : false);
- };
- return (
- <>
- {subCategories === null || !subCategories ?
- <li>
- <Link style={{textDecoration: 'none'}} to={`/catalog/category/${_id}`}>
- <Typography
- variant='body1'
- color='#616161'
- marginBottom='10px'
- >
- {name}
- </Typography>
- </Link>
- </li>
- :
- <li>
- <Accordion style={{border: 'none', borderRadius: '0',marginTop: '-10px', boxShadow: 'none'}} expanded={expanded === 'panel1'} onChange={handleChange('panel1')}>
- <AccordionSummary
- sx={{padding: '0'}}
- expandIcon={<ExpandMoreIcon />}
- aria-controls="panel1bh-content"
- id="panel1bh-header"
- >
- <Link style={{textDecoration: 'none'}} to={`/catalog/category/${_id}`}>
- <Typography
- variant='body1'
- color='#616161'
- padding='0'
- >
- {name}
- </Typography>
- </Link>
- </AccordionSummary>
- <AccordionDetails>
- <ul style={{listStyle: 'none', padding: '0 0 0 10px', marginBottom: '10px'}}>
- {subCategories && Object.values(subCategories).map(item =>
- <CategoryItem key={item['_id']} object={item}/>
- )}
- </ul>
- </AccordionDetails>
- </Accordion>
- </li>
- }
- </>
- )
- }
- const CategoryAside = ({category}) => {
- return (
- <Grid sx={{backgroundColor: '#fff', padding: '30px'}} xs={12} lg={3} item>
- <Typography
- variant='h6'
- letterSpacing='3px'
- lineHeight='1.3em'
- marginBottom='20px'
- >
- PRODUCT CATEGORIES
- </Typography>
- <ul style={{listStyle: 'none', padding: '0'}}>
- {category && Object.values(category).map(item =>
- <CategoryItem key={item['_id']} object={item}/>
- )}
- </ul>
- </Grid>
- )
- }
- const GoodCard = ({good:{_id, name, description, price, images}={}, wishlist={}, cart={}, onCartAdd, onWishListAdd, onCartRemove, onWishListRemove}) => {
- return (
- <Grid xs={12} lg={4} item margin='20px 0'>
- <Card sx={{ maxWidth: 345, height: '100%', display: 'flex', flexDirection: 'column', margin: 'auto 20px'}}>
- <CardActionArea sx={{padding: '0', flexGrow: '1', position: 'relative'}}>
- <Link to={`/good/${_id}`} style={{position: 'relative', textDecoration: 'none'}}>
- <CardMedia sx={{marginBottom: '20px', marginTop: '20px'}}
- component="img"
- height="230"
- image={images[0].url ? `${backURL}/${images[0].url}` : imgNotFound}
- alt="Good title image"
- />
- <CardContent sx={{display: 'flex', flexDirection: 'column', height: '200px', justifyContent: 'space-between'}}>
- <Typography
- textAlign='center'
- fontFamily='sarif'
- letterSpacing='2px'
- marginBottom='20px'
- fontSize='19px'
- sx={{textTransform: 'uppercase', flexGrow: '1'}}
- color='#000'
- >
- {name.length > 30 ? name.split(' ').splice(0, 6).join(' ') : name}
- </Typography>
- <Typography textAlign='center' variant="body2" color='#616161' marginBottom='20px' sx={{ flexGrow: '0'}}>
- {description.length > 60 ?
- 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' :
- description
- }
- </Typography>
- <Typography textAlign='center' variant="h5" color="#000" sx={{ flexGrow: '0'}}>
- $ {parseFloat(price).toFixed(2)}
- </Typography>
- </CardContent>
- </Link>
- </CardActionArea>
- <CardActions sx={{flexGrow: '0', justifyContent: 'space-between'}}>
- <Button onClick={() => {_id in cart ? onCartRemove({_id, name, price, images}) : onCartAdd({_id, name, price, images})}} size="small" color="primary">
- {_id in cart ? <ShoppingCartIcon/> : <AddShoppingCartIcon />}
- </Button>
- <Button onClick={() => {_id in wishlist ? onWishListRemove({_id, name, price, images}) : onWishListAdd({_id, name, price, images})}} size="small" color="primary">
- {_id in wishlist ? <FavoriteIcon/> : <FavoriteBorderIcon />}
- </Button>
- </CardActions>
- </Card>
- </Grid>
- )
- }
- const CGoodCard = connect(state => ({wishlist: state.wishlist, cart: state.cart}),
- {onCartAdd: actionCartAdd, onWishListAdd: actionWishListAdd, onCartRemove: actionCardRemove, onWishListRemove: actionWishListRemove})(GoodCard)
- const Goods = ({_id='5dc49f4d5df9d670df48cc64', category={}}) => {
- const itemsPerPage = 6
- const [page, setPage] = useState(1)
- const [count, setCount] = useState(1)
- const [goods, setGoods] = useState([])
- const [sort, setSort] = useState(0)
- const sortDefault = () => {
- setGoods([goods[0].sort((a, b) => a['name'] > b['name'] ? 1 : -1)])
- }
- const sortLatest = () => {
- setGoods([goods[0].sort((a, b) => b['createdAt'] > a['createdAt'] ? 1 : -1)])
- }
- const sortLowToHigh = () => {
- setGoods([goods[0].sort((a, b) => a['price'] > b['price'] ? 1 : -1)])
- }
- const sortHighToLow = () => {
- setGoods([goods[0].sort((a, b) => b['price'] > a['price'] ? 1 : -1)])
- }
- const handleChange = (event, value) => {
- setPage(value);
- }
- const handleChangeSelect = (event) => {
- setSort(event.target.value);
- if (event.target.value === 0) sortDefault()
- else if (event.target.value === 1) sortLatest()
- else if (event.target.value === 2) sortLowToHigh()
- else if (event.target.value === 3) sortHighToLow()
- }
- useEffect(() => {
- let arr = (Object.values(category) || []).map(item => {
- if (item['_id'] === _id) {
- if (Array.isArray(item?.goods) && item?.goods.length > 0) {
- setCount(Math.ceil(item.goods.length / itemsPerPage))
- return item.goods
- }
- }
- else if(Array.isArray(item['subCategories'])) {
- let arr = item['subCategories'].map(subItem => {
- if (subItem['_id'] === _id) {
- if (Array.isArray(subItem?.goods) && subItem?.goods.length > 0) {
- setCount(Math.ceil(subItem.goods.length / itemsPerPage))
- return subItem.goods
- }
- }
- else if(Array.isArray(subItem['subCategories'])) {
- let arr = subItem['subCategories'].map(subSubItem => {
- if (subSubItem['_id'] === _id) {
- if (Array.isArray(subSubItem?.goods && subSubItem?.goods.length > 0)) {
- setCount(Math.ceil(subSubItem.goods.length / itemsPerPage))
- return subSubItem.goods
- }
- }
- else {
- return 0
- }
- }).filter(item => item)
- return arr.length > 0 ? [...arr[0]] : 0
- }
- else {
- return 0
- }
- }).filter(item => item)
- return arr.length > 0 ? [...arr[0]] : 0
- }
- else {
- return 0
- }
- }).filter(item => item)
- setGoods(arr)
- }, [_id, category])
- return (
- <>
- {(goods.length > 0 ?
- <Box sx={{height:'100%', display: 'flex', flexDirection: 'column', justifyContent: 'space-between'}}>
- <Box display='flex' alignItems='center' justifyContent='space-between' padding='0 20px'>
- <Typography
- variant='body1'
- color='#616161'
- letterSpacing='1px'
- >
- SHOWING {goods[0].length > itemsPerPage ? `${((page-1) * itemsPerPage)+1}-${page * itemsPerPage > goods[0].length ? goods[0].length : page * itemsPerPage}` : goods[0].length} OF {goods[0].length} RESULTS
- </Typography>
- <FormControl variant="standard">
- <Select
- labelId="demo-simple-select-label"
- id="demo-simple-select"
- value={sort}
- label="Sort"
- onChange={handleChangeSelect}
- sx={{textTransform: 'uppercase', color: '#616161'}}
- >
- <MenuItem value={0}>Default sorting</MenuItem>
- <MenuItem value={1}>Sort by latest</MenuItem>
- <MenuItem value={2}>Sort by price: low to high</MenuItem>
- <MenuItem value={3}>Sort by price: high to low</MenuItem>
- </Select>
- </FormControl>
- </Box>
- <Box flexGrow='1'>
- <Grid container justifyContent='space-between'>
- {[...goods[0]].slice((page - 1) * itemsPerPage, page * itemsPerPage)
- .map(good => <CGoodCard key={good['_id']} good={good}/>)}
- </Grid>
- </Box>
- <Box width='100%' flexGrow='0'>
- <Divider sx={{margin: '20px'}}/>
- <Box display='flex' justifyContent='center' width='100%'>
- <Pagination
- count={count}
- page={page}
- onChange={handleChange}
- defaultPage={1}
- color="primary"
- size="large"
- showFirstButton
- showLastButton
- />
- </Box>
- </Box>
- </Box>
- : <NotFoundBlock/>)
- }
- </>
- )
- }
- const CGoods = connect(state => ({category: state.category}))(Goods)
- const BlockGood = ({match:{params:{_id}}, getData}) => {
- useEffect(() => {
- getData(_id)
- },[_id, getData])
- return(
- <CGoods key={_id} _id={_id} />
- )
- }
- const CBlockGood= connect(null, {getData: actionFullCatById})(BlockGood)
- const Products = () => {
- return (
- <Grid xs={12} lg={9} item>
- <Switch>
- <Route path="/catalog/category/:_id" component={CBlockGood} />
- <Route path="*" component={NotFoundBlock} />
- </Switch>
- </Grid>
- )
- }
- const CatalogPage = ({category={}, actionRootCat}) => {
- const matches = useMediaQuery('(max-width:899px)')
- if(Object.entries(category).length === 0) actionRootCat()
- return (
- <>
- <Breadcrumb links={['catalog']}/>
- <main style={{backgroundColor: "#f3f3f3", padding: matches ? "20px 0" : "50px 0"}}>
- <Container maxWidth="lg">
- <Grid container justifyContent='space-between'>
- <CategoryAside category={category}/>
- <Products/>
- </Grid>
- </Container>
- </main>
- </>
- )
- }
- const CCatalogPage = connect(state => ({category: state.category}), {actionRootCat: actionFullRootCats})(CatalogPage)
- export default CCatalogPage
- //TODO MOBILE VERSION
|