瀏覽代碼

updated good edit in admin page

Alex 2 年之前
父節點
當前提交
d5b416b768

+ 43 - 0
package-lock.json

@@ -21,6 +21,7 @@
         "@testing-library/jest-dom": "^5.16.1",
         "@testing-library/react": "^12.1.2",
         "@testing-library/user-event": "^13.5.0",
+        "array-move": "^4.0.0",
         "google-maps-react": "^2.0.6",
         "node-sass": "^7.0.0",
         "prop-types": "^15.8.0",
@@ -31,6 +32,7 @@
         "react-redux": "^7.2.6",
         "react-router-dom": "^5.3.0",
         "react-scripts": "5.0.0",
+        "react-sortable-hoc": "^2.0.0",
         "react-swipeable-views": "^0.14.0",
         "redux": "^4.1.2",
         "redux-form": "^8.3.8",
@@ -5064,6 +5066,17 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/array-move": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/array-move/-/array-move-4.0.0.tgz",
+      "integrity": "sha512-+RY54S8OuVvg94THpneQvFRmqWdAHeqtMzgMW6JNurHxe8rsS07cHQdfGkXnTUXiBcyZ0j3SiDIxxj0RPiqCkQ==",
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/array-union": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
@@ -15328,6 +15341,21 @@
         }
       }
     },
+    "node_modules/react-sortable-hoc": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/react-sortable-hoc/-/react-sortable-hoc-2.0.0.tgz",
+      "integrity": "sha512-JZUw7hBsAHXK7PTyErJyI7SopSBFRcFHDjWW5SWjcugY0i6iH7f+eJkY8cJmGMlZ1C9xz1J3Vjz0plFpavVeRg==",
+      "dependencies": {
+        "@babel/runtime": "^7.2.0",
+        "invariant": "^2.2.4",
+        "prop-types": "^15.5.7"
+      },
+      "peerDependencies": {
+        "prop-types": "^15.5.7",
+        "react": "^16.3.0 || ^17.0.0",
+        "react-dom": "^16.3.0 || ^17.0.0"
+      }
+    },
     "node_modules/react-swipeable-views": {
       "version": "0.14.0",
       "resolved": "https://registry.npmjs.org/react-swipeable-views/-/react-swipeable-views-0.14.0.tgz",
@@ -22398,6 +22426,11 @@
         "is-string": "^1.0.7"
       }
     },
+    "array-move": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/array-move/-/array-move-4.0.0.tgz",
+      "integrity": "sha512-+RY54S8OuVvg94THpneQvFRmqWdAHeqtMzgMW6JNurHxe8rsS07cHQdfGkXnTUXiBcyZ0j3SiDIxxj0RPiqCkQ=="
+    },
     "array-union": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
@@ -29800,6 +29833,16 @@
         "workbox-webpack-plugin": "^6.4.1"
       }
     },
+    "react-sortable-hoc": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/react-sortable-hoc/-/react-sortable-hoc-2.0.0.tgz",
+      "integrity": "sha512-JZUw7hBsAHXK7PTyErJyI7SopSBFRcFHDjWW5SWjcugY0i6iH7f+eJkY8cJmGMlZ1C9xz1J3Vjz0plFpavVeRg==",
+      "requires": {
+        "@babel/runtime": "^7.2.0",
+        "invariant": "^2.2.4",
+        "prop-types": "^15.5.7"
+      }
+    },
     "react-swipeable-views": {
       "version": "0.14.0",
       "resolved": "https://registry.npmjs.org/react-swipeable-views/-/react-swipeable-views-0.14.0.tgz",

+ 2 - 0
package.json

@@ -16,6 +16,7 @@
     "@testing-library/jest-dom": "^5.16.1",
     "@testing-library/react": "^12.1.2",
     "@testing-library/user-event": "^13.5.0",
+    "array-move": "^4.0.0",
     "google-maps-react": "^2.0.6",
     "node-sass": "^7.0.0",
     "prop-types": "^15.8.0",
@@ -26,6 +27,7 @@
     "react-redux": "^7.2.6",
     "react-router-dom": "^5.3.0",
     "react-scripts": "5.0.0",
+    "react-sortable-hoc": "^2.0.0",
     "react-swipeable-views": "^0.14.0",
     "redux": "^4.1.2",
     "redux-form": "^8.3.8",

+ 1 - 1
src/App.js

@@ -21,7 +21,7 @@ import SearchPage from "./pages/SearchPage";
 import MyOrdersPage from "./pages/MyOrdersPage";
 import CartPage from "./pages/CartPage";
 import {CPRoute} from "./components/CPRoute";
-import AdminPage from "./pages/AdminPage";
+import AdminPage from "./pages/AdminPage/AdminPage";
 
 const history = createHistory();
 

+ 48 - 3
src/actions/ActionCategory.js

@@ -2,6 +2,7 @@ import {actionPromise} from "../reducers/PromiseReducer";
 import {gql} from "./PathDB";
 import {actionCategoryChange, actionCategoryCreate} from "../reducers/CategoryReducer";
 
+//CategoryFind
 export const actionRootCats = () => {
     return actionPromise('rootCats', gql(`query rootCats{
           CategoryFind(query: "[{\\"parent\\": null}]"){
@@ -19,7 +20,6 @@ export const actionRootCats = () => {
         }`)
     )
 }
-
 export const actionFullRootCats = () =>
     async dispatch => {
         let value = await dispatch(actionRootCats())
@@ -28,8 +28,8 @@ export const actionFullRootCats = () =>
         }
     }
 
+//CategoryFindOne
 const actionCatById = (_id) => {
-    console.log(JSON.stringify([{_id}]))
     return actionPromise('catById', gql(`query catById($q: String){
             CategoryFindOne(query: $q){
                 _id goods {
@@ -40,7 +40,6 @@ const actionCatById = (_id) => {
             }
         }`, {q: JSON.stringify([{_id}])}))
 }
-
 export const actionFullCatById = (_id) =>
     async dispatch => {
         let value = await dispatch(actionCatById(_id))
@@ -48,3 +47,49 @@ export const actionFullCatById = (_id) =>
             dispatch(actionCategoryChange(value))
         }
     }
