Vika 2 years ago
parent
commit
93b348f5fb
33 changed files with 734 additions and 29 deletions
  1. 153 0
      project/my-project/package-lock.json
  2. 1 0
      project/my-project/package.json
  3. 14 0
      project/my-project/src/App.css
  4. 15 0
      project/my-project/src/action/actionAddCategory.js
  5. 1 1
      project/my-project/src/action/actionCatById.js
  6. 20 0
      project/my-project/src/action/actionChangeCategName.js
  7. 23 0
      project/my-project/src/action/actionChangeOneGood.js
  8. 28 0
      project/my-project/src/action/actionSearchGood.js
  9. 2 1
      project/my-project/src/action/actionUploadFile.js
  10. 4 0
      project/my-project/src/action/index.js
  11. 22 0
      project/my-project/src/components/aaaaa.js
  12. 29 0
      project/my-project/src/components/addCategory.js
  13. 1 1
      project/my-project/src/components/cGoodCard.js
  14. 62 0
      project/my-project/src/components/cartChangeGood.js
  15. 84 0
      project/my-project/src/components/changeOfGood.js
  16. 9 3
      project/my-project/src/components/header.js
  17. 6 0
      project/my-project/src/components/index.js
  18. 44 0
      project/my-project/src/components/inputSearchGood.js
  19. 5 1
      project/my-project/src/components/inputUploadFile.js
  20. 5 4
      project/my-project/src/components/listOrders.js
  21. 45 0
      project/my-project/src/components/nameCategory.js
  22. 3 2
      project/my-project/src/components/signIn.js
  23. 26 0
      project/my-project/src/components/switchRoute.js
  24. 2 1
      project/my-project/src/pages/index.js
  25. 6 2
      project/my-project/src/pages/mainPage.js
  26. 35 0
      project/my-project/src/pages/pageAdmin.js
  27. 2 3
      project/my-project/src/pages/pageBasket.js
  28. 4 0
      project/my-project/src/reducer/cartReducer.js
  29. 14 1
      project/my-project/src/reducer/promiseReducer.js
  30. 2 1
      project/my-project/src/route/index.js
  31. 19 0
      project/my-project/src/route/privateRoute.js
  32. 2 2
      project/my-project/src/route/useRoute.js
  33. 46 6
      project/my-project/src/store/index.js

+ 153 - 0
project/my-project/package-lock.json

@@ -20,6 +20,7 @@
         "react-redux": "^7.2.6",
         "react-router-dom": "^5.3.0",
         "react-scripts": "5.0.0",
+        "redux-saga": "^1.1.3",
         "redux-thunk": "^2.4.1",
         "web-vitals": "^2.1.2"
       }
@@ -2764,6 +2765,53 @@
         "react": "^16.8.0 || ^17.0.0-rc.1"
       }
     },
+    "node_modules/@redux-saga/core": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.1.3.tgz",
+      "integrity": "sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg==",
+      "dependencies": {
+        "@babel/runtime": "^7.6.3",
+        "@redux-saga/deferred": "^1.1.2",
+        "@redux-saga/delay-p": "^1.1.2",
+        "@redux-saga/is": "^1.1.2",
+        "@redux-saga/symbols": "^1.1.2",
+        "@redux-saga/types": "^1.1.0",
+        "redux": "^4.0.4",
+        "typescript-tuple": "^2.2.1"
+      }
+    },
+    "node_modules/@redux-saga/deferred": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.1.2.tgz",
+      "integrity": "sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ=="
+    },
+    "node_modules/@redux-saga/delay-p": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.1.2.tgz",
+      "integrity": "sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g==",
+      "dependencies": {
+        "@redux-saga/symbols": "^1.1.2"
+      }
+    },
+    "node_modules/@redux-saga/is": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.2.tgz",
+      "integrity": "sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w==",
+      "dependencies": {
+        "@redux-saga/symbols": "^1.1.2",
+        "@redux-saga/types": "^1.1.0"
+      }
+    },
+    "node_modules/@redux-saga/symbols": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.2.tgz",
+      "integrity": "sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ=="
+    },
+    "node_modules/@redux-saga/types": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.1.0.tgz",
+      "integrity": "sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg=="
+    },
     "node_modules/@restart/hooks": {
       "version": "0.4.5",
       "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.5.tgz",
@@ -14434,6 +14482,14 @@
         "@babel/runtime": "^7.9.2"
       }
     },
+    "node_modules/redux-saga": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.1.3.tgz",
+      "integrity": "sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw==",
+      "dependencies": {
+        "@redux-saga/core": "^1.1.3"
+      }
+    },
     "node_modules/redux-thunk": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
@@ -16107,6 +16163,27 @@
         "node": ">=4.2.0"
       }
     },
