Quellcode durchsuchen

create product page

Alex vor 2 Jahren
Ursprung
Commit
332d385b5e

+ 5 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -1,6 +1,11 @@
 <component name="InspectionProjectProfileManager">
   <profile version="1.0">
     <option name="myName" value="Project Default" />
+    <inspection_tool class="DuplicatedCode" enabled="true" level="WEAK WARNING" enabled_by_default="true">
+      <Languages>
+        <language minSize="87" name="JavaScript" />
+      </Languages>
+    </inspection_tool>
     <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
     <inspection_tool class="HtmlUnknownAttribute" enabled="true" level="WARNING" enabled_by_default="true">
       <option name="myValues">

+ 156 - 0
package-lock.json

@@ -24,6 +24,7 @@
         "prop-types": "^15.8.0",
         "react": "^17.0.2",
         "react-dom": "^17.0.2",
+        "react-material-ui-carousel": "^3.1.1",
         "react-redux": "^7.2.6",
         "react-router-dom": "^5.3.0",
         "react-scripts": "5.0.0",
@@ -8539,6 +8540,48 @@
         "url": "https://www.patreon.com/infusion"
       }
     },
+    "node_modules/framer-motion": {
+      "version": "4.1.17",
+      "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-4.1.17.tgz",
+      "integrity": "sha512-thx1wvKzblzbs0XaK2X0G1JuwIdARcoNOW7VVwjO8BUltzXPyONGAElLu6CiCScsOQRI7FIk/45YTFtJw5Yozw==",
+      "dependencies": {
+        "framesync": "5.3.0",
+        "hey-listen": "^1.0.8",
+        "popmotion": "9.3.6",
+        "style-value-types": "4.1.4",
+        "tslib": "^2.1.0"
+      },
+      "optionalDependencies": {
+        "@emotion/is-prop-valid": "^0.8.2"
+      },
+      "peerDependencies": {
+        "react": ">=16.8 || ^17.0.0",
+        "react-dom": ">=16.8 || ^17.0.0"
+      }
+    },
+    "node_modules/framer-motion/node_modules/@emotion/is-prop-valid": {
+      "version": "0.8.8",
+      "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
+      "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
+      "optional": true,
+      "dependencies": {
+        "@emotion/memoize": "0.7.4"
+      }
+    },
+    "node_modules/framer-motion/node_modules/@emotion/memoize": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
+      "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
+      "optional": true
+    },
+    "node_modules/framesync": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/framesync/-/framesync-5.3.0.tgz",
+      "integrity": "sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA==",
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
     "node_modules/fresh": {
       "version": "0.5.2",
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -8987,6 +9030,11 @@
         "he": "bin/he"
       }
     },
+    "node_modules/hey-listen": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
+      "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
+    },
     "node_modules/history": {
       "version": "4.10.1",
       "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
@@ -13385,6 +13433,17 @@
         "node": ">=4"
       }
     },
+    "node_modules/popmotion": {
+      "version": "9.3.6",
+      "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-9.3.6.tgz",
+      "integrity": "sha512-ZTbXiu6zIggXzIliMi8LGxXBF5ST+wkpXGEjeTUDUOCdSQ356hij/xjeUdv0F8zCQNeqB1+PR5/BB+gC+QLAPw==",
+      "dependencies": {
+        "framesync": "5.3.0",
+        "hey-listen": "^1.0.8",
+        "style-value-types": "4.1.4",
+        "tslib": "^2.1.0"
+      }
+    },
     "node_modules/portfinder": {
       "version": "1.0.28",
       "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -14877,6 +14936,23 @@
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
     },
+    "node_modules/react-material-ui-carousel": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/react-material-ui-carousel/-/react-material-ui-carousel-3.1.1.tgz",
+      "integrity": "sha512-MmU0eQ9NXMAfPOoK8mR5qPBdMvrtIPXq+FHRiiT+FDXQARKoLO4G1UJP/iMQHWx+9/w9hF8QfZvxZSSs3ab+nA==",
+      "dependencies": {
+        "framer-motion": "^4.1.17"
+      },
+      "peerDependencies": {
+        "@emotion/react": "^11.4.1",
+        "@emotion/styled": "^11.3.0",
+        "@mui/icons-material": "^5.0.0",
+        "@mui/material": "^5.0.0",
+        "@mui/styles": "^5.0.0",
+        "react": "^17.0.1",
+        "react-dom": "^17.0.1"
+      }
+    },
     "node_modules/react-redux": {
       "version": "7.2.6",
       "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz",
@@ -16650,6 +16726,15 @@
         "webpack": "^5.0.0"
       }
     },