+
+//CategoryCount
+export const actionCategoryCount = () => {
+    return actionPromise('categoryCount', gql(`query categoryCount{
+            CategoryCount(query: "[{}]")
+          }`
+        )
+    )
+}
+
+//CategoryUpsert
+export const actionCategoryUpsert = (category) => {
+    const mainTitleCategory = category[0]?.name || 'No name';
+    const mainGoodsCategory = []
+    if (category[0]?.goods && category[0]?.goods?.length > 0){
+        category[0].goods.forEach(item => {
+            mainGoodsCategory.push(...item)
+        })
+    }
+
+    console.log(mainTitleCategory, mainGoodsCategory)
+    return actionPromise('categoryUpsert', gql(`
+                mutation categoryUpsert($name: String!){
+                CategoryUpsert(category: {name: $name}) {
+                    _id
+                    createdAt
+                    name
+                }
+            }`,{name: mainTitleCategory}
+        )
+    )
+}
+
+//CategoryDelete
+// export const actionCategoryDelete = (_id, name) => {
+//     return actionPromise('categoryDelete', gql(`
+//                 mutation categoryDelete($q: CategoryInput){
+//                 CategoryDelete(category: $q) {
+//                     _id
+//                     createdAt
+//                     name
+//                 }
+//             }`, {q: {_id: _id, name: name}}
+//         )
+//     )
+// }

+ 14 - 0
src/actions/ActionCreateGood.js

@@ -0,0 +1,14 @@
+import {actionPromise} from "../reducers/PromiseReducer";
+import {gql} from "./PathDB";
+
+export const actionGoodUpsert = (good) => {
+    return actionPromise('goodUpsert', gql(`mutation goodUpsert($good: GoodInput){
+            GoodUpsert(good: $good){
+                 _id
+            }
+        }`,
+        {
+            "good": {...good}
+        })
+    )
+}

+ 0 - 19
src/actions/ActionDashboard.js

@@ -1,19 +0,0 @@
-import {actionPromise} from "../reducers/PromiseReducer";
-import {gql} from "./PathDB";
-
-export const actionGetAllUser = (count=100) => {
-    console.log(`[{},${JSON.stringify({skip: [count], limit: [100]})}]`)
-    return actionPromise('allUsers', gql(`query allUsers($q: String){
-            UserFind(query: $q) {
-                _id
-                createdAt
-                login
-                nick 
-                acl 
-                avatar{
-                  _id url
-                }
-            }
-        }`), {q: `[{},${JSON.stringify({skip: [count], limit: [100]})}]`}
-    )
-}

+ 22 - 0
src/actions/ActionGoodFind.js

@@ -19,6 +19,8 @@ export const actionGoodFind = (text) =>
             GoodFind(query: $query){
                 _id, name, description, price, images{
                     _id, url
+                }, categories {
+                    _id, name
                 }
             }
         }`, {query: JSON.stringify([
@@ -39,3 +41,23 @@ export const actionFullGoodFind = (text) =>
             dispatch(actionSearchResult(value))
         }
     }
+
+export const actionAllGoodFind = () => {
+    return actionPromise('goodAllFind', gql(`
+        query goodAllFind($query: String){
+            GoodFind(query: $query){
+                _id name
+            }
+        }`, {query: JSON.stringify([{name: {$ne: null}}])}
+        )
+    )
+}
+
+//GoodCount
+export const actionGoodCount = () => {
+    return actionPromise('goodCount', gql(`query goodCount{
+              GoodCount(query: "[{}]")
+            }`
+        )
+    )
+}

+ 0 - 1
src/actions/ActionLogin.js

@@ -1,5 +1,4 @@
 import {actionFullUserFindOne} from "./ActionUserFind";
-
 const {actionAuthLogin} = require("../reducers/AuthReducer");
 const {actionPromise} = require("../reducers/PromiseReducer");
 const {gql} = require("./PathDB");

+ 1 - 0
src/actions/ActionOrderFind.js

@@ -24,3 +24,4 @@ export const actionFullOrderFind = () =>
             dispatch(actionMyOrder(value))
         }
     }
+

+ 9 - 4
src/actions/ActionUploadFile.js

@@ -2,14 +2,14 @@ import {actionPromise} from "../reducers/PromiseReducer";
 import {backURL, gql} from "./PathDB";
 import {actionFullUserFindOne} from "./ActionUserFind";
 
-const actionUploadFile = file => {
+export const actionUploadFile = file => {
     let fd = new FormData()
-    fd.append('photo',file)
+    fd.append('photo', file)
     return actionPromise('uploadFile', fetch(`${backURL}/upload`, {
         method: "POST",
         headers: localStorage.authToken ? {Authorization: 'Bearer ' + localStorage.authToken} : {},
         body: fd
-    }).then(res => res.json(), err => console.log(err)))
+    }).then(res => res.json()).catch(err => console.log(err)))
 }
 
 export const actionSetAvatar = file =>
@@ -32,7 +32,6 @@ export const actionSetAvatar = file =>
          }
      }
 
-
 export const actionSetLogin = login =>
     async (dispatch, getState) => {
         let value = await dispatch(actionPromise('setNewLogin', gql(`mutation setNewLogin($myid: String, $login: String){
@@ -68,3 +67,9 @@ export const actionSetPassword = password =>
             await dispatch(actionFullUserFindOne(getState().user._id))
         }
     }
+
+//     mutation req2($user: UserInput){
+//     UserUpsert(user:$user){
+//         _id
+//     }
+// }

+ 24 - 1
src/actions/ActionUserFind.js

@@ -2,6 +2,7 @@ import {actionUserCreate} from "../reducers/UserReducer";
 const {actionPromise} = require("../reducers/PromiseReducer");
 const {gql} = require("./PathDB");
 
+//UserFindOne
 export const actionUserFindOne = (_id) => {
     return actionPromise('userfindone', gql(`query userfindone($q: String){
       UserFindOne(query: $q){
@@ -11,7 +12,6 @@ export const actionUserFindOne = (_id) => {
         }
       }`,  {q: JSON.stringify([{_id}])}))
 }
-
 export const actionFullUserFindOne = (_id) =>
     async dispatch => {
         let value = await dispatch(actionUserFindOne(_id))
@@ -19,3 +19,26 @@ export const actionFullUserFindOne = (_id) =>
             dispatch(actionUserCreate(value))
         }
     }
