4 次代码提交 b46a81722c ... e99b4855da

作者 SHA1 备注 提交日期
  Svetlana e99b4855da category admin 5 年之前
  Svetlana 44569b3daa marge -> sineIn, sineUp and profile 5 年之前
  Maxim 1fa808c423 sign up is finally done 5 年之前
  Maxim 3dd80863d5 signUp -> validation and form added, reducer is done 5 年之前
共有 50 个文件被更改,包括 1205 次插入88 次删除
  1. 254 0
      package-lock.json
  2. 4 1
      package.json
  3. 14 0
      src/actions/admin/changeCategory.js
  4. 14 0
      src/actions/admin/createCategory.js
  5. 14 0
      src/actions/admin/deleteCategory.js
  6. 14 0
      src/actions/admin/getCategory.js
  7. 3 0
      src/actions/auth/logOut.js
  8. 0 0
      src/actions/auth/saveToken.js
  9. 4 7
      src/actions/auth/signIn.js
  10. 0 0
      src/components/admin/CreateTest/index.js
  11. 56 0
      src/components/admin/addDeleteCategory/ChangeCategory.js
  12. 43 0
      src/components/admin/addDeleteCategory/CreateCategoryForm/index.js
  13. 40 0
      src/components/admin/addDeleteCategory/DeleteCategory.js
  14. 94 0
      src/components/admin/addDeleteCategory/GetCategory.js
  15. 47 0
      src/components/admin/addDeleteCategory/index.js
  16. 25 0
      src/components/admin/deleteUser/DeleteUserForm/index.js
  17. 31 0
      src/components/admin/deleteUser/index.js
  18. 1 3
      src/components/common/protectedRoute.js
  19. 14 15
      src/components/public/Header.js
  20. 12 13
      src/components/public/SignIn/Form/index.js
  21. 17 5
      src/components/public/SignIn/index.js
  22. 63 0
      src/components/public/SignUp/Form/index.js
  23. 47 0
      src/components/public/SignUp/Form/validate.js
  24. 31 0
      src/components/public/SignUp/index.js
  25. 1 1
      src/components/user/ProfilePage/changePassword/index.js
  26. 3 22
      src/components/user/ProfilePage/index.js
  27. 12 5
      src/configs/routerConfig.js
  28. 17 0
      src/constants/admin.js
  29. 1 1
      src/constants/auth.js
  30. 35 0
      src/reducers/admin/changeCategory.js
  31. 34 0
      src/reducers/admin/getCategory.js
  32. 34 0
      src/reducers/admin/index.js
  33. 3 3
      src/reducers/auth/signIn.js
  34. 8 4
      src/reducers/auth/signUp.js
  35. 9 1
      src/reducers/index.js
  36. 12 1
      src/reducers/initialState.js
  37. 0 2
      src/router.js
  38. 29 0
      src/sagas/admin/changeCategory.js
  39. 28 0
      src/sagas/admin/createCategory.js
  40. 26 0
      src/sagas/admin/deleteCategory.js
  41. 27 0
      src/sagas/admin/getCategory.js
  42. 18 0
      src/sagas/admin/index.js
  43. 4 2
      src/sagas/auth/signIn.js
  44. 24 2
      src/sagas/auth/signUp.js
  45. 2 0
      src/sagas/index.js
  46. 2 0
      src/styles/_index.scss
  47. 14 0
      src/styles/abstracts/_theme.scss
  48. 14 0
      src/styles/extended/_vh.scss
  49. 5 0
      src/styles/style/_styles.scss
  50. 1 0
      src/utils/storageKey.js

+ 254 - 0
package-lock.json

@@ -854,6 +854,86 @@
       "resolved": "https://registry.npmjs.org/@csstools/convert-colors/-/convert-colors-1.4.0.tgz",
       "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw=="
     },
+    "@emotion/cache": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.0.tgz",
+      "integrity": "sha512-1/sT6GNyvWmxCtJek8ZDV+b+a+NMDx8/61UTnnF3rqrTY7bLTjw+fmXO7WgUIH0owuWKxza/J/FfAWC/RU4G7A==",
+      "requires": {
+        "@emotion/sheet": "0.9.2",
+        "@emotion/stylis": "0.8.3",
+        "@emotion/utils": "0.11.1",
+        "@emotion/weak-memoize": "0.2.2"
+      }
+    },
+    "@emotion/core": {
+      "version": "10.0.6",
+      "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.6.tgz",
+      "integrity": "sha512-S5KkrodTKby1S6pKZnH8LzjzlebHvjactujfVzzu/mYYdVdKYegJuJdrAz3m9zhIeizzeQGD8xWF490ioGpUtw==",
+      "requires": {
+        "@emotion/cache": "10.0.0",
+        "@emotion/css": "^10.0.6",
+        "@emotion/serialize": "^0.11.3",
+        "@emotion/sheet": "0.9.2",
+        "@emotion/utils": "0.11.1"
+      }
+    },
+    "@emotion/css": {
+      "version": "10.0.6",
+      "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.6.tgz",
+      "integrity": "sha512-/suYOvP0zeKC3UNoIeN/3zvr/ghUKgfWx0Pht5ZY9qgHis68fB+V45OjonzMbdOw4mGX0vjZzJhINk9JbRWVrg==",
+      "requires": {
+        "@emotion/serialize": "^0.11.3",
+        "@emotion/utils": "0.11.1",
+        "babel-plugin-emotion": "^10.0.6"
+      }
+    },
+    "@emotion/hash": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.7.1.tgz",
+      "integrity": "sha512-OYpa/Sg+2GDX+jibUfpZVn1YqSVRpYmTLF2eyAfrFTIJSbwyIrc+YscayoykvaOME/wV4BV0Sa0yqdMrgse6mA=="
+    },
+    "@emotion/memoize": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz",
+      "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg=="
+    },
+    "@emotion/serialize": {
+      "version": "0.11.3",
+      "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.3.tgz",
+      "integrity": "sha512-6Q+XH/7kMdHwtylwZvdkOVMydaGZ989axQ56NF7urTR7eiDMLGun//pFUy31ha6QR4C6JB+KJVhZ3AEAJm9Z1g==",
+      "requires": {
+        "@emotion/hash": "0.7.1",
+        "@emotion/memoize": "0.7.1",
+        "@emotion/unitless": "0.7.3",
+        "@emotion/utils": "0.11.1",
+        "csstype": "^2.5.7"
+      }
+    },
+    "@emotion/sheet": {
+      "version": "0.9.2",
+      "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.2.tgz",
+      "integrity": "sha512-pVBLzIbC/QCHDKJF2E82V2H/W/B004mDFQZiyo/MSR+VC4pV5JLG0TF/zgQDFvP3fZL/5RTPGEmXlYJBMUuJ+A=="
+    },
+    "@emotion/stylis": {
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.3.tgz",
+      "integrity": "sha512-M3nMfJ6ndJMYloSIbYEBq6G3eqoYD41BpDOxreE8j0cb4fzz/5qvmqU9Mb2hzsXcCnIlGlWhS03PCzVGvTAe0Q=="
+    },
+    "@emotion/unitless": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.3.tgz",
+      "integrity": "sha512-4zAPlpDEh2VwXswwr/t8xGNDGg8RQiPxtxZ3qQEXyQsBV39ptTdESCjuBvGze1nLMVrxmTIKmnO/nAV8Tqjjzg=="
+    },
+    "@emotion/utils": {
+      "version": "0.11.1",
+      "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.1.tgz",
+      "integrity": "sha512-8M3VN0hetwhsJ8dH8VkVy7xo5/1VoBsDOk/T4SJOeXwTO1c4uIqVNx2qyecLFnnUWD5vvUqHQ1gASSeUN6zcTg=="
+    },
+    "@emotion/weak-memoize": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.2.tgz",
+      "integrity": "sha512-n/VQ4mbfr81aqkx/XmVicOLjviMuy02eenSdJY33SVA7S2J42EU0P1H0mOogfYedb3wXA0d/LVtBrgTSm04WEA=="
+    },
     "@mrmlnc/readdir-enhanced": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