+    "node_modules/style-value-types": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-4.1.4.tgz",
+      "integrity": "sha512-LCJL6tB+vPSUoxgUBt9juXIlNJHtBMy8jkXzUJSBzeHWdBu6lhzHqCvLVkXFGsFIlNa2ln1sQHya/gzaFmB2Lg==",
+      "dependencies": {
+        "hey-listen": "^1.0.8",
+        "tslib": "^2.1.0"
+      }
+    },
     "node_modules/stylehacks": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz",
@@ -24547,6 +24632,44 @@
       "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz",
       "integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA=="
     },
+    "framer-motion": {
+      "version": "4.1.17",
+      "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-4.1.17.tgz",
+      "integrity": "sha512-thx1wvKzblzbs0XaK2X0G1JuwIdARcoNOW7VVwjO8BUltzXPyONGAElLu6CiCScsOQRI7FIk/45YTFtJw5Yozw==",
+      "requires": {
+        "@emotion/is-prop-valid": "^0.8.2",
+        "framesync": "5.3.0",
+        "hey-listen": "^1.0.8",
+        "popmotion": "9.3.6",
+        "style-value-types": "4.1.4",
+        "tslib": "^2.1.0"
+      },
+      "dependencies": {
+        "@emotion/is-prop-valid": {
+          "version": "0.8.8",
+          "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
+          "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
+          "optional": true,
+          "requires": {
+            "@emotion/memoize": "0.7.4"
+          }
+        },
+        "@emotion/memoize": {
+          "version": "0.7.4",
+          "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
+          "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
+          "optional": true
+        }
+      }
+    },
+    "framesync": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/framesync/-/framesync-5.3.0.tgz",
+      "integrity": "sha512-oc5m68HDO/tuK2blj7ZcdEBRx3p1PjrgHazL8GYEpvULhrtGIFbQArN6cQS2QhW8mitffaB+VYzMjDqBxxQeoA==",
+      "requires": {
+        "tslib": "^2.1.0"
+      }
+    },
     "fresh": {
       "version": "0.5.2",
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -24870,6 +24993,11 @@
       "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
       "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
     },
+    "hey-listen": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
+      "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
+    },
     "history": {
       "version": "4.10.1",
       "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
@@ -28103,6 +28231,17 @@
         }
       }
     },
+    "popmotion": {
+      "version": "9.3.6",
+      "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-9.3.6.tgz",
+      "integrity": "sha512-ZTbXiu6zIggXzIliMi8LGxXBF5ST+wkpXGEjeTUDUOCdSQ356hij/xjeUdv0F8zCQNeqB1+PR5/BB+gC+QLAPw==",
+      "requires": {
+        "framesync": "5.3.0",
+        "hey-listen": "^1.0.8",
+        "style-value-types": "4.1.4",
+        "tslib": "^2.1.0"
+      }
+    },
     "portfinder": {
       "version": "1.0.28",
       "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
@@ -29040,6 +29179,14 @@
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
     },
+    "react-material-ui-carousel": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/react-material-ui-carousel/-/react-material-ui-carousel-3.1.1.tgz",
+      "integrity": "sha512-MmU0eQ9NXMAfPOoK8mR5qPBdMvrtIPXq+FHRiiT+FDXQARKoLO4G1UJP/iMQHWx+9/w9hF8QfZvxZSSs3ab+nA==",
+      "requires": {
+        "framer-motion": "^4.1.17"
+      }
+    },
     "react-redux": {
       "version": "7.2.6",
       "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz",
@@ -30401,6 +30548,15 @@
       "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==",
       "requires": {}
     },
+    "style-value-types": {
+      "version": "4.1.4",
+      "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-4.1.4.tgz",
+      "integrity": "sha512-LCJL6tB+vPSUoxgUBt9juXIlNJHtBMy8jkXzUJSBzeHWdBu6lhzHqCvLVkXFGsFIlNa2ln1sQHya/gzaFmB2Lg==",
+      "requires": {
+        "hey-listen": "^1.0.8",
+        "tslib": "^2.1.0"
+      }
+    },
     "stylehacks": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz",

