Goods.jsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. import {
  2. Box,
  3. Button,
  4. Card,
  5. CardActionArea,
  6. CardActions,
  7. CardContent,
  8. CardMedia, Divider,
  9. FormControl,
  10. Grid, MenuItem, Pagination, Select,
  11. Typography
  12. } from "@mui/material";
  13. import Link from "react-router-dom/es/Link";
  14. import {backURL} from "../../actions/PathDB";
  15. import imgNotFound from "../../img/catalog/imgNotFound.png";
  16. import ShoppingCartIcon from "@mui/icons-material/ShoppingCart";
  17. import AddShoppingCartIcon from "@mui/icons-material/AddShoppingCart";
  18. import FavoriteIcon from "@mui/icons-material/Favorite";
  19. import FavoriteBorderIcon from "@mui/icons-material/FavoriteBorder";
  20. import {connect} from "react-redux";
  21. import {actionCardRemove, actionCartAdd} from "../../reducers/CartReducer";
  22. import {actionWishListAdd, actionWishListRemove} from "../../reducers/WishListReducer";
  23. import {useEffect, useState} from "react";
  24. import {NotFoundBlock} from "../../components/NotFoundBlock";
  25. import {actionFullCatById} from "../../actions/ActionCategory";
  26. import Switch from "react-router-dom/es/Switch";
  27. import Route from "react-router-dom/es/Route";
  28. const GoodCard = ({good:{_id, name, description, price, images}={},
  29. wishlist={},
  30. cart={},
  31. onCartAdd,
  32. onWishListAdd,
  33. onCartRemove,
  34. onWishListRemove}) => {
  35. return (
  36. <Grid xs={12} lg={4} item margin='20px 0'>
  37. <Card
  38. sx={{
  39. maxWidth: 345,
  40. height: '100%',
  41. display: 'flex',
  42. flexDirection: 'column',
  43. margin: 'auto 20px'
  44. }}
  45. >
  46. <CardActionArea
  47. sx={{
  48. padding: '0',
  49. flexGrow: '1',
  50. position: 'relative'
  51. }}
  52. >
  53. <Link
  54. to={`/good/${_id}`}
  55. style={{position: 'relative', textDecoration: 'none'}}
  56. >
  57. <CardMedia
  58. sx={{marginBottom: '20px', marginTop: '20px'}}
  59. component="img"
  60. height="230"
  61. image={images && images[0]?.url ? `${backURL}/${images[0]?.url}` : imgNotFound}
  62. alt="Good title image"
  63. />
  64. <CardContent
  65. sx={{
  66. display: 'flex',
  67. flexDirection: 'column',
  68. height: '200px',
  69. justifyContent: 'space-between'
  70. }}
  71. >
  72. <Typography
  73. textAlign='center'
  74. fontFamily='sarif'
  75. letterSpacing='2px'
  76. marginBottom='20px'
  77. fontSize='19px'
  78. sx={{textTransform: 'uppercase', flexGrow: '1'}}
  79. color='#000'
  80. >
  81. {name.length > 30 ? name.split(' ').splice(0, 6).join(' ') : name}
  82. </Typography>
  83. <Typography
  84. textAlign='center'
  85. variant="body2"
  86. color='#616161'
  87. marginBottom='20px'
  88. sx={{ flexGrow: '0'}}
  89. >
  90. {description && description.length > 60 ?
  91. 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' :
  92. description
  93. }
  94. </Typography>
  95. <Typography
  96. textAlign='center'
  97. variant="h5"
  98. color="#000"
  99. sx={{ flexGrow: '0'}}>
  100. $ {parseFloat(price || 0).toFixed(2)}
  101. </Typography>
  102. </CardContent>
  103. </Link>
  104. </CardActionArea>
  105. <CardActions sx={{flexGrow: '0', justifyContent: 'space-between'}}>
  106. <Button
  107. onClick={() => {
  108. _id in cart ?
  109. onCartRemove({_id, name, price, images})
  110. : onCartAdd({_id, name, price, images})}
  111. }
  112. size="small"
  113. color="primary"
  114. >
  115. {_id in cart ?
  116. <ShoppingCartIcon/>
  117. : <AddShoppingCartIcon />
  118. }
  119. </Button>
  120. <Button
  121. onClick={() => {
  122. _id in wishlist ?
  123. onWishListRemove({_id, name, price, images})
  124. : onWishListAdd({_id, name, price, images})}
  125. }
  126. size="small"
  127. color="primary"
  128. >
  129. {_id in wishlist ?
  130. <FavoriteIcon/>
  131. : <FavoriteBorderIcon />
  132. }
  133. </Button>
  134. </CardActions>
  135. </Card>
  136. </Grid>
  137. )
  138. }
  139. const CGoodCard = connect(state => ({wishlist: state.wishlist, cart: state.cart}),
  140. {onCartAdd: actionCartAdd, onWishListAdd: actionWishListAdd, onCartRemove: actionCardRemove,
  141. onWishListRemove: actionWishListRemove})(GoodCard)
  142. const Goods = ({_id, category={}}) => {
  143. const itemsPerPage = 9
  144. const [page, setPage] = useState(1)
  145. const [count, setCount] = useState(1)
  146. const [goods, setGoods] = useState([])
  147. const [sort, setSort] = useState(0)
  148. const sortDefault = () => {
  149. setGoods([goods[0].sort((a, b) => a['name'] > b['name'] ? 1 : -1)])
  150. }
  151. const sortLatest = () => {
  152. setGoods([goods[0].sort((a, b) => b['createdAt'] > a['createdAt'] ? 1 : -1)])
  153. }
  154. const sortLowToHigh = () => {
  155. setGoods([goods[0].sort((a, b) => a['price'] > b['price'] ? 1 : -1)])
  156. }
  157. const sortHighToLow = () => {
  158. setGoods([goods[0].sort((a, b) => b['price'] > a['price'] ? 1 : -1)])
  159. }
  160. const handleChange = (event, value) => {
  161. setPage(value);
  162. }
  163. const handleChangeSelect = (event) => {
  164. setSort(event.target.value);
  165. if (event.target.value === 0) sortDefault()
  166. else if (event.target.value === 1) sortLatest()
  167. else if (event.target.value === 2) sortLowToHigh()
  168. else if (event.target.value === 3) sortHighToLow()
  169. }
  170. useEffect(() => {
  171. let arr = (Object.values(category) || []).map(item => {
  172. if (item['_id'] === _id) {
  173. if (Array.isArray(item?.goods) && item?.goods.length > 0) {
  174. setCount(Math.ceil(item.goods.length / itemsPerPage))
  175. return item.goods
  176. }
  177. }
  178. else if(Array.isArray(item['subCategories'])) {
  179. let arr = item['subCategories'].map(subItem => {
  180. if (subItem['_id'] === _id) {
  181. if (Array.isArray(subItem?.goods) && subItem?.goods.length > 0) {
  182. setCount(Math.ceil(subItem.goods.length / itemsPerPage))
  183. return subItem.goods
  184. }
  185. }
  186. else if(Array.isArray(subItem['subCategories'])) {
  187. let arr = subItem['subCategories'].map(subSubItem => {
  188. if (subSubItem['_id'] === _id) {
  189. if (Array.isArray(subSubItem?.goods && subSubItem?.goods.length > 0)) {
  190. setCount(Math.ceil(subSubItem.goods.length / itemsPerPage))
  191. return subSubItem.goods
  192. }
  193. }
  194. else {
  195. return 0
  196. }
  197. }).filter(item => item)
  198. return arr.length > 0 ? [...arr[0]] : 0
  199. }
  200. else {
  201. return 0
  202. }
  203. }).filter(item => item)
  204. return arr.length > 0 ? [...arr[0]] : 0
  205. }
  206. else {
  207. return 0
  208. }
  209. }).filter(item => item)
  210. setGoods(arr)
  211. }, [_id, category])
  212. return (
  213. <>
  214. {(goods.length > 0 ?
  215. <Box
  216. sx={{height:'100%',
  217. display: 'flex',
  218. flexDirection: 'column',
  219. justifyContent: 'space-between'
  220. }}
  221. >
  222. <Box
  223. display='flex'
  224. alignItems='center'
  225. justifyContent='space-between'
  226. padding='0 20px'
  227. >
  228. <Typography
  229. variant='body1'
  230. color='#616161'
  231. letterSpacing='1px'
  232. >
  233. SHOWING {goods[0].length > itemsPerPage ? `${((page-1) * itemsPerPage)+1}-
  234. ${page * itemsPerPage > goods[0].length ? goods[0].length : page * itemsPerPage}` :
  235. goods[0].length} OF {goods[0].length} RESULTS
  236. </Typography>
  237. <FormControl
  238. variant="standard"
  239. >
  240. <Select
  241. labelId="demo-simple-select-label"
  242. id="demo-simple-select"
  243. value={sort}
  244. label="Sort"
  245. onChange={handleChangeSelect}
  246. sx={{textTransform: 'uppercase', color: '#616161'}}
  247. >
  248. <MenuItem value={0}>Default sorting</MenuItem>
  249. <MenuItem value={1}>Sort by latest</MenuItem>
  250. <MenuItem value={2}>Sort by price: low to high</MenuItem>
  251. <MenuItem value={3}>Sort by price: high to low</MenuItem>
  252. </Select>
  253. </FormControl>
  254. </Box>
  255. <Box
  256. flexGrow='1'
  257. >
  258. <Grid
  259. container
  260. justifyContent='space-between'
  261. >
  262. {[...goods[0]].slice((page - 1) * itemsPerPage, page * itemsPerPage)
  263. .map(good => <CGoodCard key={good['_id']} good={good}/>)
  264. }
  265. </Grid>
  266. </Box>
  267. <Box width='100%' flexGrow='0'>
  268. <Divider sx={{margin: '20px'}}/>
  269. <Box
  270. display='flex'
  271. justifyContent='center'
  272. width='100%'
  273. >
  274. <Pagination
  275. count={count}
  276. page={page}
  277. onChange={handleChange}
  278. defaultPage={1}
  279. color="primary"
  280. size="large"
  281. showFirstButton
  282. showLastButton
  283. />
  284. </Box>
  285. </Box>
  286. </Box>
  287. : <NotFoundBlock marginTop={'-50px'}/>)
  288. }
  289. </>
  290. )
  291. }
  292. const CGoods = connect(state => ({category: state.category}))(Goods)
  293. const BlockGood = ({match:{params:{_id}}, getData}) => {
  294. useEffect(() => {
  295. getData(_id)
  296. },[_id, getData])
  297. return(
  298. <CGoods key={_id} _id={_id} />
  299. )
  300. }
  301. const CBlockGood= connect(null, {getData: actionFullCatById})(BlockGood)
  302. export const Products = () => {
  303. return (
  304. <Grid xs={12} lg={9} item>
  305. <Switch>
  306. <Route path="/catalog/category/:_id" component={CBlockGood} />
  307. <Route path="*" component={NotFoundBlock} />
  308. </Switch>
  309. </Grid>
  310. )
  311. }