+
+//UserFind
+export const actionUserFind = (count=0, value='login', sort=-1) => {
+    return actionPromise('allUsers', gql(`query allUsers($query: String!){
+          UserFind(query: $query){
+            _id login createdAt nick acl avatar 
+             {_id, url}
+           }
+        }`,
+            {
+                query: JSON.stringify([{login: {$ne: null}}, { sort: [{ [value]: sort }], skip: [count || 0], limit: [100] }]),
+            }
+        )
+    )
+}
+
+//UserCount
+export const actionUserCount = () => {
+    return actionPromise('usersCount', gql(`query usersCount{
+            UserCount(query: "[{}]")
+        }`)
+    )
+}

+ 47 - 26
src/pages/AdminPage.jsx

@@ -1,5 +1,15 @@
-import {Button, Container, useMediaQuery} from "@mui/material";
-import Breadcrumb from "../components/Breadcrumbs";
+import {
+    Avatar,
+    BottomNavigationAction,
+    Button, Card, CardContent, CardHeader, Checkbox, CircularProgress, Collapse,
+    Container, Divider,
+    FormControl,
+    Grid,
+    InputLabel, MenuItem, Pagination, Select, Switch,
+    TextField,
+    useMediaQuery
+} from "@mui/material";
+import Breadcrumb from "../../components/Breadcrumbs";
 import PropTypes from 'prop-types';
 import SwipeableViews from 'react-swipeable-views';
 import { useTheme } from '@mui/material/styles';
@@ -11,12 +21,20 @@ import Box from '@mui/material/Box';
 import {useState} from "react";
 import PersonIcon from '@mui/icons-material/Person';
 import CategoryIcon from '@mui/icons-material/Category';
-import HistoryIcon from '@mui/icons-material/History';
-import {connect} from "react-redux";
-import {actionGetAllUser} from "../actions/ActionDashboard";
+import AutoAwesomeIcon from '@mui/icons-material/AutoAwesome';
+import BottomNavigation from '@mui/material/BottomNavigation';
+import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline';
+import EditIcon from '@mui/icons-material/Edit';
+import {CategoryAside} from "../CatalogPage";
+import {CFindGoodEdit, CGoodEdit, CSearchPage, FindGoodEdit} from "./GoodTab";
+import MyOrdersPage from "../MyOrdersPage";
+import {Route} from "react-router-dom";
 
-const defaultTabs = [{icon: PersonIcon, text: 'clients'}, {icon: HistoryIcon, text: 'orders'}, {icon: CategoryIcon, text: 'categories'}]
+const defaultTabs = [{icon: PersonIcon, text: 'clients'}, {icon: CategoryIcon, text: 'categories'}, {icon: AutoAwesomeIcon, text: 'products'}]
 
+const IconHeader = ({Icon}) => {
+    return <Icon style={{marginRight: '10px'}} />
+}
 function TabPanel(props) {
     const { children, value, index, ...other } = props;
 
@@ -48,25 +66,30 @@ function a11yProps(index) {
     };
 }
 