+ 1 - 0
package.json

@@ -19,6 +19,7 @@
     "prop-types": "^15.8.0",
     "react": "^17.0.2",
     "react-dom": "^17.0.2",
+    "react-material-ui-carousel": "^3.1.1",
     "react-redux": "^7.2.6",
     "react-router-dom": "^5.3.0",
     "react-scripts": "5.0.0",

+ 3 - 1
src/actions/ActionGoodFind.js

@@ -5,7 +5,9 @@ export const actionGoodFindOne = (_id) =>
     actionPromise('goodFindOne', gql(`query goodFindOne($q :String){
             GoodFindOne(query:  $q){
                 _id name price createdAt description images{
-                    _id url
+                    _id url originalFileName
+                }, categories {
+                  _id name 
                 }
             }
     }`, { q: JSON.stringify([{ _id }]) }))

+ 32 - 0
src/components/SetCount.jsx

@@ -0,0 +1,32 @@
+import {Box, Button} from "@mui/material";
+import {useEffect, useState} from "react";
+
+export const SetCount = ({onCount}) => {
+    let [count, setCount] = useState(1)
+
+    useEffect(() => {
+        onCount(count)
+    }, [count, onCount])
+
+    return (
+        <Box sx={{display: 'flex', flexWrap: 'no-wrap'}}>
+            <Button
+                sx={{height: '55px', width: '50px', borderRadius: '0', color: '#000', borderColor: '#000', fontSize: '30px', fontWeight: '300'}}
+                variant="outlined"
+                color={"inherit"}
+                onClick={() => setCount(count === 1 ? count : count-1)}
+            >
+                -
+            </Button>
+            <input disabled value={count} style={{boxSizing: 'border-box', height: '55px', width: '60px', textAlign: 'center', border: '0', backgroundColor: '#eaeaea'}}/>
+            <Button
+                sx={{height: '55px', width: '50px', borderRadius: '0', color: '#000', borderColor: '#000', fontSize: '30px', fontWeight: '300'}}
+                variant="outlined"
+                color={"inherit"}
+                onClick={() => setCount(count === 100 ? count : count+1)}
+            >
+                +
+            </Button>
+        </Box>
+    )
+}

+ 2 - 0
src/pages/CatalogPage.jsx