+    "node_modules/typescript-compare": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz",
+      "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
+      "dependencies": {
+        "typescript-logic": "^0.0.0"
+      }
+    },
+    "node_modules/typescript-logic": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz",
+      "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q=="
+    },
+    "node_modules/typescript-tuple": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
+      "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
+      "dependencies": {
+        "typescript-compare": "^0.0.2"
+      }
+    },
     "node_modules/unbox-primitive": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
@@ -19129,6 +19206,53 @@
         "@babel/runtime": "^7.6.2"
       }
     },
+    "@redux-saga/core": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.1.3.tgz",
+      "integrity": "sha512-8tInBftak8TPzE6X13ABmEtRJGjtK17w7VUs7qV17S8hCO5S3+aUTWZ/DBsBJPdE8Z5jOPwYALyvofgq1Ws+kg==",
+      "requires": {
+        "@babel/runtime": "^7.6.3",
+        "@redux-saga/deferred": "^1.1.2",
+        "@redux-saga/delay-p": "^1.1.2",
+        "@redux-saga/is": "^1.1.2",
+        "@redux-saga/symbols": "^1.1.2",
+        "@redux-saga/types": "^1.1.0",
+        "redux": "^4.0.4",
+        "typescript-tuple": "^2.2.1"
+      }
+    },
+    "@redux-saga/deferred": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.1.2.tgz",
+      "integrity": "sha512-908rDLHFN2UUzt2jb4uOzj6afpjgJe3MjICaUNO3bvkV/kN/cNeI9PMr8BsFXB/MR8WTAZQq/PlTq8Kww3TBSQ=="
+    },
+    "@redux-saga/delay-p": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.1.2.tgz",
+      "integrity": "sha512-ojc+1IoC6OP65Ts5+ZHbEYdrohmIw1j9P7HS9MOJezqMYtCDgpkoqB5enAAZrNtnbSL6gVCWPHaoaTY5KeO0/g==",
+      "requires": {
+        "@redux-saga/symbols": "^1.1.2"
+      }
+    },
+    "@redux-saga/is": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.2.tgz",
+      "integrity": "sha512-OLbunKVsCVNTKEf2cH4TYyNbbPgvmZ52iaxBD4I1fTif4+MTXMa4/Z07L83zW/hTCXwpSZvXogqMqLfex2Tg6w==",
+      "requires": {
+        "@redux-saga/symbols": "^1.1.2",
+        "@redux-saga/types": "^1.1.0"
+      }
+    },
+    "@redux-saga/symbols": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.2.tgz",
+      "integrity": "sha512-EfdGnF423glv3uMwLsGAtE6bg+R9MdqlHEzExnfagXPrIiuxwr3bdiAwz3gi+PsrQ3yBlaBpfGLtDG8rf3LgQQ=="
+    },
+    "@redux-saga/types": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.1.0.tgz",
+      "integrity": "sha512-afmTuJrylUU/0OtqzaRkbyYFFNgCF73Bvel/sw90pvGrWIZ+vyoIJqA6eMSoA6+nb443kTmulmBtC9NerXboNg=="
+    },
     "@restart/hooks": {
       "version": "0.4.5",
       "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.5.tgz",
@@ -27550,6 +27674,14 @@
         "@babel/runtime": "^7.9.2"
       }
     },
+    "redux-saga": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.1.3.tgz",
+      "integrity": "sha512-RkSn/z0mwaSa5/xH/hQLo8gNf4tlvT18qXDNvedihLcfzh+jMchDgaariQoehCpgRltEm4zHKJyINEz6aqswTw==",
+      "requires": {
+        "@redux-saga/core": "^1.1.3"
+      }
+    },
     "redux-thunk": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz",
@@ -28802,6 +28934,27 @@
       "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==",
       "peer": true
     },
+    "typescript-compare": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz",
+      "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
+      "requires": {
+        "typescript-logic": "^0.0.0"
+      }
+    },
+    "typescript-logic": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz",
+      "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q=="
+    },
+    "typescript-tuple": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
+      "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
+      "requires": {
+        "typescript-compare": "^0.0.2"
+      }
+    },
     "unbox-primitive": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",

+ 1 - 0
project/my-project/package.json

@@ -15,6 +15,7 @@
     "react-redux": "^7.2.6",
     "react-router-dom": "^5.3.0",
     "react-scripts": "5.0.0",
+    "redux-saga": "^1.1.3",
     "redux-thunk": "^2.4.1",
     "web-vitals": "^2.1.2"
   },

+ 14 - 0
project/my-project/src/App.css