-const IconHeader = ({Icon}) => {
-    return <Icon/>
-}
-const Clients = ({users={}, getAllClients}) => {
-    // if (!users?.payload) getAllClients()
+
+const SelectBlock = ({Block, FindBlock}) => {
+    const [value, setValue] = useState('create');
     return (
         <>
-            <Button onClick={() => {getAllClients()}}>click</Button>
-            {users?.payload && Object.entries(users.payload).length > 0 &&
-                Object.values(users.payload).map(item => {
-                    return <Typography>
-                        {item.login}
-                    </Typography>
-                })
+            <Box sx={{width: '100%', display:'flex', justifyContent: 'center', alignItems: 'center', marginBottom: '20px'}}>
+                <BottomNavigation
+                    showLabels
+                    sx={{width: '100%'}}
+                    value={value}
+                    onChange={(event, newValue) => {
+                        setValue(newValue);
+                    }}
+                >
+                    <BottomNavigationAction value={'create'} label="Create" icon={<AddCircleOutlineIcon />} />
+                    <BottomNavigationAction value={'edit'} label="Edit" icon={<EditIcon />} />
+                </BottomNavigation>
+            </Box>
+            {value === 'create' ?
+                <Block variant={value}/> : <FindBlock variant={value}/>
             }
         </>
     )
 }
-const CClients = connect(state => ({users: state.promise?.allUsers}), {getAllClients: actionGetAllUser})(Clients)
 
 const FullWidthTabs = () => {
     const theme = useTheme();
@@ -75,7 +98,6 @@ const FullWidthTabs = () => {
     const handleChange = (event, newValue) => {
         setValue(newValue);
     };
-
     const handleChangeIndex = (index) => {
         setValue(index);
     };
@@ -93,8 +115,8 @@ const FullWidthTabs = () => {
                     aria-label="full width tabs example"
                 >
                     {defaultTabs.map((item, index) =>
-                        <Tab key={index} sx={{borderBottom: '1px solid #dedede'}} label={<Box display='flex' alignItems='center'><IconHeader Icon={item.icon}/><Typography marginLeft='20px'>{item.text}</Typography></Box>} {...a11yProps(index)} />)
-                    }
+                        <Tab key={index} icon={<IconHeader Icon={item.icon}/>} iconPosition="start" label={item.text} sx={{borderBottom: '1px solid #dedede'}} {...a11yProps(index)}/>
+                    )}
                 </Tabs>
             </AppBar>
             <SwipeableViews
@@ -103,19 +125,18 @@ const FullWidthTabs = () => {
                 onChangeIndex={handleChangeIndex}
             >
                 <TabPanel value={value} index={0} dir={theme.direction}>
-                    <CClients/>
+                    {/*<CClients/>*/}
                 </TabPanel>
                 <TabPanel value={value} index={1} dir={theme.direction}>
-                    Item Two
+                    {/*<SelectBlock Block={CCategoryEdit} FindBlock={CFindGoodEdit}/>*/}
                 </TabPanel>
                 <TabPanel value={value} index={2} dir={theme.direction}>
-                    Item Three
+                    <SelectBlock Block={CGoodEdit} FindBlock={CFindGoodEdit}/>
                 </TabPanel>
             </SwipeableViews>
         </Box>
     );
 }
-
 const AdminPage = () => {
     const matches = useMediaQuery('(max-width:768px)')
     return(

+ 169 - 0
src/pages/AdminPage/CateforyTab.jsx

@@ -0,0 +1,169 @@
+import {useEffect, useState} from "react";
+import {Button, Checkbox, Grid, Switch, TextField} from "@mui/material";
+import Autocomplete from "@mui/material/Autocomplete";
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+import {SetCount} from "../../components/SetCount";
+import {connect} from "react-redux";
+import {actionCategoryCount, actionCategoryUpsert, actionFullRootCats} from "../../actions/ActionCategory";
+import {actionAllGoodFind} from "../../actions/ActionGoodFind";
+
+const InputCategory = ({goods, setArray, countSubCat}) => {
+    const [name, setName] = useState('');
+    const [products, setProducts] = useState([]);
+    const [addSub, setAddSub] = useState(false);
+    const [subArray, setSubArray] = useState([]);
+
+    const [checked, setChecked] = useState(false);
+    const handleChange = (event) => {
+        setChecked(event.target.checked);
+        if (!checked){
+            setArray([{"name": name, "goods": products, "subcategory": subArray}])
+        }
+    };
+
+    return (
+        <>
+            <Grid container justifyContent='space-between'>
+                <Grid item xs={5}>
+                    <TextField fullWidth id="filled-basic" label="Title category" variant="standard" value={name} onChange={e => {setName(e.target.value); setChecked(false)}}/>
+                </Grid>
+                <Grid item xs={5}>
+                    {goods?.payload &&
+                        <Autocomplete
+                            multiple
+                            id="tags-standard"
+                            options={goods.payload}
+                            onChange={(event, newValue) => {
+                                setProducts([newValue]);
+                                setChecked(false)
+                            }}
+                            getOptionLabel={(option) => option?.name || 'no name'}
+                            key={option => option?.id}
+                            renderInput={(params) => (
+                                <TextField
+                                    {...params}
+                                    variant="standard"
+                                    label="Select goods"
+                                    placeholder="goods"
+                                />
+                            )}
+                        />
+                    }
+                </Grid>
+                <Grid item xs={1} display='flex' justifyContent='center' alignItems='flex-end'>
+                    <Checkbox
+                        checked={checked}
+                        onChange={handleChange}
+                        inputProps={{ 'aria-label': 'controlled' }}
+                    />
+                </Grid>
+            </Grid>
+            <Grid container justifyContent='space-between' marginTop='30px' marginBottom='10px'>
+                <Grid item xs={5.5}>
+                    {countSubCat < 2 &&
+                        <Box display='flex' alignItems='center'>
+                            <Typography color='#616161'>Add subcategories</Typography>
+                            <Switch onChange={() => {setAddSub(!addSub); setChecked(false)}}/>
+                        </Box>
+                    }
+                </Grid>
+            </Grid>
+            {addSub && <AddCategory goods={goods} setArray={value => setSubArray(value)} addCategory={true} countSubCat={countSubCat+1}/>}
+        </>
+    )
+}
+const AddCategory = ({goods, setArray, addCategory, countSubCat}) => {
+    const [name, setName] = useState('');
+    const [products, setProducts] = useState([]);
+    const [addSub, setAddSub] = useState(false);
+    const [subArray, setSubArray] = useState([]);
+    const [addCat, setAddCat] = useState(false);
+    const [catCount, setCatCount] = useState(0);
+    const [subCat, setSubCat] = useState([]);
+
+    useEffect(() => {
+        setArray([{"name": name, "goods": products, "subcategory": subArray}, {...subCat}])
+    }, [name, products, subArray, subCat])
+    console.log(subCat)
+
+    return (
+        <Box sx={{border: '1px dashed #616161', borderRadius: '20px', padding: '20px'}}>
+            <Grid container justifyContent='space-between'>
+                <Grid item xs={5.5}>
+                    <TextField fullWidth id="filled-basic" label="Title category" variant="standard" value={name} onChange={e => setName(e.target.value)}/>
+                </Grid>
+                <Grid item xs={5.5}>
+                    {goods?.payload &&
+                        <Autocomplete
+                            multiple
+                            id="tags-standard"
+                            options={goods.payload}
+                            onChange={(event, newValue) => {
+                                setProducts([newValue]);
+                            }}
+                            getOptionLabel={(option) => option?.name || 'no name'}
+                            key={option => option?.id}
+                            renderInput={(params) => (
+                                <TextField
+                                    {...params}
+                                    variant="standard"
+                                    label="Select goods"
+                                    placeholder="goods"
+                                />
+                            )}
+                        />
+                    }
+                </Grid>
+            </Grid>
+            <Grid container justifyContent='space-between' marginTop='30px' marginBottom='10px'>
+                <Grid item xs={5.5}>
+                    {countSubCat < 2  &&
+                        <Box display='flex' alignItems='center'>
+                            <Typography color='#616161'>Add subcategories</Typography>
+                            <Switch onChange={() => setAddSub(!addSub)}/>
+                        </Box>
+                    }
+                </Grid>
+                <Grid item xs={5.5} display='flex' justifyContent='space-between' alignItems='center'>
+                    {addCategory &&
+                        <Box display='flex' alignItems='center'>
+                            <Typography color='#616161'>Add categories</Typography>
+                            <Switch onChange={() => {setAddCat(!addCat); setCatCount(0)}}/>
+                        </Box>
+                    }
+                    {addCat && <SetCount defaultValue={1} width={40} height={40} onCount={value => setCatCount(value)}/>}
+                </Grid>
+            </Grid>
+            {addSub && <AddCategory goods={goods} setArray={value => setSubArray(value)} addCategory={true} countSubCat={countSubCat+1}/>}
+            {catCount >= 1 && new Array(catCount).fill(0).map(item => {
+                return <InputCategory goods={goods} setArray={value => setSubCat([...subCat, value])} countSubCat={countSubCat}/>
+            })
+            }
+        </Box>
+    )
+}
+const CategoryEdit = ({category, categoryCount, goods, variant='create', actionRootCat, getCountCategory, getGoodFind, onCreateCategory}) => {
+    const [array, setArray] = useState([])
+
+    useEffect(() => {
+        if(!goods) getGoodFind()
+        if(!category) actionRootCat()
+        if(!categoryCount) getCountCategory()
+    }, [actionRootCat, category, categoryCount, getCountCategory, getGoodFind, goods])
+
+    return(
+        <>
+            <Typography variant='h6' letterSpacing='2px' marginBottom='20px'>Total category: {categoryCount?.payload || 0}</Typography>
+            <AddCategory goods={goods} setArray={value => setArray(value)} countSubCat={0}/>
+            <Grid container justifyContent='center' marginTop='30px'>
+                <Grid item xs={4}>
+                    <Button disabled={array.length === 0} fullWidth variant="outlined" onClick={() => onCreateCategory(array)}>
+                        Save
+                    </Button>
+                </Grid>
+            </Grid>
+        </>
+    )
+}
+export const CCategoryEdit = connect(state => ({category: state.category, categoryCount: state.promise['categoryCount'], goods: state.promise['goodAllFind'] }), {actionRootCat: actionFullRootCats, getCountCategory: actionCategoryCount, getGoodFind: actionAllGoodFind, onCreateCategory: actionCategoryUpsert})(CategoryEdit)

+ 160 - 0
src/pages/AdminPage/ClientsTab.jsx

@@ -0,0 +1,160 @@
+import Typography from "@mui/material/Typography";
+import {useEffect, useState} from "react";
+import {
+    Avatar,
+    Card,
+    CardContent,
+    CardHeader,
+    CircularProgress,
+    Collapse, Divider,
+    FormControl,
+    MenuItem, Pagination,
+    Select
+} from "@mui/material";
+import Box from "@mui/material/Box";
+import {backURL} from "../../actions/PathDB";
+import userDefault from "../../img/header/userDefault.png";
+import {timeCalc} from "../ProductPage";
+import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
+import {connect} from "react-redux";
+import {actionUserCount, actionUserFind} from "../../actions/ActionUserFind";
+
+const ClientsCart = ({_id, login, nick, avatar, createdAt, acl}) => {
+    const ItemAccordion = ({text, size='h6'}) => {
+        return (
+            <Typography
+                variant={size}
+                color='#616161'
+                letterSpacing='1px'
+            >
+                {text}
+            </Typography>
+        )
+    }
+    const [expanded, setExpanded] = useState(false);
+    const handleExpandClick = () => {
+        setExpanded(!expanded);
+    };
+    return (
+        <Card sx={{boxShadow: 'none', border: '1px solid #616161', marginBottom: '20px'}}>
+            <Box display='flex' justifyContent='space-between' alignItems='center' padding='0 20px 0 10px'
+                 style={{cursor:'pointer'}}
+                 onClick={handleExpandClick}
+            >
+                <CardHeader
+                    avatar={
+                        avatar ?
+                            <Avatar alt="User" src={avatar?.url && backURL + '/' + avatar.url}/> :
+                            <Avatar alt="User" src={userDefault}/>
+                    }
+                    title={`Login: ${login || 'login'}  ${nick ? '| Nick: ' + nick : ''} ${(acl && Array.isArray(acl) && acl.length > 1) ? '| Status: ' + acl.slice(1, acl.length).toString() : ''}`}
+                    subheader={timeCalc(+createdAt || 0)}
+                />
+                <ExpandMoreIcon />
+            </Box>
+            <Collapse in={expanded} timeout="auto" unmountOnExit>
+                <CardContent>
+                    <ItemAccordion text={`Login: ${login || 'login'}`}/>
+                    <ItemAccordion size={'body1'} text={`${nick ? 'Nick: ' + nick : ''}`}/>
+                    <ItemAccordion size={'body1'} text={`${(acl && Array.isArray(acl) && acl.length > 1) ? 'Status: ' + acl.slice(1, acl.length).toString() : ''}`}/>
+                    <ItemAccordion size={'body1'} text={'Created at: '+timeCalc(+createdAt || 0)}/>
+                </CardContent>
+            </Collapse>
+        </Card>
+    )
+}
+const Clients = ({usersArr, usersCount, getAllClients, getCountUser}) => {
+    const itemsPerPage = 100
+    const [page, setPage] = useState(1)
+    const [sortValue, setSortValue] = useState('login')
+    const [sortVector, setSortVector] = useState(1)
+    const [sortSelect, setSortSelect] = useState(0)
+
+    useEffect(() => {
+        if (!usersArr && page === 1) getAllClients()
+        if (!usersCount) getCountUser()
+        else {
+            setCount(Math.ceil(+usersCount?.payload / itemsPerPage))
+        }
+    }, [getAllClients, getCountUser, page, sortValue, sortVector, usersArr, usersCount])
+
+    const [count, setCount] = useState(1)
+    const handleChange = (event, value) => {
+        setPage(value);
+        getAllClients(itemsPerPage * value, sortValue, sortVector);
+    }
+    const handleChangeSelect = (event) => {
+        setSortSelect(event.target.value);
+        if (event.target.value === 0){
+            setSortValue('login')
+            setSortVector(1)
+            getAllClients(itemsPerPage*page, sortValue, sortVector)
+        }
+        else if (event.target.value === 1){
+            setSortValue('login')
+            setSortVector(-1)
+            getAllClients(itemsPerPage*page, sortValue, sortVector)
+        }
+        else if (event.target.value === 2){
+            setSortValue('login')
+            setSortVector(1)
+            getAllClients(itemsPerPage*page, sortValue, sortVector)
+        }
+        else if (event.target.value === 3){
+            setSortValue('createdAt')
+            setSortVector(1)
+            getAllClients(itemsPerPage*page, sortValue, sortVector)
+        }
+        else if (event.target.value === 4){
+            setSortValue('createdAt')
+            setSortVector(-1)
+            getAllClients(itemsPerPage*page, sortValue, sortVector)
+        }
+    }
+
+    return (
+        <>
+            <Box marginBottom='20px' width='100%' display='flex' justifyContent='space-between' alignItems='center'>
+                {usersCount?.payload  && <Typography variant='h6' letterSpacing='2px'>Total clients: {usersCount.payload}</Typography>}
+                <FormControl variant="standard">
+                    <Select
+                        labelId="demo-simple-select-label"
+                        id="demo-simple-select"
+                        value={sortSelect}
+                        label="Sort"
+                        onChange={handleChangeSelect}
+                        sx={{textTransform: 'uppercase', color: '#616161'}}
+                    >
+                        <MenuItem value={0}>Default sort</MenuItem>
+                        <MenuItem value={1}>Sort by login: ascending</MenuItem>
+                        <MenuItem value={2}>Sort by login: descending</MenuItem>
+                        <MenuItem value={3}>Sort by created at: ascending</MenuItem>
+                        <MenuItem value={4}>Sort by created at: descending</MenuItem>
+                    </Select>
+                </FormControl>
+            </Box>
+            {!usersArr || !usersArr?.payload ?
+                <Box sx={{height: '100%', width: '100%', display: 'flex', justifyContent:'center', alignItems:'center'}}><CircularProgress color="inherit"/></Box>:
+                Array.isArray(usersArr.payload) && usersArr.payload.map(item => {
+                    return <ClientsCart key={item?._id} _id={item?._id || ''} login={item?.login || 'not found'} nick={item?.nick || ''} createdAt={item?.createdAt || ''} avatar={item?.avatar} acl={item?.acl}/>
+                })
+            }
+            <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>
+        </>
+    )
+}
+export const CClients = connect(state => ({usersArr: state.promise['allUsers'], usersCount: state.promise['usersCount']}), {getAllClients: actionUserFind, getCountUser: actionUserCount})(Clients)

+ 317 - 0
src/pages/AdminPage/GoodTab.jsx

@@ -0,0 +1,317 @@
+import {useEffect, useState} from "react";
+import {useDropzone} from "react-dropzone";
+import {sortableContainer, sortableElement} from "react-sortable-hoc";
+import {arrayMoveImmutable} from "array-move";
+import Box from "@mui/material/Box";
+import Typography from "@mui/material/Typography";
+import {
+    Button,
+    CircularProgress, Container,
+    FormControl,
+    Grid, IconButton,
+    InputAdornment,
+    InputLabel,
+    MenuItem,
+    Select,
+    TextField
+} from "@mui/material";
+import {connect} from "react-redux";
+import {actionFullRootCats} from "../../actions/ActionCategory";
+import {actionGoodUpsert} from "../../actions/ActionCreateGood";
+import Autocomplete from "@mui/material/Autocomplete";
+import {actionFullGoodFind, actionGoodCount} from "../../actions/ActionGoodFind";
+import {actionUploadFile} from "../../actions/ActionUploadFile";
+import {backURL} from "../../actions/PathDB";
+import {actionClearPromise} from "../../reducers/PromiseReducer";
+import {Link} from "react-router-dom";
+import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline';
+import SearchIcon from "@material-ui/icons/Search";
+import imgNotFound from "../../img/catalog/imgNotFound.png";
+import {actionSearchRemove} from "../../reducers/SearchReducer";
+
+
+const GoodEdit = ({entity={images: [], categories: []}, onSave, onFileDrop, fileStatus, variant='create', categoryState, actionRootCat, goodCount, goods, actionClear, result}) => {
+    const [state, setState] = useState(entity)
+
+    const {getRootProps, getInputProps, isDragActive} = useDropzone({accept: 'image/*', onDrop: acceptedFiles => {
+            acceptedFiles.forEach(async file => {
+                await onFileDrop(file)
+            })
+        }})
+    const SortableItem = sortableElement(({value}) => {
+        return <div key={value?._id} style={{display: 'inline-flex', borderRadius: 2,border: '1px solid #eaeaea',marginBottom: 8, marginRight: 8, width: 200, height: 200, padding: 4, boxSizing: 'border-box'}}>
+            <div style={{display: 'flex', justifyContent: 'center', minWidth: 0, overflow: 'hidden'}}>
+                {value?.url ?
+                    <img src={backURL+ '/' + value?.url} style={{display: 'block', width: 'auto', height: '100%', objectFit: 'cover', objectPosition: 'center center'}} alt={value.name}/>
+                    :
+                    <Box sx={{ display: 'flex' }}>
+                        <CircularProgress />
+                    </Box>
+                }
+            </div>
+        </div>
+    });
+    const SortableContainer = sortableContainer(({children}) => {
+        return <aside style={{display:'flex', justifyContent: 'space-between', flexWrap: 'wrap'}}>
+            {children}
+        </aside>
+    })
+    const onSortEnd = ({oldIndex, newIndex}) => {
+        setState(({images}) => ({
+            ...state,
+            images: arrayMoveImmutable(images, oldIndex, newIndex),
+        }));
+    }
+
+    const handleClear = () => {
+        setState(entity)
+    }
+    const handleOnSave = () => {
+        let query = {...state}
+        state.images.length > 0 ? query.images = state.images.map(item => {return {'_id': item['_id']}}) : delete query.images
+        state.categories.length > 0 ? query.categories = state.categories.map(item => {return {'_id': item['_id'], 'name': item['name']}}) : delete query.categories
+        onSave(query)
+        goodCount()
+    }
+    const handleFullClear = () => {
+        setState(entity)
+        actionClear('goodUpsert')
+        actionClear('uploadFile')
+    }
+    useEffect(() => {
+        if(!categoryState || Object.entries(categoryState).length === 0) actionRootCat()
+        if(!goods) goodCount()
+        if(fileStatus?.status === 'RESOLVED'){
+            setState({...state, images: [...state.images, fileStatus?.payload]})
+        }
+    },[categoryState, goods, fileStatus])
+
+    return (
+        <>
+            {!result ?
+                <>
+                    <Typography variant='h6' letterSpacing='2px' marginBottom='20px'>Total products: {goods?.payload || 0}</Typography>
+                    <Box style={{minHeight: "200px", border: '1px dashed #616161', borderRadius: '20px', padding: '20px'}} {...getRootProps()}>
+                        <input {...getInputProps()} />
+                        {isDragActive ?
+                            <Typography variant='body1' textAlign='center' color='#616161'>Drop the file here ...</Typography> :
+                            <Typography variant='body1' textAlign='center' color='#616161' marginBottom='20px'>Drag 'n' drop image files here, or click to select file</Typography>
+                        }
+                        <SortableContainer axis="xy" onSortEnd={onSortEnd}>
+                            {state.images.length > 0 && state.images.map((value, index) => (
+                                <SortableItem key={`item-${value?._id}`} index={index} value={value} />
+                            ))}
+                        </SortableContainer>
+                    </Box>
+                    <Grid container justifyContent='space-between' marginTop='30px'>
+                        <Grid item xs={5.5}>
+                            <TextField fullWidth id="filled-basic" label="Title product" variant="standard" value={state?.name || ''} onChange={e => setState({...state, name: e.target.value})}/>
+                        </Grid>
+                        <Grid item xs={5.5}>
+                            {categoryState &&
+                                <Autocomplete
+                                    multiple
+                                    id="tags-standard"
+                                    options={Object.values(categoryState)}
+                                    onChange={(event, newValue) => {
+                                        setState({...state, categories: [...newValue]})
+                                    }}
+                                    getOptionLabel={(option) => state?.categories ? [...state.categories] : option?.name || 'no name'}
+                                    key={option => option?.id}
+                                    renderInput={(params) => (
+                                        <TextField
+                                            {...params}
+                                            variant="standard"
+                                            label="Select categories"
+                                            placeholder="categories"
+                                        />
+                                    )}
+                                />
+                            }
+                        </Grid>
+                    </Grid>
+                    <Grid container justifyContent='space-between' marginTop='30px'>
+                        <Grid item xs={5.5}>
+                            <TextField fullWidth
+                                       id='Price'
+                                       type='number'
+                                       label='Price'
+                                       variant='standard'
+                                       value={state?.price || ''}
+                                       onChange={e => setState({...state, price: parseFloat(e.target.value < 0 ? 0 : e.target.value)})}
+                            />
+                        </Grid>
+                        <Grid item xs={5.5}>
+                            <TextField fullWidth
+                                       id='filled-basic'
+                                       label='Description product'
+                                       variant='standard'
+                                       multiline
+                                       value={state?.description || ''}
+                                       onChange={e => setState({...state, description: e.target.value})}
+                            />
+                        </Grid>
+                    </Grid>
+                    <Grid container justifyContent='space-between' marginTop='30px'>
+                        <Grid item xs={5.5} display='flex' justifyContent='center'>
+                            <Button
+                                fullWidth
+                                onClick={handleClear}
+                                variant="outlined"
+                                color='warning'
+                            >
+                                Clear
+                            </Button>
+                        </Grid>
+                        <Grid item xs={5.5} display='flex' justifyContent='center'>
+                            <Button
+                                fullWidth
+                                variant="outlined"
+                                color='primary'
+                                onClick={handleOnSave}
+                            >
+                                Save
+                            </Button>
+                        </Grid>
+                    </Grid>
+                </> :
+                result?.payload?._id ?
+                    <>
+                        <Box display='flex' alignItems='center' flexDirection='column'>
+                            <Typography variant='h5' letterSpacing='2px' textAlign='center' color='#616161' marginBottom='20px'>Product successfully created!</Typography>
+                            <CheckCircleOutlineIcon sx={{marginBottom: '20px'}}/>
+                            <Link to={`/good/${result?.payload?._id}`} style={{color:'#616161', marginBottom:'20px'}}>
+                                <Typography variant='h5' letterSpacing='2px' textAlign='center' color='#616161'>View results</Typography>
+                            </Link>
+                            <Button variant='outlined' onClick={handleFullClear}>Add more</Button>
+                        </Box>
+                    </> :
+                    result?.error ?
+                        <Box display='flex' alignItems='center' flexDirection='column'>
+                            <Typography variant='h5' letterSpacing='2px' textAlign='center' color='#f00' marginBottom='20px'>Fatal error, try again!</Typography>
+                            <Button variant='outlined' onClick={handleFullClear}>Add more</Button>
+                        </Box>
+                        :
+                        <Box sx={{ display: 'flex' }}>
+                            <CircularProgress />
+                        </Box>
+            }
+        </>
+    )
+}
+export const CGoodEdit = connect(state => ({fileStatus: state.promise['uploadFile'], categoryState: state.category, goods: state.promise['goodCount'], result: state.promise['goodUpsert']}), {actionRootCat: actionFullRootCats, onSave: actionGoodUpsert, goodCount:  actionGoodCount, onFileDrop: actionUploadFile, actionClear: actionClearPromise})(GoodEdit)
+
+const ItemFound = ({item:{_id, name, price, images, description, categories}}) => {
+    let [state, setState] = useState(false)
+
+    return (
+        !state ?
+            <Button style={{textDecoration: 'none', display: 'flex', alignItems: 'center', marginBottom: '30px'}} onClick={() => setState(true)}>
+                <Box width='60px' height='60px' borderRadius='10px' overflow='hidden' marginRight='60px'
+                     position='relative'>
+                    <img style={{
+                        position: 'absolute',
+                        top: '0',
+                        left: '0',
+                        width: '100%',
+                        height: '100%',
+                        objectFit: 'cover'
+                    }} src={images && Array.isArray(images) && images[0]?.url ? backURL + '/' + images[0].url : imgNotFound}
+                         alt={name}/>
+                </Box>
+                <Box sx={{
+                    display: 'flex',
+                    flexDirection: 'column',
+                    justifyContent: 'space-between',
+                    alignItems: 'flex-start'
+                }}>
+                    <Typography
+                        color='#000'
+                        letterSpacing='1px'
+                        fontFamily='sarif'
+                        fontWeight='600'
+                        variant='h6'
+                    >
+                        {name}
+                    </Typography>
+                    <Typography
+                        letterSpacing='1px'
+                        variant='body1'
+                        fontWeight='300'
+                        color='#616161'
+                        margin='10px 0'
+                    >
+                        {description?.length > 60 ? 'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' : description}
+                    </Typography>
+                    <Typography
+                        color='#000'
+                        letterSpacing='1px'
+                        variant='body1'
+                        fontWeight='600'
+                    >
+                        ${parseFloat(price).toFixed(2)}
+                    </Typography>
+                </Box>
+            </Button>
+        :
+            <CGoodEdit entity={{_id, name, price, images, description, categories}}/>
+    )
+}
+const NotFound = () => {
+    return (
+        <Typography
+            textAlign='center'
+            color='#000'
+            letterSpacing='1px'
+            variant='body1'
+        >
+            No results found
+        </Typography>
+    )
+}
+const FindGoodEdit = ({searchResult, onSearch, onSearchRemove}) => {
+    const [value, setValue] = useState('')
+    const [click, setClick] = useState(false)
+
+    return (
+        <>
+            <Container maxWidth="sm">
+                <Typography
+                    variant='h5'
+                    fontFamily='sarif'
+                    letterSpacing='3px'
+                    marginBottom='30px'
+                    marginTop='30px'
+                    textAlign='center'
+                >
+                    WHICH ITEM TO EDIT?
+                </Typography>
+                <TextField
+                    color={'primary'}
+                    fullWidth
+                    variant="standard"
+                    value={value}
+                    placeholder="Start typing..."
+                    onChange={(event) => {setClick(false); setValue(event.target.value); onSearchRemove()}}
+                    InputProps={{
+                        sx: {padding: '10px', outline:'none', color: '#616161', fontWeight: '300', letterSpacing: '1px', marginBottom: '50px'},
+                        endAdornment: (
+                            <InputAdornment position="end">
+                                <IconButton onClick={() => {setClick(true); onSearchRemove(); onSearch(value)}}>
+                                    <SearchIcon />
+                                </IconButton>
+                            </InputAdornment>
+                        )
+                    }}
+                />
+                {(value !== '' && click) && (searchResult?.searchResult ?
+                        Object.values(searchResult.searchResult).length > 0  ?
+                            Object.values(searchResult.searchResult).map(item => <ItemFound item={item}/>) : <NotFound/> :
+                        <CircularProgress color="inherit"/>
+                )}
+            </Container>
+        </>
+    )
+}
+export const CFindGoodEdit = connect(state=>({searchResult: state.search}), {onSearch: actionFullGoodFind, onSearchRemove: actionSearchRemove})(FindGoodEdit)
+

+ 2 - 2
src/pages/CatalogPage.jsx

@@ -109,7 +109,7 @@ const GoodCard = ({good:{_id, name, description, price, images}={}, wishlist={},
                         <CardMedia sx={{marginBottom: '20px', marginTop: '20px'}}
                             component="img"
                             height="230"
-                            image={images[0].url ? `${backURL}/${images[0].url}` : imgNotFound}
+                            image={images && images[0]?.url ? `${backURL}/${images[0]?.url}` : imgNotFound}
                             alt="Good title image"
                         />
                         <CardContent sx={{display: 'flex', flexDirection: 'column', height: '200px', justifyContent: 'space-between'}}>
@@ -125,7 +125,7 @@ const GoodCard = ({good:{_id, name, description, price, images}={}, wishlist={},
                                {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 ?
+                                {description && description.length > 60 ?
                                     'Lorem ipsum dolor sit amet, consectetur adipisicing elit.' :
                                     description
                                 }

+ 2 - 3
src/pages/MyOrdersPage.jsx

@@ -53,10 +53,9 @@ const AccordionItem = ({data}) => {
                     {!status && <Box sx={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '200px'}}>
                         {data['orderGoods'] && data['orderGoods'].map((item, index, array) => {
                             if (index < 2) {
-                                {console.log(item.good.images[0].url)}
                                 return <Box minWidth='60px' maxWidth='60px' height='60px' borderRadius='10px' overflow='hidden' marginRight='20px'>
                                             <img style={{width: '100%', height: '100%', objectFit: 'cover'}}
-                                                 src={item.good.images && item.good.images[0].url ? backURL + '/' + item.good.images[0].url : imgNotFound}
+                                                 src={item?.good?.images && item.good.images[0].url ? backURL + '/' + item.good.images[0].url : imgNotFound}
                                                  alt={'image'}/>
                                         </Box>
                             }
@@ -121,7 +120,7 @@ const AccordionItem = ({data}) => {
                                     <Link style={{textDecoration: 'none', display: 'flex', alignItems: 'center', color: '#616161'}} to={`/good/${item?.good?._id}`}>
                                         <Box minWidth='60px' maxWidth='60px' height='60px' borderRadius='10px' overflow='hidden' marginRight='20px'>
                                             <img style={{width: '100%', height: '100%', objectFit: 'cover'}}
-                                                 src={item.good.images && item.good.images[0].url ? backURL + '/' + item.good.images[0].url : imgNotFound}
+                                                 src={item?.good?.images && item.good.images[0].url ? backURL + '/' + item.good.images[0].url : imgNotFound}
                                                  alt={'image'}/>
                                         </Box>
                                         <Typography

+ 3 - 2
src/pages/ProductPage.jsx

@@ -169,8 +169,9 @@ const Goods = ({good}) => {
             <Grid container justifyContent='space-around' padding={matches ? "20px 0" : "50px 0"}>
                 <Grid xs={12} md={6} item padding='5px 70px 5px 10px'>
                     {Array.isArray(good?.images) && good?.images.length > 1 ? <CarouselItem images={good?.images}/> :
-                        <Box sx={{width: '100%', display: 'flex', justifyContent: 'center', height: '340px'}}><ImageItem
-                            images={good?.images[0]}/></Box>}
+                        <Box sx={{width: '100%', display: 'flex', justifyContent: 'center', height: '340px'}}>
+                            <ImageItem images={Array.isArray(good?.images) && good?.images[0]}/>
+                        </Box>}
                     <Divider sx={{margin: '20px 0'}}/>
                     <ProductDescription description={good?.description}/>
                 </Grid>

+ 1 - 1
src/reducers/CombineReducers.js

@@ -14,7 +14,7 @@ export const rootReducer = combineReducers({
     promise: PromiseReducer,
     cart: localStoredReducer(CartReducer, 'cart'),
     user: UserReducer,
-    category: localStoredReducer(CategoryReducer,'category'),
+    category: CategoryReducer,
     wishlist: localStoredReducer(WishListReducer, 'wishlist'),
     search: SearchReducer,
     myorders: MyOrdersReducer