@@ -1965,6 +2045,23 @@
         "object.assign": "^4.1.0"
       }
     },
+    "babel-plugin-emotion": {
+      "version": "10.0.6",
+      "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.6.tgz",
+      "integrity": "sha512-JD2st8enZJn8h7W1s8kcb40r3RBCJwV9E8ZAhyyhELUMP8OYwyI9K1rz7MxRi0CoorX15kVo2NXZ+OJ6CeMY8A==",
+      "requires": {
+        "@babel/helper-module-imports": "^7.0.0",
+        "@emotion/hash": "0.7.1",
+        "@emotion/memoize": "0.7.1",
+        "@emotion/serialize": "^0.11.3",
+        "babel-plugin-macros": "^2.0.0",
+        "babel-plugin-syntax-jsx": "^6.18.0",
+        "convert-source-map": "^1.5.0",
+        "escape-string-regexp": "^1.0.5",
+        "find-root": "^1.1.0",
+        "source-map": "^0.5.7"
+      }
+    },
     "babel-plugin-istanbul": {
       "version": "4.1.6",
       "resolved": "http://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
@@ -1995,6 +2092,11 @@
       "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.0.tgz",
       "integrity": "sha512-to6Shd/r8fMRRg/MaOhDNfqpuXfjlQx3ypWDG6jh4ESCVZDJCgdgIalZbrnVlBPGgH/QeyHMjnGb2W+JJiy+NQ=="
     },
+    "babel-plugin-syntax-jsx": {
+      "version": "6.18.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
+      "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
+    },
     "babel-plugin-syntax-object-rest-spread": {
       "version": "6.13.0",
       "resolved": "http://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
@@ -2792,6 +2894,11 @@
         "supports-color": "^5.3.0"
       }
     },
+    "change-emitter": {
+      "version": "0.1.6",
+      "resolved": "https://registry.npmjs.org/change-emitter/-/change-emitter-0.1.6.tgz",
+      "integrity": "sha1-6LL+PX8at9aaMhma/5HqaTFAlRU="
+    },
     "chardet": {
       "version": "0.7.0",
       "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
@@ -3732,6 +3839,11 @@
         "cssom": "0.3.x"
       }
     },
+    "csstype": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.2.tgz",
+      "integrity": "sha512-Rl7PvTae0pflc1YtxtKbiSqq20Ts6vpIYOD5WBafl4y123DyHUeLrRdQP66sQW8/6gmX8jrYJLXwNeMqYVJcow=="
+    },
     "currently-unhandled": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@@ -4088,6 +4200,14 @@
         "utila": "~0.4"
       }
     },
+    "dom-helpers": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
+      "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
+      "requires": {
+        "@babel/runtime": "^7.1.2"
+      }
+    },
     "dom-serializer": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
@@ -4221,6 +4341,14 @@
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
       "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
     },
+    "encoding": {
+      "version": "0.1.12",
+      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
+      "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
+      "requires": {
+        "iconv-lite": "~0.4.13"
+      }
+    },
     "end-of-stream": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
@@ -5193,6 +5321,35 @@
         "bser": "^2.0.0"
       }
     },
+    "fbjs": {
+      "version": "0.8.17",
+      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
+      "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
+      "requires": {
+        "core-js": "^1.0.0",
+        "isomorphic-fetch": "^2.1.1",
+        "loose-envify": "^1.0.0",
+        "object-assign": "^4.1.0",
+        "promise": "^7.1.1",
+        "setimmediate": "^1.0.5",
+        "ua-parser-js": "^0.7.18"
+      },
+      "dependencies": {
+        "core-js": {
+          "version": "1.2.7",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+          "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
+        },
+        "promise": {
+          "version": "7.3.1",
+          "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+          "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+          "requires": {
+            "asap": "~2.0.3"
+          }
+        }
+      }
+    },
     "figgy-pudding": {
       "version": "3.5.1",
       "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz",
@@ -5304,6 +5461,11 @@
         "pkg-dir": "^2.0.0"
       }
     },
+    "find-root": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+      "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
+    },
     "find-up": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
@@ -5674,6 +5836,14 @@
         "map-cache": "^0.2.2"
       }
     },
+    "framesync": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/framesync/-/framesync-4.0.1.tgz",
+      "integrity": "sha512-7dF3SXz/xMdwSHFHgj8PV2dAUCFclXWhasAb06rFvAM2pX24m9eDs6X+ikK0kx92w/uIljUi0sBINwcbl0rT2Q==",
+      "requires": {
+        "hey-listen": "^1.0.5"
+      }
+    },
     "fresh": {
       "version": "0.5.2",
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -6613,6 +6783,11 @@
       "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
       "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
     },
+    "hey-listen": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.5.tgz",
+      "integrity": "sha512-O2iCNxBBGb4hOxL9tUdnoPwDYmZhQ29t5xKV74BVZNdvwCDXCpVYTJ4yoaibc1V0I8Yw3K3nwmvDpoyjnCqUaw=="
+    },
     "history": {
       "version": "4.7.2",
       "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz",
@@ -7624,6 +7799,15 @@
       "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
       "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
     },
+    "isomorphic-fetch": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
+      "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
+      "requires": {
+        "node-fetch": "^1.0.1",
+        "whatwg-fetch": ">=0.10.0"
+      }
+    },
     "isstream": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -9156,6 +9340,15 @@
         "lower-case": "^1.1.1"
       }
     },
+    "node-fetch": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
+      "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
+      "requires": {
+        "encoding": "^0.1.11",
+        "is-stream": "^1.0.1"
+      }
+    },
     "node-forge": {
       "version": "0.7.5",
       "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz",
@@ -13895,6 +14088,27 @@
         "workbox-webpack-plugin": "3.6.3"
       }
     },
+    "react-spinners": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.5.1.tgz",
+      "integrity": "sha512-8MW2565BOoh2VrJNFXDayT0yMw6VPh7xc7UtvY7lX2Ci1V2dvKrjeVBM3ojj8vWrR0pKqY9MyZ9Ehx9wOxi47g==",
+      "requires": {
+        "@emotion/core": "^10.0.4",
+        "prop-types": "^15.5.10",
+        "recompose": "0.27.1 - 0.30.0"
+      }
+    },
+    "react-transition-group": {
+      "version": "2.5.3",
+      "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.3.tgz",
+      "integrity": "sha512-2DGFck6h99kLNr8pOFk+z4Soq3iISydwOFeeEVPjTN6+Y01CmvbWmnN02VuTWyFdnRtIDPe+wy2q6Ui8snBPZg==",
+      "requires": {
+        "dom-helpers": "^3.3.1",
+        "loose-envify": "^1.4.0",
+        "prop-types": "^15.6.2",
+        "react-lifecycles-compat": "^3.0.4"
+      }
+    },
     "read-pkg": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
@@ -14223,6 +14437,26 @@
         "util.promisify": "^1.0.0"
       }
     },