@@ -43,3 +43,17 @@ a:link, a:visited {
 .ant-layout-header {
   background:  #728892; 
 }
+
+.imgWrapper{
+  /* padding-top: 30px; */
+  height: 150px;
+  width: 150px;
+}
+
+.ant-btn-block {
+  margin-top: 10px;
+}
+
+.ant-input-group-wrapper {
+  margin-top: 15px;
+}

+ 15 - 0
project/my-project/src/action/actionAddCategory.js

@@ -0,0 +1,15 @@
+import _default from "antd/lib/checkbox/Group"
+import { actionPromise } from ".";
+import gql from "../api";
+
+const actionAddCategory = (name) => 
+  actionPromise('addCat', gql(`mutation addCategory ($add:CategoryInput) {
+    CategoryUpsert(category:$add){
+      _id name
+      }
+    }`, {
+      "add": {"name": name}
+    }))
+
+
+export default actionAddCategory; 

+ 1 - 1
project/my-project/src/action/actionCatById.js

@@ -14,7 +14,7 @@ const actionCatById = (_id) =>  //добавить подкатегории
             }
           }
        }goods {
-         _id name price images {
+         _id name price description images{
            url
          }
        }

+ 20 - 0
project/my-project/src/action/actionChangeCategName.js

@@ -0,0 +1,20 @@
+import { actionPromise } from ".";
+import gql from "../api";
+import { actionRootCats } from ".";
+
+const actionChangeCategName = (_id, name) => 
+  async (dispatch) => { 
+    await dispatch(actionPromise('newCategoryName', gql(`mutation categoryChange($category:CategoryInput){
+    CategoryUpsert(category:$category){
+      _id name
+      }
+    }`, {
+      "category": {
+        "_id": _id,
+        "name": name}
+    })))
+
+    dispatch(actionRootCats())
+  }
+
+export default actionChangeCategName;

+ 23 - 0
project/my-project/src/action/actionChangeOneGood.js

@@ -0,0 +1,23 @@
+import { actionPromise, actionCatById } from ".";
+import gql from "../api";
+
+const actionChangeOneGood = (_id, name, description, price, idImg) =>
+  async (dispatch) => {
+    await dispatch(actionPromise('changeGood', gql(`mutation changeGood($good:GoodInput){
+      GoodUpsert(good:$good){
+        _id name
+      }
+    }`, {
+          "good":{
+          "_id": _id,
+          "description": description,
+          "name": name, 
+          "price": price,
+          "images": [{"_id": idImg}]
+        } 
+    })))
+
+    dispatch(actionCatById())
+}
+
+export default actionChangeOneGood; 

+ 28 - 0
project/my-project/src/action/actionSearchGood.js

@@ -0,0 +1,28 @@
+import { actionPromise } from ".";
+import  gql  from '../api';
+
+
+const actionSearchGood = (name) =>
+  
+    actionPromise('searchGood', gql(`
+      query gf($query: String){
+          GoodFind(query: $query){
+              _id, name, description, price, images{
+                  _id, url
+              }
+          }
+      }`, {
+        query: JSON.stringify([
+                  {
+                      $or: [{name}, {description: name}]
+                  },
+                  {
+                      sort: [{name: 1}]
+                  }
+                  ])
+          }
+      )
+    )
+  
+
+export default actionSearchGood;

+ 2 - 1
project/my-project/src/action/actionUploadFile.js

@@ -1,6 +1,8 @@
 import { connect } from "react-redux";
 import { actionPromise } from "./";
 import { backURL } from '../api';
+import { Upload, message, Button } from 'antd';
+import { UploadOutlined } from '@ant-design/icons';
 
 const actionUploadFile = (file) => {
   const fileJson = JSON.stringify(file[0]);
@@ -23,5 +25,4 @@ const actionUploadFile = (file) => {
   )
 }
 
-
 export default actionUploadFile;

+ 4 - 0
project/my-project/src/action/index.js

@@ -8,4 +8,8 @@ export {actionAuthLogout, actionFullRegister,} from './actionRegister';
 export { default as actionOrder } from './actionOrder';
 export { default as actionMyOrders } from './actionMyOrders';
 export { default as actionUploadFile} from './actionUploadFile';
+export { default as actionChangeCategName } from './actionChangeCategName';
+export { default as actionAddCategory } from './actionAddCategory';
+export { default as actionChangeOneGood } from './actionChangeOneGood';
+export { default as actionSearchGood } from './actionSearchGood';
 

+ 22 - 0
project/my-project/src/components/aaaaa.js

@@ -0,0 +1,22 @@
+const localStoredReducer = (reducer, localStorageName) =>
+  (state, action) => {
+
+    if(!state) {
+      const key = localStorage.getItem(localStorageName);
+      if(key) {
+       return JSON.parse(key);
+      } else {
+        let newState = reducer(state,action);
+        localStorage.setItem(localStorageName, JSON.stringify(newState))
+        return newState;
+      }
+
+    }
+   
+   
+
+  }
+combineReducers({cart: localStoredReducer(cartReducer, 'cart')})  
+
+
+

+ 29 - 0
project/my-project/src/components/addCategory.js

@@ -0,0 +1,29 @@
+import { Input, Card, Button, Space } from 'antd';
+import { useEffect, useState } from 'react';
+import { connect } from 'react-redux';
+import { actionAddCategory } from '../action';
+
+const ACategory = ({addCat}) => {
+  const [nameCat, setNameCat] =useState('');
+  
+  const clearInput = () => { 
+    setNameCat(''); 
+  }
+  
+  return (
+    <div >
+    <Card type="inner" title="Добавить категорию товара">
+      <Input onChange={ (e) => setNameCat(e.target.value)}/>
+      <Space>
+        <Button type="primary" onClick={() => addCat(nameCat)}>Сохранить изменения</Button>
+        <Button type="primary" onClick={clearInput} >Очистить поле</Button>
+      </Space>
+      
+    </Card>
+</div>
+  )
+}
+
+const AddCategory = connect(null, {addCat: actionAddCategory})(ACategory);
+
+export default AddCategory;

+ 1 - 1
project/my-project/src/components/cGoodCard.js

@@ -17,7 +17,7 @@ const GoodCard = ({good:{_id, name, price, images}, onAdd}) =>
     >
     <Meta title={name} />
     <Space direction="vertical">
-      {images && images[0] && images[0].url &&<Link to={`/good/${_id}`}> <Image width={200} height={200} src={backendURL + '/' + images[0].url} /></Link>}
+      {images && images[0] && images[0].url &&<Link to={`/good/${_id}`}> <Image width={200} height={200} style={{objectFit: 'cover'}} src={backendURL + '/' + images[0].url} /></Link>}
       <strong>{price} грн.</strong>
       <Button size="middle" onClick={() => onAdd({_id, name, price, images})}>Купить</Button>
     </Space>

+ 62 - 0
project/my-project/src/components/cartChangeGood.js

@@ -0,0 +1,62 @@
+import { Select,Card } from 'antd';
+import { useEffect, useState } from 'react';
+import { connect } from 'react-redux';
+import { СhangeOfGood } from '.';
+import { actionChangeOneGood } from '../action';
+
+const { Option } = Select;
+
+const SelectGood = ({goods, changeGood}) => { console.log('ggggg',goods)
+  
+  const [goodsCat, setGoodsCat] = useState([]); 
+  const [_id, setId] = useState('');
+  const [selectGood, setSelectGood] = useState({}); 
+  console.log('RENDER======')
+  useEffect(() => {
+    if(goods && goods.goods && selectGood.name!== goods.goods.name ) {
+      setSelectGood({});
+    }
+
+    if(goods && goods.goods){
+    setGoodsCat(goods.goods);
+    }
+  }, [goods])
+
+  function handleChange(value) {
+      console.log(`selected ${value}`);
+     
+      const good = goodsCat.filter((good) => good._id === value); 
+      setSelectGood(...good);
+      setId(value);
+    }
+
+    function changeGoodInSer (name, description, price, imgId) {
+      console.log("----", typeof name, typeof description, typeof price, typeof imgId )
+      changeGood(_id, name, description,price, imgId);
+    }
+
+
+   return (
+     < >{goods &&
+      <Card type="inner" title="Изменить товар">
+        <Select value={selectGood.name || null} placeholder='Выбирите товар' style={{ width: 272 }} onChange={handleChange}>
+          {goodsCat.map((item) => <Option value={item._id} key={item._id}>{item.name}</Option>)}
+        </Select>
+        <СhangeOfGood good={selectGood} changeGood={() => changeGoodInSer}/>
+      </Card>
+    }</>
+   )
+}
+
+const mapStateToProps = (state) => ({
+  goods: state.promise.catById?.payload
+})
+
+const mapDispatchToProps = {
+  changeGood : actionChangeOneGood,
+}
+
+
+const CartChangeGood = connect(mapStateToProps, mapDispatchToProps)(SelectGood);
+
+export default CartChangeGood;

+ 84 - 0
project/my-project/src/components/changeOfGood.js

@@ -0,0 +1,84 @@
+import { Input, Card, Button, Space, Image, Row } from 'antd';
+import { useEffect, useState } from 'react';
+import { connect } from 'react-redux';
+import { InputUpLoadFile } from '.';
+import { backURL } from '../api'; 
+
+const { TextArea } = Input;
+
+const CharacterfGood =({ good, good:{ _id, name, description, images, price }, upLoad, changeGood }) => {    console.log('gooood',good)
+    const [ inputIdImg, setInputIdImg] = useState(''); 
+    const [ inputName, setInputName ] = useState(name); 
+    const [ inputDescrip, setInputDescrip] = useState(description);
+    const [ img, setImg ] = useState(''); 
+    const [ cost, setCost ] = useState(price);
+
+    useEffect( () => {
+      setInputName(name);
+      setInputDescrip(description);
+
+      if(images && images[0].url) {
+        setImg(images[0].url); 
+      }
+              
+      setCost(price);           
+
+    }, [good])
+
+    useEffect(() => {
+      if(upLoad && upLoad.status === 'RESOLVED' ) { console.log('',)
+        setImg(upLoad.payload.url);
+        setInputIdImg(upLoad.payload._id);  //61e304d8f9be102f49b2aa5c
+      }
+    }, [upLoad])
+    // onChange = ({ target: { value } }) => {
+    //   setInputDescrip(value);
+    // };
+
+  return (
+    <div >
+      <div>Название</div>
+        <Input value={inputName} onChange={(e) => setInputName(e.target.value)}/>
+        <Button type="primary" >Очистить поле</Button>
+      <div>Характеристика</div>
+        <TextArea
+            value={inputDescrip}
+            onChange={(e) => setInputDescrip(e.target.value)}
+            
+            autoSize={{ minRows: 3, maxRows: 5 }}
+          />
+        <Button type="primary" >Очистить поле</Button>
+      <div>Цена</div>
+        <Row>
+          <Input value={cost} onChange={(e) => setCost(e.target.value)}/>
+          <Button type="primary" >Очистить поле</Button>
+        </Row>
+       
+        
+        <Space size={12} direction="vertical">
+          
+            {/* <div  className="imgWrapper"> */}
+              <div>Фото</div>
+            {Object.keys(good).length === 0 ?
+              <div style={{height:"150px", width:"150px"}}> </div>
+              :
+              <Image width={150} height={150} src={`${backURL}/${img}`} style={{ objectFit: 'cover' }}/>}
+              <InputUpLoadFile/>
+           {/* </div> */}
+        </Space>
+        <Space size={2}></Space>
+        <Button type="primary" block onClick={() => changeGood(inputName, inputDescrip, cost, inputIdImg )}>
+          Сохранить изменения
+        </Button>     
+  </div>
+  )
+}
+
+const mapStateToProps = ((state) => ({
+  upLoad: state.promise?.upLoad
+}))
+const СhangeOfGood = connect(mapStateToProps)(CharacterfGood);
+
+export default СhangeOfGood;
+
+//{images && images[0] && images[0].url && (src={backURL + '/' + `${img || images[0].url }`})}

+ 9 - 3
project/my-project/src/components/header.js

@@ -1,4 +1,4 @@
-import { Layout, Menu, Breadcrumb, Row, Col, Avatar, Badge, Button  } from 'antd';
+import { Layout, Menu, Breadcrumb, Row, Col, Avatar, Badge, Button, Input  } from 'antd';
 import { useEffect, useState } from 'react';
 import {Router, Route, Link, Redirect, Switch} from 'react-router-dom';
 import { createFromIconfontCN, FileTwoTone } from '@ant-design/icons';
@@ -6,8 +6,10 @@ import { connect } from 'react-redux';
 import { jwtDecode } from '../utils';
 import {default as ButtonExSite } from './buttonExSite';
 import { actionMyOrders } from '../action';
+import { InputSearchGood } from '.';
 
 const { Header, Content, Footer, Sider } = Layout;
+
 const IconFont = createFromIconfontCN({
   scriptUrl: [
     '//at.alicdn.com/t/font_1788044_0dwu4guekcwr.js', // icon-javascript, icon-java, icon-shoppingcart (overrided)
@@ -48,15 +50,19 @@ const HeaderComponent = ({login, cart, getOrders}) => {
   , [login, cart])
 
     
-
+   
   return(
     <Header className="header">
     {/* <div className="logo" /> */}
     
       <Row>
-        <Col span={17}>
+        <Col span={12}>
         </Col>
 
+        <Col span={15}>
+          <InputSearchGood/> 
+        </Col>  
+
        { nike? 
         < >
           <Col span={1}>

+ 6 - 0
project/my-project/src/components/index.js

@@ -9,5 +9,11 @@ export { default as RegisterIn } from './registerIn';
 export { default as ListOrders }  from './listOrders';
 export { default as Page404 } from './pege404';
 export { default as InputUpLoadFile } from './inputUploadFile';
+export { default as SwitchRoute } from './switchRoute';
+export { default as NameCategory } from './nameCategory';
+export { default as AddCategory } from './addCategory';
+export { default as СhangeOfGood } from './changeOfGood';
+export { default as CartChangeGood} from './cartChangeGood';
+export { default as InputSearchGood } from './inputSearchGood';
 
 

+ 44 - 0
project/my-project/src/components/inputSearchGood.js

@@ -0,0 +1,44 @@
+import { Input  } from 'antd';
+import { useEffect, useState } from 'react';
+import { connect } from 'react-redux';
+import { actionSearchGood } from '../action';
+import {useHistory} from 'react-router-dom';
+
+const { Search } = Input;
+
+const InputSearchG = ({good:{_id}, search}) => { 
+  let history = useHistory();
+  const [idGood, setIdGood] = useState(_id);
+  const [inputValue, setInputValue] = useState('');
+  
+  useEffect(() => {
+    if(_id) {
+      setIdGood(_id);
+      history.push(`/good/${_id}`);
+    }
+
+  }, [_id])
+
+  const onSearch = value => {
+    console.log(value);
+    search(value);
+    setInputValue(''); console.log('setInputValue',)
+   
+  } 
+  
+  return (
+    <Search placeholder="Найти товар " allowClear onSearch={onSearch} style={{ width: 250 }} value={inputValue} onChange={(e) => setInputValue(e.target.value)}/> 
+  )
+}
+
+const mapStateToProps = (state) => ({
+  good: state.promise.searchGood?.payload[0] || '',
+}) 
+
+const mapDispatchToProps = {
+  search: actionSearchGood,
+}
+
+const InputSearchGood = connect(mapStateToProps, mapDispatchToProps)(InputSearchG);
+
+export default InputSearchGood;

+ 5 - 1
project/my-project/src/components/inputUploadFile.js

@@ -1,12 +1,16 @@
 import React, {useCallback} from 'react';
 import {useDropzone} from 'react-dropzone';
+import { Upload, message, Button } from 'antd';
+import { UploadOutlined } from '@ant-design/icons';
 
 import { store} from '../store';
 import { actionUploadFile } from '../action';
 
 const InputUpLoadFile = () => {
+  
   const onDrop = useCallback(acceptedFiles => {
     console.log('acceptedFiles', acceptedFiles);
+
     store.dispatch(actionUploadFile(acceptedFiles ))
   }, [])
   
@@ -18,7 +22,7 @@ const InputUpLoadFile = () => {
       {
         isDragActive ?
           <p>Drop the files here ...</p> :
-          <p>Выбрать файл</p>
+          <Button icon={<UploadOutlined />}> Выбрать файл</Button>
       }
     </div>
   )

+ 5 - 4
project/my-project/src/components/listOrders.js

@@ -3,7 +3,7 @@ import { Card, Row, Col } from 'antd';
 import { actionMyOrders } from "../action";
 import { useEffect, useState } from "react";
 
-const Orders = ({allOrders}) => {
+const Orders = ({allOrders, status}) => {
   const [ord, setOrd] = useState(allOrders); 
 
   useEffect( () => {
@@ -15,8 +15,8 @@ const Orders = ({allOrders}) => {
   return (
     <Card title="История заказов">
 
-    { ord.length ? 
-        ord.map( (item, index) => 
+    { ord.length0 === 0 && status['status'] &&  <Card>Вы не совершали покупки</Card>}
+       { ord.map( (item, index) => 
           <Card  key={index} type="inner" title={`Заказ №  ${index + 1}`} style={{ marginTop: 16 }} >
             <Row>
               <Col span={9}>Название</Col>
@@ -38,7 +38,7 @@ const Orders = ({allOrders}) => {
 
 
       ) 
-      : <Card>Вы не совершали покупки</Card>
+      
     
     }
 
@@ -50,6 +50,7 @@ const Orders = ({allOrders}) => {
 const mapStateToProps = (state) => (
   {
     allOrders: state.promise.myOrders?.payload || [],
+    status: state.promise?.myOrders,
   }
 )
 

+ 45 - 0
project/my-project/src/components/nameCategory.js

@@ -0,0 +1,45 @@
+import { Input, Card, Button, Space } from 'antd';
+import { useEffect, useState } from 'react';
+import { connect } from 'react-redux';
+import { actionChangeCategName } from '../action';
+
+const CategoryAdmin = ({category, _id, changeCategName }) => { 
+
+  const [nameCat, setNameCat] = useState(category.name); 
+  
+  useEffect ( () => {
+    setNameCat(category.name)
+  }, [category])
+
+  const renewCategory = () => {
+    changeCategName(_id, nameCat);// console.log('zzz', typeof _id)
+    setNameCat('');
+  }
+
+  const clearInput = () => { 
+    setNameCat(''); 
+  }
+
+  return (
+   <div >
+      <Card type="inner" title="Изменить категорию товара">
+        <Input value={nameCat} onChange={ (e) => setNameCat(e.target.value)}/>
+        <Space>
+          <Button type="primary" onClick={renewCategory}>Сохранить изменения</Button>
+          <Button type="primary" onClick={clearInput} >Очистить поле</Button>
+        </Space>
+        
+      </Card>
+  </div>
+    
+  )
+}
+
+const mapStateToProps = (state) => ({
+  category: state.promise. catById?.payload || {},
+  allcategory: state.promise.rootCats?.payload || [],
+})
+
+const NameCategory = connect(mapStateToProps, { changeCategName :actionChangeCategName })(CategoryAdmin);
+
+export default NameCategory;

+ 3 - 2
project/my-project/src/components/signIn.js

@@ -8,7 +8,7 @@ import {Router, Route, Link, Redirect, Switch, useHistory} from 'react-router-do
 
 import { useEffect, useState } from 'react';
 
-const Sign = ({getState, auth}) => { console.log('auth', auth); 
+const Sign = ({getState, auth, logStatus}) => { console.log('auth', auth); 
 
   const  [logMessage, setLogMessage] = useState(false);
   
@@ -76,7 +76,7 @@ const Sign = ({getState, auth}) => { console.log('auth', auth);
           </Button>
         </Form.Item>
 
-        { logMessage && (auth).length == 0 && <Form.Item wrapperCol={{ offset: 8, span: 16 }}> {console.log('tttt')}
+        { logMessage && logStatus == 'RESOLVED' && (auth).length == 0 && <Form.Item wrapperCol={{ offset: 8, span: 16 }}> {console.log('tttt')}
         <Alert
           message="Ошибка"
           description="Неправильно введен логин или пароль"
@@ -93,6 +93,7 @@ const Sign = ({getState, auth}) => { console.log('auth', auth);
 
 const mapStateToProps = state => ({
   auth: state.auth?.token || '',
+  logStatus: state.promise.login?.status || '', 
  
 })
 

+ 26 - 0
project/my-project/src/components/switchRoute.js

@@ -0,0 +1,26 @@
+import { useEffect, useState } from "react";
+import { UseRoute } from "../route";
+import { jwtDecode } from "../utils";
+import { PrivateRoute } from "../route";
+
+const SwitchRoute = () => {
+  const [userName, setUserName] = useState('user');
+
+  useEffect( () => {
+    const token = localStorage.getItem('authToken'); 
+    //
+    if (token) { 
+      const name = jwtDecode(token)['sub']['acl']; //console.log('name', jwtDecode(token)['sub']);
+      name.includes('admin') ? setUserName(name ):  setUserName('user'); 
+     
+    }
+  }, [localStorage.getItem('authToken')])
+
+  return ( 
+    < >
+    {userName === 'user' ? <UseRoute/>: <PrivateRoute/>}
+    </>
+  )
+}
+
+export default SwitchRoute; 

+ 2 - 1
project/my-project/src/pages/index.js

@@ -1,3 +1,4 @@
 export { default as PageBasket } from './pageBasket';
 export { default as CreatePageGood } from './pageGood';
-export { default as CPageCategory } from './cpageCategory';
+export { default as CPageCategory } from './cpageCategory';
+export { default as PageCategoryAdmin } from './pageAdmin';

+ 6 - 2
project/my-project/src/pages/mainPage.js

@@ -7,7 +7,7 @@ import { actionRootCats } from "../action";
 
 
 import {SignIn, ListOrders, Page404} from '../components';
-import { CCategoryList } from '../components';
+import { CCategoryList, SwitchRoute } from '../components';
 import { useEffect } from 'react';
 import CPageCategory from './cpageCategory';
 import CreatePageGood from './pageGood';
@@ -60,7 +60,11 @@ function MainPage () {
           {/* </Menu> */}
         </Sider>
         <Content style={{ padding: '0 24px', minHeight: 280 }}>Content
-          <UseRoute/>
+          <Switch>
+            <SwitchRoute/>
+          </Switch>
+
+          
 
 
         </Content>

+ 35 - 0
project/my-project/src/pages/pageAdmin.js

@@ -0,0 +1,35 @@
+import { useEffect } from "react";
+import { connect } from "react-redux";
+import { actionCatById } from "../action";
+import { NameCategory, AddCategory, CartChangeGood, SelectGoodAdmin } from "../components";
+
+ 
+const PCategoryAdmin = ({match, match: {params: {_id}}, getCategory}) => {
+  useEffect( () => {
+    getCategory(_id);
+  }, [_id])
+
+  return (
+    <>
+       {/* Изменить категорию товара */}
+    <div>
+      <NameCategory _id={_id}/>
+    </div>
+      {/* Добавть категорию товара */}
+    <div>
+      <AddCategory/>
+    </div>
+        <CartChangeGood/>
+      <div>
+  
+      </div>
+
+    </> 
+  )
+}
+
+
+
+const PageCategoryAdmin = connect(null, {getCategory: actionCatById})(PCategoryAdmin)
+
+export default PageCategoryAdmin;

+ 2 - 3
project/my-project/src/pages/pageBasket.js

@@ -67,9 +67,8 @@ const GoodsInBasket = ({cart = {}, orderPayload, cartMin, cartClear, cartChange,
   const oderPlusclearOrder = () => { 
     order();
 
-    if (Object.values(orderPayload).length !== 0) { console.log('clearOrder')
-      cartClear();
-    }
+    cartClear();
+    
   }
 
   return (

+ 4 - 0
project/my-project/src/reducer/cartReducer.js

@@ -49,6 +49,10 @@ function cartReducer(state={}, {type, good = {}, count=1}){
           
         };
       },
+      AUTH_LOGOUT () {
+        localStorage.clear();                          //почистить localStorage
+        return {};                                     //вернуть пустой объект
+      }
   }
 
   if (type in types)

+ 14 - 1
project/my-project/src/reducer/promiseReducer.js

@@ -1,11 +1,24 @@
+// function promiseReducer(state={}, {type, name, status, payload, error}){
+//   if (type === 'PROMISE'){
+//       return {
+//         ...state,
+//         [name]:{status, payload, error}
+//       }
+//   }
+//   return state
+// }
+
+
 function promiseReducer(state={}, {type, name, status, payload, error}){
   if (type === 'PROMISE'){
       return {
         ...state,
-        [name]:{status, payload, error}
+        [name]:{status, payload: (status === 'PENDING' && state[name] && state[name].payload) || payload, error}
       }
   }
   return state
 }
 
+
+
 export default promiseReducer;

+ 2 - 1
project/my-project/src/route/index.js

@@ -1 +1,2 @@
-export { default as UseRoute } from './useRoute';
+export { default as UseRoute } from './useRoute';
+export { default as PrivateRoute } from './privateRoute';

+ 19 - 0
project/my-project/src/route/privateRoute.js

@@ -0,0 +1,19 @@
+import { Route, Switch } from "react-router-dom";
+import { SignIn } from "../components";
+import { PageCategoryAdmin } from "../pages";
+
+
+
+const PrivateRoute = () => {
+  return (
+    <>
+      <Route path = "/login" component = {SignIn}/>
+      <Route path = "/category/:_id" component = {PageCategoryAdmin}/>
+      {/* <Route path = "/good/:_id" component = {CreatePageGood}/>
+      <Route path = "/basket" component={PageBasket}/> 
+      <Route path = "/listOrders" component={ListOrders}/> */}
+    </>
+  )
+}
+
+export default PrivateRoute;

+ 2 - 2
project/my-project/src/route/useRoute.js

@@ -7,7 +7,7 @@ import { PageBasket, CPageCategory, CreatePageGood}  from '../pages';
 
 const UseRoute = () => {
   return (
-    <Switch>
+    <>
       {/* <Redirect from="/main" to='/' /> */}
       {/* <Route path="/" component={PageMain} exact /> */}
       <Route path = "/login" component = {SignIn}/>
@@ -17,7 +17,7 @@ const UseRoute = () => {
       <Route path = "/basket" component={PageBasket}/> 
       <Route path = "/listOrders" component={ListOrders}/>
       {/* <Route path = "/*" component= {Page404}/> */}
-    </Switch>
+    </>
   )
 }
 

+ 46 - 6
project/my-project/src/store/index.js

@@ -2,13 +2,53 @@
 import thunk from 'redux-thunk';
 import { createStore, combineReducers, applyMiddleware } from 'redux';
 import { authReducer, promiseReducer, cartReducer } from '../reducer';
-import { actionRootCats } from "../action";
+import { actionRootCats, actionSearchGood } from "../action";
 
-export const store = createStore(combineReducers({
-  promise: promiseReducer, 
-  auth: authReducer, 
-  cart: cartReducer
-}), applyMiddleware(thunk));
+// export const store = createStore(combineReducers({
+//   promise: promiseReducer, 
+//   auth: authReducer, 
+//   cart: cartReducer
+// }), applyMiddleware(thunk));
  
+// store.subscribe(() => console.log(store.getState()));
+// store.dispatch(actionRootCats());
+
+
+
+const localStoredReducer = (reducer, localStorageName) => 
+  (state, action) => { 
+
+    if(!state) {
+      const key = localStorage.getItem(localStorageName); 
+      if(key) { 
+       return JSON.parse(key);
+      } else {
+       return reducer(state, action);
+      }  
+    }       
+    if(state) {
+      let newState = reducer(state, action);  
+      localStorage.setItem(localStorageName, JSON.stringify(newState));
+      return newState;
+    }   
+  }
+
+
+ 
+
+
+  export const store = createStore(combineReducers({
+    promise: localStoredReducer(promiseReducer, 'promise'), 
+    auth: localStoredReducer(authReducer, 'auth'), 
+    cart: localStoredReducer(cartReducer, 'cart')
+  }), applyMiddleware(thunk));
+
+
+  
+
+
 store.subscribe(() => console.log(store.getState()));
 store.dispatch(actionRootCats());
+// setTimeout(() => {
+//   store.dispatch(actionSearchGood("iPhone 11"));
+// }, 2000)