@@ -361,3 +361,5 @@ const CatalogPage = ({category={}, actionRootCat}) => {
 const CCatalogPage = connect(state => ({category: state.category}), {actionRootCat: actionFullRootCats})(CatalogPage)
 
 export default CCatalogPage
+
+//TODO MOBILE VERSION

+ 200 - 13
src/pages/ProductPage.jsx

@@ -1,21 +1,205 @@
-import {useEffect} from "react";
+import {useEffect, useState} from "react";
 import {connect} from "react-redux";
-import {Typography} from "@mui/material";
+import {Box, Button, Container, Divider, Grid, Paper, Typography, useMediaQuery} from "@mui/material";
 import {actionGoodFindOne} from "../actions/ActionGoodFind";
 import Switch from "react-router-dom/es/Switch";
 import Route from "react-router-dom/es/Route";
 import Page404 from "./404Page";
 import Breadcrumb from "../components/Breadcrumbs";
+import {SetCount} from "../components/SetCount";
+import FavoriteBorderIcon from "@mui/icons-material/FavoriteBorder";
+import Link from "react-router-dom/es/Link";
+import {actionCardChange} from "../reducers/CartReducer";
+import {actionWishListAdd, actionWishListRemove} from "../reducers/WishListReducer";
+import FavoriteIcon from "@mui/icons-material/Favorite";
+import ArrowForwardIosIcon from '@mui/icons-material/ArrowForwardIos';
+import ArrowBackIosNewIcon from '@mui/icons-material/ArrowBackIosNew';
+import Carousel from 'react-material-ui-carousel'
+import {backURL} from "../actions/PathDB";
 
-const Goods = ({good:{_id, name, description, price, images}={}}) => {
+let defProduct = {
+    "_id": "5dc45d0b5df9d670df48cc4b",
+    "name": "Apple iPhone X 64GB Space Gray",
+    "price": 5000,
+    "images": [
+        {
+            "url": "images/00505f5f08ac113874318dee67975aa9",
+            "originalFileName": "image"
+        },
+        {
+            "url": "images/00505f5f08ac113874318dee67975aa9",
+            "originalFileName": "image"
+        },
+        {
+            "url": "images/00505f5f08ac113874318dee67975aa9",
+            "originalFileName": "image"
+        }
+    ]
+}
+
+const timeCalc = (createdAt) => {
+    let formattedTime = 0;
+    let date = new Date(+createdAt);
+    let year = date.getFullYear();
+    let month = "0" + date.getMonth();
+    let day = "0" + date.getDate();
+    let hours = "0" + date.getHours();
+    let minutes = "0" + date.getMinutes();
+    let seconds = "0" + date.getSeconds();
+    formattedTime = day.substr(-2) + '.' + month.substr(-2) + '.' + year +
+        ' ' + hours.substr(-2) + ':' + minutes.substr(-2) + ':' + seconds.substr(-2);
+    return formattedTime;
+}
+
+const ImageItem = ({images: {url, originalFileName}}) => {
     return (
-        <>
-            <Typography>{_id}</Typography>
-            <Typography>{name}</Typography>
-            <Typography>{description}</Typography>
-            <Typography>{price}</Typography>
+        <img src={backURL + '/' + url} alt={originalFileName.split('.')[0]}/>
+    )
+}
+const CarouselItem = ({images}) => {
+    return (
+        <Carousel
+            navButtonsProps={{
+                style: {
+                    backgroundColor: 'transparent',
+                    color: '#000',
+                    borderRadius: 0
+                }
+            }}
+            NextIcon={<ArrowForwardIosIcon/>}
+            PrevIcon={<ArrowBackIosNewIcon/>}
+            fullHeightHover={true}
+        >
+            {
+                images.map((item, index) => <Box key={index} sx={{width: '100%', display: 'flex', justifyContent: 'center', height: '340px'}}><ImageItem key={item._id} images={item} /></Box>)
+            }
+        </Carousel>
+    )
+}
 
-        </>
+const ProductTitle = ({title}) => {
+    return (
+        <Typography
+            variant='h4'
+            fontFamily='sarif'
+            letterSpacing='4px'
+        >
+            {title || 'PRODUCT TITLE'}
+        </Typography>
+    )
+}
+const ProductPrice = ({price}) => {
+    return (
+        <Typography
+            variant='h5'
+            margin='30px 0'
+        >
+            ${price ? parseFloat(price).toFixed(2) : 0 }
+        </Typography>
+    )
+}
+const ProductDescription = ({description}) => {
+    return (
+        <Typography
+            fontSize='17px'
+            letterSpacing='1px'
+            lineHeight='1.7em'
+            color='#616161'
+            fontWeight='300'
+        >
+            {description || 'PRODUCT DESCRIPTION'}
+        </Typography>
+    )
+}
+const ProductTags = ({title, subtitle}) => {
+    return (
+        <Typography
+            variant='body2'
+            color='#616161'
+            fontWeight='300'
+            marginBottom='10px'
+        >
+            {title}: {Array.isArray(subtitle) ? subtitle.map((item, index) => <span key={index}>{item}{subtitle.length-1 !== index && ", " } </span>) : subtitle}
+        </Typography>
+    )
+}
+
+const AddToCart = ({good, addToCart}) => {
+    let [count, setCount] = useState(1)
+    return (
+        <Box width='100%' backgroundColor='#fff' padding='30px'>
+            <Grid container justifyContent='space-between'>
+                <Grid xs={5} item>
+                   <SetCount onCount={value => setCount(value)}/>
+                </Grid>
+                <Grid xs={5} item>
+                    <Button
+                        sx={{height: '55px', width: '100%', borderRadius: '0', color: '#000', borderColor: '#000', fontSize: '20px', fontWeight: '300'}}
+                        variant="outlined"
+                        color={"inherit"}
+                        onClick={() => addToCart(good, count)}
+                    >
+                        ADD TO CART
+                    </Button>
+                </Grid>
+            </Grid>
+        </Box>
+    )
+}
+const CAddToCart = connect(null, {addToCart: actionCardChange})(AddToCart)
+
+const AddToWishList = ({good={}, wishlist ,onAddToWishList, onWishListRemove}) => {
+    const flag = good?._id in wishlist
+    return (
+        <Button size="small"
+                color="inherit"
+                sx={{paddingLeft: '0', margin: '30px 0'}}
+                onClick={() => {flag ? onWishListRemove(good) : onAddToWishList(good)}}
+        >
+            <Typography
+                color='#000'
+                display='flex'
+                alignItems='center'
+                fontSize='13px'
+                fontWeight='600'
+                letterSpacing='2px'
+            >
+                {flag ?
+                    <><FavoriteIcon sx={{marginRight: '10px'}}/> REMOVE FROM WISHLIST</>:
+                    <><FavoriteBorderIcon sx={{marginRight: '10px'}}/> ADD TO WISHLIST</>
+                }
+            </Typography>
+        </Button>
+    )
+}
+const CAddToWishList = connect(state => ({wishlist: state.wishlist}), {onAddToWishList: actionWishListAdd, onWishListRemove: actionWishListRemove})(AddToWishList)
+
+const Goods = ({good:{_id, name, description, price, images, categories, createdAt}=defProduct}) => {
+    const matches = useMediaQuery('(max-width:768px)');
+
+    return (
+        <Grid container justifyContent='space-around' padding={matches ? "20px 0" : "50px 0"} >
+            <Grid xs={12} md={6} item padding='5px 70px 5px 10px'>
+                {Array.isArray(images) && images.length > 1 ? <CarouselItem images={images}/> : <Box sx={{width: '100%', display: 'flex', justifyContent: 'center', height: '340px'}}><ImageItem images={images[0]}/></Box>}
+                <Divider sx={{margin: '20px 0'}}/>
+                <ProductDescription description={description}/>
+            </Grid>
+            <Grid xs={12} md={6} item padding='5px 110px 5px 10px'>
+                <ProductTitle title={name}/>
+                <ProductPrice price={price}/>
+                <CAddToCart good={{_id, name, price, images}}/>
+                <CAddToWishList good={{_id, name, price, images}}/>
+                <Box>
+                    {_id && <ProductTags key={'SKU'} title={'SKU'} subtitle={_id}/>}
+                    {Array.isArray(categories) &&
+                        <ProductTags key={'CATEGORY'} title={'CATEGORY'} subtitle={categories.map(item => {
+                            return <Link key={item?._id} style={{color: "#000", textDecoration: 'none'}} to={`/catalog/category/${item?._id}`}>{item?.name}</Link>
+                         })}/>
+                    }
+                    {createdAt && <ProductTags key={'TIMEOFCREATION'} title={'TIME OF CREATION'} subtitle={timeCalc(createdAt)}/>}
+                </Box>
+            </Grid>
+        </Grid>
     )
 }
 const CGoods = connect(state => ({good: state.promise['goodFindOne']?.payload}))(Goods)
@@ -27,15 +211,17 @@ const BlockProduct = ({match:{params:{_id}}, getData}) => {
 
     return(
         <>
-            <Breadcrumb links={['good']}/>
-            <CGoods key={_id} />
+            <main style={{backgroundColor: "#f3f3f3"}}>
+                <Breadcrumb links={['good']}/>
+                <Container maxWidth="lg">
+                    <CGoods key={_id} />
+                </Container>
+            </main>
         </>
     )
 }
-
 const CBlockProduct = connect(null, {getData: actionGoodFindOne})(BlockProduct)
 
-
 const ProductPage = () => {
     return (
         <Switch>
@@ -47,3 +233,4 @@ const ProductPage = () => {
 
 export default ProductPage
 
+//TODO MOBILE VERSION

+ 2 - 2
src/reducers/CombineReducers.js

@@ -12,6 +12,6 @@ export const rootReducer = combineReducers({
     promise: PromiseReducer,
     cart: localStoredReducer(CartReducer, 'cart'),
     user: UserReducer,
-    category: CategoryReducer,
-    wishlist: localStoredReducer(WishListReducer, 'wishlist'),
+    category: localStoredReducer(CategoryReducer,'category'),
+    wishlist: localStoredReducer(WishListReducer, 'wishlist')
 })