+    "recompose": {
+      "version": "0.30.0",
+      "resolved": "https://registry.npmjs.org/recompose/-/recompose-0.30.0.tgz",
+      "integrity": "sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w==",
+      "requires": {
+        "@babel/runtime": "^7.0.0",
+        "change-emitter": "^0.1.2",
+        "fbjs": "^0.8.1",
+        "hoist-non-react-statics": "^2.3.1",
+        "react-lifecycles-compat": "^3.0.2",
+        "symbol-observable": "^1.0.4"
+      },
+      "dependencies": {
+        "hoist-non-react-statics": {
+          "version": "2.5.5",
+          "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
+          "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
+        }
+      }
+    },
     "recursive-readdir": {
       "version": "2.2.2",
       "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz",
@@ -15899,6 +16133,21 @@
         }
       }
     },
+    "style-value-types": {
+      "version": "3.0.7",
+      "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-3.0.7.tgz",
+      "integrity": "sha512-7vzeicDiPNnJjvTYfJbQhZ7P3OCkXfvkJOJQ+ifFnXNTA/7KBxMZacHLvlRjM5/TtXbVdrZE6u+2nzSUSPrbSQ=="
+    },
+    "stylefire": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/stylefire/-/stylefire-2.4.0.tgz",
+      "integrity": "sha512-soSvx0Xc4If/8EGmU/HrE0HHOOzQ+JEEyhj1xJFfOx5PCIy19veoN588e2QGJfOZJYJeAYQx/YzofbzWCAi6DA==",
+      "requires": {
+        "framesync": "^4.0.0",
+        "hey-listen": "^1.0.4",
+        "style-value-types": "^3.0.6"
+      }
+    },
     "stylehacks": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.1.tgz",
@@ -16376,6 +16625,11 @@
         "typescript-compare": "^0.0.2"
       }
     },
+    "ua-parser-js": {
+      "version": "0.7.19",
+      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz",
+      "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ=="
+    },
     "uglify-js": {
       "version": "3.4.9",
       "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",

+ 4 - 1
package.json

@@ -14,9 +14,12 @@
     "react-router": "^4.3.1",
     "react-router-dom": "^4.3.1",
     "react-scripts": "^2.1.3",
+    "react-spinners": "^0.5.1",
+    "react-transition-group": "^2.5.3",
     "redux": "^4.0.1",
     "redux-form": "^8.1.0",
-    "redux-saga": "^1.0.0"
+    "redux-saga": "^1.0.0",
+    "stylefire": "^2.4.0"
   },
   "scripts": {
     "start": "react-scripts start",

+ 14 - 0
src/actions/admin/changeCategory.js

@@ -0,0 +1,14 @@
+import * as actionTypes from './../../constants/admin';
+
+export const changeCategoryRequest = payload => ({
+    type: actionTypes.CHANGE_CATEGORY_REQUEST,
+    payload
+});
+export const changeCategorySuccess = payload => ({
+    type: actionTypes.CHANGE_CATEGORY_REQUEST_SUCCESS,
+    payload
+});
+export const changeCategoryFailure = error => ({
+    type: actionTypes.CHANGE_CATEGORY_REQUEST_FAILURE,
+    error
+});

+ 14 - 0
src/actions/admin/createCategory.js

@@ -0,0 +1,14 @@
+import * as actionTypes from './../../constants/admin';
+
+export const createCategoryRequest = payload => ({
+    type: actionTypes.CREATE_CATEGORY_REQUEST,
+    payload
+});
+export const createCategorySuccess = payload => ({
+    type: actionTypes.CREATE_CATEGORY_REQUEST_SUCCESS,
+    payload
+});
+export const createCategoryFailure = error => ({
+    type: actionTypes.CREATE_CATEGORY_REQUEST_FAILURE,
+    error
+});

+ 14 - 0
src/actions/admin/deleteCategory.js

@@ -0,0 +1,14 @@
+import * as actionTypes from './../../constants/admin';
+
+export const deleteCategoryRequest = payload => ({
+    type: actionTypes.DELETE_CATEGORY_REQUEST,
+    payload
+});
+export const deleteCategorySuccess = payload => ({
+    type: actionTypes.DELETE_CATEGORY_REQUEST_SUCCESS,
+    payload
+});
+export const deleteCategoryFailure = error => ({
+    type: actionTypes.DELETE_CATEGORY_REQUEST_FAILURE,
+    error
+});

+ 14 - 0
src/actions/admin/getCategory.js

@@ -0,0 +1,14 @@
+import * as actionTypes from './../../constants/admin';
+
+export const getCategoryRequest = payload => ({
+    type: actionTypes.GET_CATEGORY_REQUEST,
+    payload
+});
+export const getCategorySuccess = payload => ({
+    type: actionTypes.GET_CATEGORY_REQUEST_SUCCESS,
+    payload
+});
+export const getCategoryFailure = error => ({
+    type: actionTypes.GET_CATEGORY_REQUEST_FAILURE,
+    error
+});

+ 3 - 0
src/actions/auth/logOut.js

@@ -0,0 +1,3 @@
+export const logOut = () => ({
+    
+})

+ 0 - 0
src/actions/auth/saveToken.js


+ 4 - 7
src/actions/auth/signIn.js

@@ -1,12 +1,9 @@
 import * as actionTypes from './../../constants/auth';
 
-export const signIn = payload => {
-    console.log('Inside the signIn action', payload);
-    return {
-        type: actionTypes.SIGN_IN_REQUEST,
-        payload
-    };
-}
+export const signIn = payload => ({
+    type: actionTypes.SIGN_IN_REQUEST,
+    payload
+});
 export const signInSuccess = payload => ({
     type: actionTypes.SIGN_IN_REQUEST_SUCCESS,
     payload

+ 0 - 0
src/components/admin/CreateTest/index.js


+ 56 - 0
src/components/admin/addDeleteCategory/ChangeCategory.js

@@ -0,0 +1,56 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import { Field, reduxForm } from 'redux-form';
+import formInput from '../../common/formInput'
+import {changeCategoryRequest} from '../../../actions/admin/changeCategory'
+
+
+
+class ChangeCategory extends React.Component {
+
+    submit=({name})=>{
+        const {actions:{changeCategoryRequest}, token, category:{id}} = this.props;
+        console.log(name)
+        changeCategoryRequest({
+            name,
+            id,
+            token
+
+        })
+    }
+
+    
+    
+
+    render() {
+        const {  handleSubmit, changeCategoryRequest, token, category:{id, name} } = this.props;
+        const {submit} = this;
+        console.log("token", token, "name", name, "id", id)
+
+
+       
+        return (
+            
+            <form onSubmin={handleSubmit(submit)}>
+                <Field name="name" type="name" placeholder="Change Category" component={formInput} />
+                <button type="button" className="link link--btn right"  onClick ={
+                        function(){
+                        handleSubmit(submit)();
+                        }                        
+                    }     
+                    >
+                    Search
+                </button>
+            </form >
+            
+        )
+    }
+
+}
+
+
+
+export default reduxForm({
+    form: "changeCategoryForm",
+})(ChangeCategory);

+ 43 - 0
src/components/admin/addDeleteCategory/CreateCategoryForm/index.js

@@ -0,0 +1,43 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { Field, reduxForm } from 'redux-form';
+
+import formInput from '../../..//common/formInput';
+
+class CreateCategoryForm extends React.Component {
+submit =({name})=>{
+    const {actions:{createCategoryRequest}, token}= this.props;
+    createCategoryRequest({
+        name,
+        token
+    })
+}
+    render() {
+        const {  handleSubmit, actions:{createCategoryRequest}, handlers:{onClick}, token } = this.props;
+        const { submit}=this;
+        console.log(token)
+        return (
+            <form onSubmin={handleSubmit(submit)}>
+                <Field name="name" type="name" placeholder="Add new Category" component={formInput} />
+                <button
+                    type="button" className="link link--btn right"  onClick ={
+                        function(){
+
+                        onClick()
+                        handleSubmit(submit)();
+
+                        }
+
+                        
+                    }     
+                    >
+                    Search
+                </button>
+            </form >
+        )
+    }
+}
+
+export default reduxForm({
+    form: "createCategoryForm",
+})(CreateCategoryForm);

+ 40 - 0
src/components/admin/addDeleteCategory/DeleteCategory.js

@@ -0,0 +1,40 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux'
+import {deleteCategoryRequest} from  '../../../actions/admin/deleteCategory';
+
+
+
+class DeleteCategory extends React.Component {
+    state = {
+        ckick:false
+    }
+    onClick = ()=>{
+        const {deleteCategoryRequest,category:{id}, token}=this.props;
+        console.log(id,token)
+        deleteCategoryRequest({
+            id,
+            token
+        })
+    }
+    
+    
+
+    render() {
+const {onClick} = this;
+       
+        return (
+            <div> 
+                <button type="button" className="link link--btn right" onClick={onClick}>Delete</button>
+            </div>
+            
+        )
+    }
+
+}
+
+
+
+const mapDispatchToProps = dispatch => bindActionCreators({deleteCategoryRequest}, dispatch);
+
+export default connect( null, mapDispatchToProps)(DeleteCategory);

+ 94 - 0
src/components/admin/addDeleteCategory/GetCategory.js

@@ -0,0 +1,94 @@
+import React from 'react';
+import { CSSTransition, TransitionGroup } from 'react-transition-group';
+import PropagateLoader from 'react-spinners/PropagateLoader';
+
+import CreateCategoryForm from "./CreateCategoryForm";
+import ChangeCategory from "./ChangeCategory";
+import DeleteCategory from './DeleteCategory';
+
+
+class GetCategory extends React.Component {
+
+    state ={
+        click:false,
+        category:{
+            id:null,
+            names:null
+        }
+    }
+    
+    
+    componentDidMount() {
+        const {actions:{getCategoryRequest}, token} = this.props;
+        console.log("token", token)
+        getCategoryRequest(
+            token
+            )
+            
+        }
+        
+        onClick = ()=>{
+            this.setState((prevState) => ({ click: !prevState.click }));
+            }
+
+        onClicked = ({mass:{_id, name}})=>{
+                this.setState({category:{id:_id,name:name}} )
+            }
+
+
+    render() {
+        const {actions:{ createCategoryRequest, changeCategoryRequest}, token, name} = this.props;
+        const {category:{data, isFetching}} =this.props;
+        console.log(data)
+        const {onClick, onClicked} =this;
+        const {click, category} =this.state;
+       
+        return (
+            <div>
+                <div className ="container w-100 h-auto  bg-stone  bg-mist-border">
+                    {
+                        !isFetching
+                        ?
+                        data&&data.map(mass =>
+                            <div className ="btn ">
+                                <button class="btn btn-secondary font-ci font-ci-bold text-light bg-mist " onClick = {onClicked.bind(null,{mass})} type="button" id={mass.id} key ={mass.id} >
+                                    {mass.name}
+                                </button>
+                            </div>
+                        )
+                        :
+                    <PropagateLoader/>
+                }
+                <div>
+                {
+                    click
+                    ?
+                    <CreateCategoryForm actions ={{createCategoryRequest}} handlers ={{onClick}} token={token}></CreateCategoryForm>
+                    :
+                    name==null
+                    ?
+                    <button onClick = {onClick}>Create Category</button>
+                    :
+                    <React.Fragment>
+                        <p>New Category</p>
+                        <button class="btn btn-secondary font-ci font-ci-bold text-light mx-auto " onClick = {onClick} type="button"  >
+                            {name}
+                        </button>
+                        <button onClick = {onClick}>Create Category</button>
+                    </React.Fragment>
+                }
+                </div>
+
+            </div>
+            <ChangeCategory actions ={{changeCategoryRequest}} token={token} category ={category}></ChangeCategory>
+            <DeleteCategory token={token} category ={category} ></DeleteCategory>
+        </div>
+        )
+    }
+
+}
+
+
+
+
+export default GetCategory;

+ 47 - 0
src/components/admin/addDeleteCategory/index.js

@@ -0,0 +1,47 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux'
+import {createCategoryRequest} from  '../../../actions/admin/createCategory';
+import {changeCategoryRequest} from  '../../../actions/admin/changeCategory';
+import {getCategoryRequest} from '../../../actions/admin/getCategory';
+import GetCategory from './GetCategory'
+
+
+
+class AddDeleteCategory extends React.Component {
+    state = {
+        ckick:false
+    }
+    onClick = ()=>{
+        this.setState((prevState) => ({ click: !prevState.click }));
+    }
+    
+    
+
+    render() {
+        const {signIn:{token}, category, createCategoryRequest, getCategoryRequest, changeCategoryRequest, newCategory:{name}}= this.props
+        const {onClick} = this;
+        console.log("jjjjjjjj", token)
+
+       
+        return (
+            <div> 
+                <GetCategory actions ={{getCategoryRequest,createCategoryRequest, changeCategoryRequest}} token ={token} category = {category} name ={name}></GetCategory>
+            </div>
+            
+        )
+    }
+
+}
+
+const
+    mapStateToProps = state => ({
+        signIn: state.signIn,
+        category:state.category,
+        newCategory:state.newCategory       
+
+    });
+
+const mapDispatchToProps = dispatch => bindActionCreators({createCategoryRequest, getCategoryRequest, changeCategoryRequest}, dispatch);
+
+export default connect(mapStateToProps, mapDispatchToProps)(AddDeleteCategory);

+ 25 - 0
src/components/admin/deleteUser/DeleteUserForm/index.js

@@ -0,0 +1,25 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { Field, reduxForm } from 'redux-form';
+
+import formInput from '../../../common/formInput';
+
+class DeleteUserForm extends React.Component {
+
+    render() {
+        return (
+            <form>
+                <Field name="name" type="name" placeholder="Enter login" component={formInput} />
+                <button
+                    type="button" className="link link--btn right"        
+                    >
+                    Search
+                </button>
+            </form >
+        )
+    }
+}
+
+export default reduxForm({
+    form: "deleteUserForm",
+})(DeleteUserForm);

+ 31 - 0
src/components/admin/deleteUser/index.js

@@ -0,0 +1,31 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux'
+import DeleteUserForm from './DeleteUserForm/index'
+
+
+
+class DeleteUser extends React.Component {
+    
+
+    render() {
+       
+        return (
+            <div> 
+                <input type="file"/>
+                <DeleteUserForm></DeleteUserForm>
+            </div>
+            
+        )
+    }
+
+}
+
+const
+    mapStateToProps = state => ({
+
+    });
+
+const mapDispatchToProps = dispatch => bindActionCreators({}, dispatch);
+
+export default connect(mapStateToProps, mapDispatchToProps)(DeleteUser);

+ 1 - 3
src/components/common/protectedRoute.js

@@ -23,9 +23,7 @@ export default ({ component: Component, user, tokenAuth, access, ...rest }) => (
             } */}
             const checkedData = user && user.data ? user.data : null;
 
-            console.log('Component', Component);
-            console.log('Access', access);
-            console.log('User Data', user);
+            console.log('\n\nHere goes the route:', '\nUser', user, '\n\n\n')
 
             if (access === 'public') {
                 return <Component {...props} />

+ 14 - 15
src/components/public/Header.js

@@ -5,8 +5,8 @@ import * as routes from '../../constants/routes'
 export default class Header extends React.Component {
     render() {
         return (
-            <nav class="navbar navbar-expand-lg navbar-dark bg-dark p-3">
-                <a class="navbar-brand" href="#">Test.io</a>
+            <nav class="navbar navbar-expand-lg bg-mist p-3">
+                <a class="navbar-brand font-po font-po-bold text-shadow " href="#">Test.io</a>
                 <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
                     <span class="navbar-toggler-icon"></span>
                 </button>
@@ -14,23 +14,25 @@ export default class Header extends React.Component {
                 <div class="collapse navbar-collapse" id="navbarSupportedContent">
                     <ul class="navbar-nav mr-auto">
                         <li class="nav-item active">
-                            <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold" to={routes.HOME}>Home <span class="sr-only">(current)</span></Link>
+                            <Link onClick={this.handleClick} class="nav-link text-shadow font-ci font-ci-bold" to={routes.HOME}>Home <span class="sr-only">(current)</span></Link>
                         </li>
                         <li class="nav-item">
-                            <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold" to={routes.PROFILE}>Profile</Link>
+                            <Link onClick={this.handleClick} class="nav-link text-shadow font-ci font-ci-bold" to={routes.PROFILE}>Profile</Link>
                         </li>
                         <li class="nav-item">
-                            <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold " to={routes.TESTS}>Tests</Link>
+                            <Link onClick={this.handleClick} class="nav-link text-shadow font-ci font-ci-bold " to={routes.TESTS}>Tests</Link>
                         </li>
                         <li class="nav-item">
-                            <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold " to={routes.CATEGORIES}>Catigories</Link>
+                            <Link onClick={this.handleClick} class="nav-link text-shadow font-ci font-ci-bold " to={routes.CATEGORIES}>Catigories</Link>
                         </li>
-                        {/* TODO: admin-only ! */}
+                        
                         <li class="nav-item dropdown">
-                            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                                Dropdown
+                            <a class="nav-link dropdown-toggle text-shadow font-ci font-ci-bold" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                                Menu Admina
                                     </a>
                             <div class="dropdown-menu" aria-labelledby="navbarDropdown">
+                                <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold " to={routes.DELETE_USER}>Delete</Link>
+                                <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold " to={routes.CREATE_CATEGORY}><a class="dropdown-item">fffffff</a></Link>
                                 <a class="dropdown-item" href="#">Action</a>
                                 <a class="dropdown-item" href="#">Another action</a>
                                 <div class="dropdown-divider"></div>
@@ -39,16 +41,13 @@ export default class Header extends React.Component {
                         </li>
 
                     </ul>
-                    <form class="form-inline my-2 my-lg-0">
-                        <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" />
-                        <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
-                    </form>
+
                     <div className="pl-2">
                         <Link to={routes.SIGN_IN}>
-                            <button className="btn btn-outline-primary">Sign In</button>
+                            <button className="btn  btn-outline-light bg-stone">Sign In</button>
                         </Link>
                         <Link to={routes.SIGN_UP}>
-                            <button className="btn btn-outline-primary ml-2">Sign Up</button>
+                            <button className="btn  btn-outline-light ml-2 bg-stone">Sign Up</button>
                         </Link>
                     </div>
                 </div>

+ 12 - 13
src/components/public/SignIn/Form/index.js

@@ -1,8 +1,5 @@
 import React from 'react';
 import { reduxForm, Field } from 'redux-form';
-import { connect } from 'react-redux';
-import { bindActionCreators } from 'redux';
-
 import validate from './validate';
 import formInput from './../../../common/formInput';
 
@@ -17,37 +14,39 @@ class Form extends React.Component {
     }
 
     render() {
-        const { handleSubmit, error } = this.props;
-        console.log('Auth error', error);
+        const { handleSubmit, requestError, invalid } = this.props;
+
 
         return (
-            <div className="container">
+            <div className="container mt-5 ">
                 <div className="row">
-                    <div className="col-md-8 col-10 col-lg-6 m-auto p-4 border rounded">
+                    <div className="col-md-8 col-4 col-lg-5 m-auto p-4  border rounded">
+                        <h1 className = "position-absolute pl-5 pr-5 sinein bg-white text-stone">SignIn</h1>
 
                         <form className="text-center" onSubmit={handleSubmit(this.submit)}>
                             {
-                                error
+                                requestError
                                     ?
-                                    <p className="text-af text-uppercase">{error}</p>
+                                    <p className="text-af text-uppercase">{requestError}</p>
                                     :
                                     null
                             }
 
                             <div className="form-group">
-                                <label className="text-uppercase">Email address</label>
+                                <label className="text-uppercase font-ci">Email address</label>
                                 <Field type="email" name='email' className="form-control" placeholder="name@example.com" component={formInput} />
                             </div>
 
                             <div className="form-group">
-                                <label className="text-uppercase">Password</label>
-                                <Field type="password" name='password' className="form-control" placeholder="example123" component={formInput} />
+                                <label className="text-uppercase font-ci">Password</label>
+                                <Field type="password" name='password' className="form-control" component={formInput} />
                             </div>
 
-                            <button type="submit" className="btn btn-primary">Sign In!</button>
+                            <button type="submit" className="btn btn-primary" disabled={invalid}>Sign In!</button>
                         </form>
                     </div>
                 </div>
+                
             </div>
         )
     }

+ 17 - 5
src/components/public/SignIn/index.js

@@ -4,22 +4,34 @@ import { bindActionCreators } from 'redux';
 import { connect } from 'react-redux';
 import { Redirect } from 'react-router-dom'
 
+import PropagateLoader from 'react-spinners/PropagateLoader';
+
 import Spinner from './../../common/spinner';
 import { signIn } from './../../../actions/auth/signIn';
 
-const SignIn = ({ signIn, user }) => (
-    user.isFetching
+const SignIn = ({ signIn, user }) => {
+    const someShit = user.isFetching
         ?
-        <Spinner />
+         <PropagateLoader/>
         : user.data
             ?
             <Redirect to='/' />
             : user.error
                 ?
-                <Form error={user.error} signIn={signIn} />
+                (
+                    <React.Fragment>
+                        <Form signIn={signIn} requestError={user.error} />
+                    </React.Fragment>
+
+                )
                 :
                 <Form signIn={signIn} />
-)
+
+    return someShit
+
+}
+
+
 
 const mapStateToProps = state => ({
     user: state.signIn

+ 63 - 0
src/components/public/SignUp/Form/index.js

@@ -0,0 +1,63 @@
+import React from 'react';
+import { reduxForm, Field } from 'redux-form';
+
+import validate from './validate';
+import formInput from './../../../common/formInput';
+
+class Form extends React.Component {
+
+    submit = ({ name, email, password }) => {
+        const { signUp } = this.props;
+        signUp({
+            name,
+            email,
+            password
+        })
+    }
+
+    render() {
+        const { handleSubmit, requestError, invalid } = this.props;
+
+        return (
+            <div className="container">
+                <div className="row">
+                    <div className="col-md-8 col-10 col-lg-6 m-auto p-4 border rounded">
+
+                        <form className="text-center" onSubmit={handleSubmit(this.submit)}>
+                            {
+                                requestError
+                                    ?
+                                    <p className="text-af text-uppercase">{requestError}</p>
+                                    :
+                                    null
+                            }
+
+                            <div className="form-group border p-4">
+                                <label className="text-uppercase">Name</label>
+                                <Field type="text" name='name' className="form-control" placeholder="example" component={formInput} />
+
+                                <label className="text-uppercase pt-3">Email address</label>
+                                <Field type="email" name='email' className="form-control" placeholder="name@example.com" component={formInput} />
+                            </div>
+
+                            <div className="form-group border p-4">
+                                <label className="text-uppercase">Password</label>
+                                <Field type="password" name='password' className="form-control" component={formInput} />
+
+                                <label className="text-uppercase pt-3">Password Confirmation</label>
+                                <Field type="password" name='passwordConfirmation' className="form-control" component={formInput} />
+                            </div>
+
+                            <button type="submit" className="btn btn-primary" disabled={invalid}>Sign In!</button>
+                        </form>
+                    </div>
+                </div>
+            </div>
+        )
+    }
+}
+
+export default reduxForm({
+    form: "SignUp",
+    validate
+})(Form)

+ 47 - 0
src/components/public/SignUp/Form/validate.js

@@ -0,0 +1,47 @@
+export default function validate(values) {
+    const { name, email, password, passwordConfirmation } = values;
+    const errors = {};
+
+    if (!email) {
+        errors.email = "Required";
+    }
+    else if (email.length < 8 || email.length > 20) {
+        errors.email = "Invalid email length: email should be from 8 to 20 symbols";
+    }
+    else if (
+        !/^(([^<>()\]\\.,;:\s@"]+(\.[^<>()\]\\.,;:\s@"]+)*)|(".+"))@(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(email)) {
+        errors.email = "Invalid email, try another one";
+    }
+
+    if (!name) {
+        errors.name = "Required";
+    }
+    else if (name.length < 6 || name.length > 10) {
+        errors.name = "Invalid name length: name should be from 6 to 10 symbols";
+    }
+    else if (!/^[_A-z0-9]*((-|\s)*[_A-z0-9])*$/.test(name)) {
+        errors.name = "Invalid name, try another one"
+    }
+    
+    if (!password) {
+        errors.password = "Required"
+    }
+    else if (/[,]/.test(password)) {
+        errors.password = "Invalid symbol: \",\" is not allowed!";
+    }
+    else if (password.length < 8 || password.length > 20) {
+        errors.password = "Invalid password length: password should be from 8 to 20 symbols";
+    }
+    else if (!/^[a-z0-9_-]{8,20}$/i.test(password)) {
+        errors.password = "Invalid password, try another one";
+    }
+
+    if (!passwordConfirmation) {
+        errors.passwordConfirmation = "Required";
+    }
+    else if (password !== passwordConfirmation) {
+        errors.passwordConfirmation = "Passwords don't match each other!";
+    }
+
+    return errors;
+}

+ 31 - 0
src/components/public/SignUp/index.js

@@ -0,0 +1,31 @@
+import React from 'react';
+import Form from './Form';
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+import { Redirect } from 'react-router-dom';
+
+import Spinner from './../../common/spinner';
+import { signUp } from './../../../actions/auth/signUp';
+
+const SignUp = ({ status, signUp }) => (
+    status.isFetching
+        ?
+        <Spinner />
+        : status.isSuccessful
+            ?
+            <Redirect to='/sign-in' />
+            : status.error
+                ?
+                <Form signUp={signUp} requestError={status.error} />
+                :
+                <Form signUp={signUp} />
+)
+
+const mapStateToProps = state => ({
+    status: state.signUp
+});
+const mapDispatchToProps = dispatch => bindActionCreators({
+    signUp
+}, dispatch);
+
+export default connect(mapStateToProps, mapDispatchToProps)(SignUp);

+ 1 - 1
src/components/user/ProfilePage/changePassword/index.js

@@ -19,7 +19,7 @@ class ChangePasswordForm extends React.Component {
     }
 
     render() {
-        const { children, handleSubmit, actions:{changePasswordRequest}, handlers: {  handleClicked }, data, token } = this.props;
+        const { children, handleSubmit, actions:{ changePasswordRequest }, handlers: {  handleClicked }, data, token } = this.props;
         const { submit}=this
         console.log( data)
         return (

+ 3 - 22
src/components/user/ProfilePage/index.js

@@ -34,8 +34,8 @@ class ProfilePage extends React.Component {
         const {handleClick, handleClicks, handleClicked} = this;
 
         return (
-            <div className="page page--bottom-only profile-page">
-                <div className="border bg-autumn-foliage m-5 rounded d-flex">
+            <div className="page page--bottom-only profile-page ">
+                <div className="border bg-autumn-foliage m-5 rounded d-flex flex-wrap">
                     <div>
                 {/* <h5 className="p-2 font-po-bold flex-fill bd-highlight align-self-end">{data.name}</h5> */}
                 {/* <div className="d-flex"  >
@@ -109,26 +109,7 @@ class ProfilePage extends React.Component {
                  
                     </div>
                 </div>
-                <section className="container section section--stats">
-                    <div className="section__element section__element--">
-                        <h3>Member Since</h3>
-                        <p>{new Date(data.createdAt).toLocaleString()}</p>
-                    </div>
-                    <div className="section__element section__element--comments border-right-0">
-                        <h3>Last comments</h3>
-                        <p className="comments-block">
-                            {
-                                data.comments && data.comments
-                                    .slice(0, 60)
-                                    .map(el =>
-                                        <p>
-                                            <h4>{new Date(el.createdAt).toLocaleString()}</h4>
-                                            {el.text}
-                                        </p>)
-                            }
-                        </p>
-                    </div>
-                </section>
+                
                 </div>
             
         )

+ 12 - 5
src/configs/routerConfig.js

@@ -1,10 +1,12 @@
 import React, { lazy } from 'react';
 import * as routes from './../constants/routes';
 
-const ProfilePage =lazy(()=> import('../components/user/ProfilePage'))
-
+const ProfilePage = lazy(() => import('../components/user/ProfilePage'));
+const DeleteUser = lazy(()=>import('../components/admin/deleteUser/index'));
+const AddDeleteCategory = lazy(()=> import('../components/admin/addDeleteCategory'))
 // import SignIn from '../components/public/SignIn';
-const SignIn = lazy(() => import('./../components/public/SignIn'))
+const SignIn = lazy(() => import('./../components/public/SignIn'));
+const SignUp = lazy(() => import('./../components/public/SignUp'));
 
 export default [
     {
@@ -20,7 +22,7 @@ export default [
     {
         path: routes.SIGN_UP,
         access: 'public',
-        component: () => <div>sign up</div>
+        component: SignUp
     },
     {
         path: routes.HOME,
@@ -45,7 +47,12 @@ export default [
     {
         path: routes.DELETE_USER,
         access: 'admin-only',
-        component: () => <div>delete user</div>
+        component: DeleteUser
+    },
+    {
+        path: routes.CREATE_CATEGORY,
+        access: 'public',
+        component: AddDeleteCategory
     },
     {
         access: 'public',

+ 17 - 0
src/constants/admin.js

@@ -0,0 +1,17 @@
+export const CREATE_CATEGORY = "https://test-app-a-level.herokuapp.com/category" 
+export const CREATE_CATEGORY_REQUEST = 'CREATE_CATEGORY_REQUEST';
+export const CREATE_CATEGORY_REQUEST_SUCCESS = 'CREATE_CATEGORY_REQUEST_SUCCESS';
+export const CREATE_CATEGORY_REQUEST_FAILURE = 'CREATE_CATEGORY_REQUEST_FAILURE';
+
+export const GET_CATEGORY_REQUEST = 'GET_CATEGORY_REQUEST';
+export const GET_CATEGORY_REQUEST_SUCCESS = 'GET_CATEGORY_REQUEST_SUCCESS';
+export const GET_CATEGORY_REQUEST_FAILURE = 'GET_CATEGORY_REQUEST_FAILURE';
+
+
+export const CHANGE_CATEGORY_REQUEST = 'CHANGE_CATEGORY_REQUEST';
+export const CHANGE_CATEGORY_REQUEST_SUCCESS = 'CHANGE_CATEGORY_REQUEST_SUCCESS';
+export const CHANGE_CATEGORY_REQUEST_FAILURE = 'CHANGE_CATEGORY_REQUEST_FAILURE';
+
+export const DELETE_CATEGORY_REQUEST = 'DELETE_CATEGORY_REQUEST';
+export const DELETE_CATEGORY_REQUEST_SUCCESS = 'DELETE_CATEGORY_REQUEST_SUCCESS';
+export const DELETE_CATEGORY_REQUEST_FAILURE = 'DELETE_CATEGORY_REQUEST_FAILURE';

+ 1 - 1
src/constants/auth.js

@@ -3,7 +3,7 @@ export const SIGN_IN_REQUEST = 'SIGN_IN_REQUEST';
 export const SIGN_IN_REQUEST_SUCCESS = 'SIGN_IN_REQUEST_SUCCESS';
 export const SIGN_IN_REQUEST_FAILURE = 'SIGN_IN_REQUEST_FAILURE';
 
-export const SIGN_UP_URL = '';
+export const SIGN_UP_URL = 'https://test-app-a-level.herokuapp.com/auth/register';
 export const SIGN_UP_REQUEST = 'SIGN_UP_REQUEST';
 export const SIGN_UP_REQUEST_SUCCESS = 'SIGN_UP_REQUEST_SUCCESS';
 export const SIGN_UP_REQUEST_FAILURE = 'SIGN_UP_REQUEST_FAILURE';

+ 35 - 0
src/reducers/admin/changeCategory.js

@@ -0,0 +1,35 @@
+import * as actionTypes from '../../constants/admin';
+import initialState from './../initialState';
+
+export default function changeCategory(state = initialState.newCategory, {payload, type, error}) {
+
+    switch (type) { // payload.type -> type
+        case actionTypes.CREATE_CATEGORY_REQUEST: {
+            return {
+                ...state,
+                isFetching: true,
+                payload
+            }
+        }
+        case actionTypes.CREATE_CATEGORY_REQUEST_SUCCESS: {
+            const { name } = payload;
+
+            return {
+                ...state,
+                isFetching: false,
+                name: name,
+            }
+        }
+        case actionTypes.GET_CATEGORY_REQUEST_FAILURE: {
+
+            return {
+                ...state,
+                isFetching: false,
+                error
+            }
+        }
+        default: {
+            return state;
+        }
+    }
+}

+ 34 - 0
src/reducers/admin/getCategory.js

@@ -0,0 +1,34 @@
+import * as actionTypes from '../../constants/admin';
+import initialState from './../initialState';
+
+export default function getCategory(state = initialState.category, {payload, type, error}) {
+
+    switch (type) { // payload.type -> type
+        case actionTypes.GET_CATEGORY_REQUEST: {
+            return {
+                ...state,
+                isFetching: true
+            }
+        }
+        case actionTypes.GET_CATEGORY_REQUEST_SUCCESS: {
+            const { category } = payload;
+
+            return {
+                ...state,
+                isFetching: false,
+                data: category,
+            }
+        }
+        case actionTypes.GET_CATEGORY_REQUEST_FAILURE: {
+
+            return {
+                ...state,
+                isFetching: false,
+                error
+            }
+        }
+        default: {
+            return state;
+        }
+    }
+}

+ 34 - 0
src/reducers/admin/index.js

@@ -0,0 +1,34 @@
+// import * as actionTypes from './../../constants/auth';
+// import initialState from './../initialState';
+
+// export default function createCategoryReducer(state = initialState.categ, {type, payload, error}) {
+//     switch(type) {
+//         case actionTypes.SIGN_UP_REQUEST: {
+//             return {
+//                 ...state,
+//                 isFetching: true
+//             }
+//         }
+        
+//         case actionTypes.SIGN_UP_REQUEST_SUCCESS: {
+//             return {
+//                 ...state,
+//                 isFetching: false,
+//                 isSuccessful: true
+//             }
+//         }
+
+//         case actionTypes.SIGN_UP_REQUEST_FAILURE: {
+//             return {
+//                 ...state,
+//                 isFetching: false,
+//                 isSuccessful: false,
+//                 error
+//             }
+//         }
+
+//         default: {
+//             return state;
+//         }
+//     }
+// }

+ 3 - 3
src/reducers/auth/signIn.js

@@ -1,8 +1,9 @@
 import * as actionTypes from './../../constants/auth';
 import initialState from './../initialState';
 
-export default function signInReducer(state = initialState.signIn, { payload, token, type }) {
-    switch (type) {
+export default function signInReducer(state = initialState.signIn, {payload, type, error}) {
+
+    switch (type) { // payload.type -> type
         case actionTypes.SIGN_IN_REQUEST: {
             return {
                 ...state,
@@ -20,7 +21,6 @@ export default function signInReducer(state = initialState.signIn, { payload, to
             }
         }
         case actionTypes.SIGN_IN_REQUEST_FAILURE: {
-            const { error } = payload;
 
             return {
                 ...state,

+ 8 - 4
src/reducers/auth/signUp.js

@@ -3,26 +3,30 @@ import initialState from './../initialState';
 
 export default function signInReducer(state = initialState.signUp, {type, payload, error}) {
     switch(type) {
-        case actionTypes.SIGN_IN_REQUEST: {
+        case actionTypes.SIGN_UP_REQUEST: {
             return {
                 ...state,
                 isFetching: true
             }
         }
-        case actionTypes.SIGN_IN_REQUEST_SUCCESS: {
+        
+        case actionTypes.SIGN_UP_REQUEST_SUCCESS: {
             return {
                 ...state,
                 isFetching: false,
-                payload
+                isSuccessful: true
             }
         }
-        case actionTypes.SIGN_IN_REQUEST_FAILURE: {
+
+        case actionTypes.SIGN_UP_REQUEST_FAILURE: {
             return {
                 ...state,
                 isFetching: false,
+                isSuccessful: false,
                 error
             }
         }
+
         default: {
             return state;
         }

+ 9 - 1
src/reducers/index.js

@@ -2,13 +2,21 @@ import { combineReducers } from 'redux';
 import { reducer as form } from 'redux-form';
 
 import signIn from './auth/signIn';
+import signUp from './auth/signUp';
+
+import category from './admin/getCategory';
+import newCategory from './admin/changeCategory';
+
 import chageLoginReducer from './user/chageLogin';
 import changeEmailReducer from './user/changeEmail';
 
 export default combineReducers({
 
     signIn,
+    signUp,
     chageLoginReducer,
     changeEmailReducer,
-    form
+    form,
+    category,
+    newCategory
 })

+ 12 - 1
src/reducers/initialState.js

@@ -7,7 +7,7 @@ export default {
     },
     signUp: {
         isFetching: false,
-        data: null,
+        isSuccessful: null,
         error: null
     },
     changeLogin:{
@@ -20,4 +20,15 @@ export default {
         data: null,
         error: null
     },
+    category:{
+    data:null,
+    isFetching:false,
+    error:null
+},
+newCategory:{
+    name:null,
+    isFetching:false,
+    error:null
+}
+
 }

+ 0 - 2
src/router.js

@@ -13,8 +13,6 @@ import { bindActionCreators } from "redux";
 class Router extends React.Component {
     render() {
         const { user, tokenAuth } = this.props;
-        console.log(user);
-
         // TODO: add footer
         return (
             <div className="app">

+ 29 - 0
src/sagas/admin/changeCategory.js

@@ -0,0 +1,29 @@
+import { put, call } from 'redux-saga/effects';
+import axios from 'axios';
+
+import { CREATE_CATEGORY } from './../../constants/admin';
+import { changeCategorySuccess, changeCategoryFailure } from './../../actions/admin/changeCategory'
+
+export default function* ({payload:{id,name ,token}}) {
+    console.log('User inside the worker-saga', name, "token", token, 'id', id );
+    try {
+        const config = {
+            headers: {
+                "Content-Type": "application/json",
+                "Authorization": `Bearer ${token}`
+            }
+        }
+
+        const user = yield call(() =>
+            axios.put(`${CREATE_CATEGORY}${'/'}${id}`,{
+                id,
+                name}, config)
+                .then(({ data }) => data)
+        )
+
+        yield put(changeCategorySuccess(user));
+    }
+    catch ({ message }) {
+        yield put(changeCategoryFailure(message));
+    }
+}

+ 28 - 0
src/sagas/admin/createCategory.js

@@ -0,0 +1,28 @@
+import { put, call } from 'redux-saga/effects';
+import axios from 'axios';
+
+import { CREATE_CATEGORY } from './../../constants/admin';
+import { createCategorySuccess, createCategoryFailure } from './../../actions/admin/createCategory'
+
+export default function* ({payload:{name,token}}) {
+    console.log('User inside the worker-saga', name, token);
+    try {
+        const config = {
+            headers: {
+                "Content-Type": "application/json",
+                "Authorization": `Bearer ${token}`
+            }
+        }
+
+        const user = yield call(() =>
+            axios.post(CREATE_CATEGORY,{
+                name}, config)
+                .then(({ data }) => data)
+        )
+
+        yield put(createCategorySuccess(user));
+    }
+    catch ({ message }) {
+        yield put(createCategoryFailure(message));
+    }
+}

+ 26 - 0
src/sagas/admin/deleteCategory.js

@@ -0,0 +1,26 @@
+import { put, call } from 'redux-saga/effects';
+import axios from 'axios';
+
+import { CREATE_CATEGORY } from './../../constants/admin';
+import { deleteCategorySuccess, deleteCategoryFailure } from './../../actions/admin/deleteCategory';
+
+export default function* ({payload:{id,token}}) {
+    console.log('User inside the worker-saga', "token", token, 'id', id );
+    try {
+        const config = {
+            headers: {
+                "Authorization": `Bearer ${token}`
+            }
+        }
+
+        const user = yield call(() =>
+            axios.delete(`${CREATE_CATEGORY}${'/'}${id}`, config)
+                .then(({ data }) => data)
+        )
+
+        yield put(deleteCategorySuccess(user));
+    }
+    catch ({ message }) {
+        yield put(deleteCategoryFailure(message));
+    }
+}

+ 27 - 0
src/sagas/admin/getCategory.js

@@ -0,0 +1,27 @@
+import { put, call } from 'redux-saga/effects';
+import axios from 'axios';
+
+import { CREATE_CATEGORY } from './../../constants/admin';
+import { getCategorySuccess, getCategoryFailure } from './../../actions/admin/getCategory'
+
+export default function* ({payload}) {
+    console.log('User inside the worker-saga', payload);
+    try {
+        const config = {
+            headers: {
+                "Content-Type": "application/json",
+                "Authorization": `Bearer ${payload}`
+            }
+        }
+
+        const user = yield call(() =>
+            axios.get(CREATE_CATEGORY, config)
+                .then(({ data }) => data)
+        )
+
+        yield put(getCategorySuccess(user));
+    }
+    catch ({ message }) {
+        yield put(getCategoryFailure(message));
+    }
+}

+ 18 - 0
src/sagas/admin/index.js

@@ -0,0 +1,18 @@
+import createCategory from './createCategory';
+import getCategory from './getCategory';
+import * as actionTypes from './../../constants/admin';
+
+import { takeEvery } from 'redux-saga/effects';
+import changeCategory from './changeCategory';
+import deleteCategory from './deleteCategory';
+
+export default function* () {
+    yield takeEvery(actionTypes.CREATE_CATEGORY_REQUEST, createCategory);
+    yield takeEvery(actionTypes.GET_CATEGORY_REQUEST, getCategory);
+    yield takeEvery(actionTypes.CHANGE_CATEGORY_REQUEST, changeCategory);
+    yield takeEvery(actionTypes.DELETE_CATEGORY_REQUEST, deleteCategory);
+
+
+
+
+}

+ 4 - 2
src/sagas/auth/signIn.js

@@ -2,10 +2,10 @@ import { put, call } from 'redux-saga/effects';
 import axios from 'axios';
 
 import { SIGN_IN_URL } from './../../constants/auth';
+import storageKey from './../../utils/storageKey';
 import { signInSuccess, signInFailure } from './../../actions/auth/signIn'
 
-export default function* ({payload}) {
-    console.log('User inside the worker-saga', payload);
+export default function* ({ payload }) {
     try {
         const config = {
             headers: {
@@ -18,6 +18,8 @@ export default function* ({payload}) {
                 .then(({ data }) => data)
         )
 
+        // TODO: TOKEN
+        // yield call(localStorage.setItem, storageKey, user.token);
         yield put(signInSuccess(user));
     }
     catch ({ message }) {

+ 24 - 2
src/sagas/auth/signUp.js

@@ -1,3 +1,25 @@
-export default function* () {
-    
+import { put, call } from 'redux-saga/effects';
+import axios from 'axios';
+
+import { SIGN_UP_URL } from './../../constants/auth';
+import { signUpSuccess, signUpFailure } from './../../actions/auth/signUp';
+
+export default function* ({payload}) {
+    try {
+        const config = {
+            headers: {
+                "Content-Type": "application/json"
+            }
+        }
+
+        const report = yield call(() =>
+            axios.post(SIGN_UP_URL, payload, config)
+                .then(({ data }) => data)
+        )
+
+        yield put(signUpSuccess(report));
+    }
+    catch ({ message }) {
+        yield put(signUpFailure(message));
+    }
 }

+ 2 - 0
src/sagas/index.js

@@ -1,8 +1,10 @@
 import { fork } from "redux-saga/effects";
 import auth from './auth'
 import user from './user/index'
+import admin from './admin/index'
 
 export default function*() {
     yield fork(user);
     yield fork(auth);
+    yield fork(admin);
 }

+ 2 - 0
src/styles/_index.scss

@@ -1,4 +1,6 @@
 @import 'abstracts/variables';
 @import 'abstracts/theme';
+@import 'extended/vh';
+@import './style/styles';
 
 @import 'base/typography';

+ 14 - 0
src/styles/abstracts/_theme.scss

@@ -1,16 +1,24 @@
 .bg {
     &-stone {
         background: $color-stone !important;
+    
     }
     &-shadow {
         background: $color-shadow !important;
+        
     }
     &-mist {
         background: $color-mist !important;
+            &-border{
+            border:solid;
+            border-color: $color-mist
+        }
     }
     &-af {
         background: $color-autumn-foliage !important;
     }
+
+
 }
 .text {
     &-stone {
@@ -25,4 +33,10 @@
     &-af {
         color: $color-autumn-foliage !important;
     }
+}
+
+.opacity{
+    &-opacity{
+        opacity:0.3
+    }
 }

+ 14 - 0
src/styles/extended/_vh.scss

@@ -0,0 +1,14 @@
+.vh {
+    &-100 {
+        height: 100vh;
+    }
+    &-75 {
+        height: 75vh;
+    }
+    &-50 {
+        height: 50vh;
+    }
+    &-25 {
+        height: 25vh;
+    }
+}

+ 5 - 0
src/styles/style/_styles.scss

@@ -0,0 +1,5 @@
+.sinein{
+    position: absolute;
+    right: 20px;
+    top: -30px;
+}

+ 1 - 0
src/utils/storageKey.js

@@ -0,0 +1 @@
+export default 'https://test.io';