anton123 1 jaar geleden
bovenliggende
commit
f4991940b1

+ 286 - 0
package-lock.json

@@ -1408,11 +1408,144 @@
         "tslib": "^2.0.0"
       }
     },
+    "@emotion/babel-plugin": {
+      "version": "11.10.5",
+      "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz",
+      "integrity": "sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==",
+      "requires": {
+        "@babel/helper-module-imports": "^7.16.7",
+        "@babel/plugin-syntax-jsx": "^7.17.12",
+        "@babel/runtime": "^7.18.3",
+        "@emotion/hash": "^0.9.0",
+        "@emotion/memoize": "^0.8.0",
+        "@emotion/serialize": "^1.1.1",
+        "babel-plugin-macros": "^3.1.0",
+        "convert-source-map": "^1.5.0",
+        "escape-string-regexp": "^4.0.0",
+        "find-root": "^1.1.0",
+        "source-map": "^0.5.7",
+        "stylis": "4.1.3"
+      },
+      "dependencies": {
+        "@emotion/hash": {
+          "version": "0.9.0",
+          "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz",
+          "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ=="
+        },
+        "escape-string-regexp": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+          "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
+        }
+      }
+    },
+    "@emotion/cache": {
+      "version": "11.10.5",
+      "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz",
+      "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==",
+      "requires": {
+        "@emotion/memoize": "^0.8.0",
+        "@emotion/sheet": "^1.2.1",
+        "@emotion/utils": "^1.2.0",
+        "@emotion/weak-memoize": "^0.3.0",
+        "stylis": "4.1.3"
+      }
+    },
     "@emotion/hash": {
       "version": "0.8.0",
       "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz",
       "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="
     },
+    "@emotion/is-prop-valid": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz",
+      "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==",
+      "requires": {
+        "@emotion/memoize": "^0.8.0"
+      }
+    },
+    "@emotion/memoize": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz",
+      "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA=="
+    },
+    "@emotion/react": {
+      "version": "11.10.5",
+      "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.5.tgz",
+      "integrity": "sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==",
+      "requires": {
+        "@babel/runtime": "^7.18.3",
+        "@emotion/babel-plugin": "^11.10.5",
+        "@emotion/cache": "^11.10.5",
+        "@emotion/serialize": "^1.1.1",
+        "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
+        "@emotion/utils": "^1.2.0",
+        "@emotion/weak-memoize": "^0.3.0",
+        "hoist-non-react-statics": "^3.3.1"
+      }
+    },
+    "@emotion/serialize": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz",
+      "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==",
+      "requires": {
+        "@emotion/hash": "^0.9.0",
+        "@emotion/memoize": "^0.8.0",
+        "@emotion/unitless": "^0.8.0",
+        "@emotion/utils": "^1.2.0",
+        "csstype": "^3.0.2"
+      },
+      "dependencies": {
+        "@emotion/hash": {
+          "version": "0.9.0",
+          "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz",
+          "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ=="
+        }
+      }
+    },
+    "@emotion/sheet": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz",
+      "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA=="
+    },
+    "@emotion/styled": {
+      "version": "11.10.5",
+      "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.5.tgz",
+      "integrity": "sha512-8EP6dD7dMkdku2foLoruPCNkRevzdcBaY6q0l0OsbyJK+x8D9HWjX27ARiSIKNF634hY9Zdoedh8bJCiva8yZw==",
+      "requires": {
+        "@babel/runtime": "^7.18.3",
+        "@emotion/babel-plugin": "^11.10.5",
+        "@emotion/is-prop-valid": "^1.2.0",
+        "@emotion/serialize": "^1.1.1",
+        "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
+        "@emotion/utils": "^1.2.0"
+      }
+    },
+    "@emotion/unitless": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz",
+      "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw=="
+    },
+    "@emotion/use-insertion-effect-with-fallbacks": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz",
+      "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A=="
+    },
+    "@emotion/utils": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz",
+      "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw=="
+    },
+    "@emotion/weak-memoize": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz",
+      "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg=="
+    },
     "@eslint/eslintrc": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz",
@@ -2065,6 +2198,18 @@
         "@babel/runtime": "^7.4.4"
       }
     },
+    "@material-ui/lab": {
+      "version": "4.0.0-alpha.61",
+      "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.61.tgz",
+      "integrity": "sha512-rSzm+XKiNUjKegj8bzt5+pygZeckNLOr+IjykH8sYdVk7dE9y2ZuUSofiMV2bJk3qU+JHwexmw+q0RyNZB9ugg==",
+      "requires": {
+        "@babel/runtime": "^7.4.4",
+        "@material-ui/utils": "^4.11.3",
+        "clsx": "^1.0.4",
+        "prop-types": "^15.7.2",
+        "react-is": "^16.8.0 || ^17.0.0"
+      }
+    },
     "@material-ui/styles": {
       "version": "4.11.5",
       "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz",
@@ -2128,6 +2273,119 @@
         "react-is": "^16.8.0 || ^17.0.0"
       }
     },
+    "@mui/base": {
+      "version": "5.0.0-alpha.115",
+      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.115.tgz",
+      "integrity": "sha512-OGQ84whT/yNYd6xKCGGS6MxqEfjVjk5esXM7HP6bB2Rim7QICUapxZt4nm8q39fpT08rNDkv3xPVqDDwRdRg1g==",
+      "requires": {
+        "@babel/runtime": "^7.20.7",
+        "@emotion/is-prop-valid": "^1.2.0",
+        "@mui/types": "^7.2.3",
+        "@mui/utils": "^5.11.2",
+        "@popperjs/core": "^2.11.6",
+        "clsx": "^1.2.1",
+        "prop-types": "^15.8.1",
+        "react-is": "^18.2.0"
+      },
+      "dependencies": {
+        "react-is": {
+          "version": "18.2.0",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+          "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+        }
+      }
+    },
+    "@mui/core-downloads-tracker": {
+      "version": "5.11.6",
+      "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.6.tgz",
+      "integrity": "sha512-lbD3qdafBOf2dlqKhOcVRxaPAujX+9UlPC6v8iMugMeAXe0TCgU3QbGXY3zrJsu6ex64WYDpH4y1+WOOBmWMuA=="
+    },
+    "@mui/material": {
+      "version": "5.11.6",
+      "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.6.tgz",
+      "integrity": "sha512-MzkkL5KC2PCkFiv8cLpkzgLUPXSrAtnvJBR0emV7mLVWbkwV3n5832vjBx154B6R032fHjFTziTh7YEb50nK6Q==",
+      "requires": {
+        "@babel/runtime": "^7.20.7",
+        "@mui/base": "5.0.0-alpha.115",
+        "@mui/core-downloads-tracker": "^5.11.6",
+        "@mui/system": "^5.11.5",
+        "@mui/types": "^7.2.3",
+        "@mui/utils": "^5.11.2",
+        "@types/react-transition-group": "^4.4.5",
+        "clsx": "^1.2.1",
+        "csstype": "^3.1.1",
+        "prop-types": "^15.8.1",
+        "react-is": "^18.2.0",
+        "react-transition-group": "^4.4.5"
+      },
+      "dependencies": {
+        "react-is": {
+          "version": "18.2.0",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+          "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+        }
+      }
+    },
+    "@mui/private-theming": {
+      "version": "5.11.2",
+      "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.2.tgz",
+      "integrity": "sha512-qZwMaqRFPwlYmqwVKblKBGKtIjJRAj3nsvX93pOmatsXyorW7N/0IPE/swPgz1VwChXhHO75DwBEx8tB+aRMNg==",
+      "requires": {
+        "@babel/runtime": "^7.20.7",
+        "@mui/utils": "^5.11.2",
+        "prop-types": "^15.8.1"
+      }
+    },
+    "@mui/styled-engine": {
+      "version": "5.11.0",
+      "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.0.tgz",
+      "integrity": "sha512-AF06K60Zc58qf0f7X+Y/QjaHaZq16znliLnGc9iVrV/+s8Ln/FCoeNuFvhlCbZZQ5WQcJvcy59zp0nXrklGGPQ==",
+      "requires": {
+        "@babel/runtime": "^7.20.6",
+        "@emotion/cache": "^11.10.5",
+        "csstype": "^3.1.1",
+        "prop-types": "^15.8.1"
+      }
+    },
+    "@mui/system": {
+      "version": "5.11.5",
+      "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.5.tgz",
+      "integrity": "sha512-KNVsJ0sgRRp2XBqhh4wPS5aacteqjwxgiYTVwVnll2fgkgunZKo3DsDiGMrFlCg25ZHA3Ax58txWGE9w58zp0w==",
+      "requires": {
+        "@babel/runtime": "^7.20.7",
+        "@mui/private-theming": "^5.11.2",
+        "@mui/styled-engine": "^5.11.0",
+        "@mui/types": "^7.2.3",
+        "@mui/utils": "^5.11.2",
+        "clsx": "^1.2.1",
+        "csstype": "^3.1.1",
+        "prop-types": "^15.8.1"
+      }
+    },
+    "@mui/types": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.3.tgz",
+      "integrity": "sha512-tZ+CQggbe9Ol7e/Fs5RcKwg/woU+o8DCtOnccX6KmbBc7YrfqMYEYuaIcXHuhpT880QwNkZZ3wQwvtlDFA2yOw=="
+    },
+    "@mui/utils": {
+      "version": "5.11.2",
+      "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.2.tgz",
+      "integrity": "sha512-AyizuHHlGdAtH5hOOXBW3kriuIwUIKUIgg0P7LzMvzf6jPhoQbENYqY6zJqfoZ7fAWMNNYT8mgN5EftNGzwE2w==",
+      "requires": {
+        "@babel/runtime": "^7.20.7",
+        "@types/prop-types": "^15.7.5",
+        "@types/react-is": "^16.7.1 || ^17.0.0",
+        "prop-types": "^15.8.1",
+        "react-is": "^18.2.0"
+      },
+      "dependencies": {
+        "react-is": {
+          "version": "18.2.0",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+          "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+        }
+      }
+    },
     "@nicolo-ribaudo/eslint-scope-5-internals": {
       "version": "5.1.1-v1",
       "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz",
@@ -2191,6 +2449,11 @@
         "source-map": "^0.7.3"
       }
     },
+    "@popperjs/core": {
+      "version": "2.11.6",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
+      "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
+    },
     "@rollup/plugin-babel": {
       "version": "5.3.1",
       "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -2967,6 +3230,14 @@
         "@types/react": "*"
       }
     },
+    "@types/react-is": {
+      "version": "17.0.3",
+      "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-17.0.3.tgz",
+      "integrity": "sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==",
+      "requires": {
+        "@types/react": "*"
+      }
+    },
     "@types/react-transition-group": {
       "version": "4.4.5",
       "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -5895,6 +6166,11 @@
         "pkg-dir": "^4.1.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": "5.0.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -10315,6 +10591,11 @@
       "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
       "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
     },
+    "react-mui-pagination": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/react-mui-pagination/-/react-mui-pagination-1.1.0.tgz",
+      "integrity": "sha512-BEDEbgefo3YN3emEZCzLZF7YqFB8Wws6siHD/FlPGekmNRkH3KKs3U07AkdpkNhqjVF7venUEUDvPUS0xMiHMQ=="
+    },
     "react-redux": {
       "version": "8.0.5",
       "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
@@ -11298,6 +11579,11 @@
         "postcss-selector-parser": "^6.0.4"
       }
     },
+    "stylis": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz",
+      "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA=="
+    },
     "supports-color": {
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",

+ 5 - 0
package.json

@@ -5,8 +5,12 @@
   "dependencies": {
     "@dnd-kit/core": "^6.0.7",
     "@dnd-kit/sortable": "^7.0.2",
+    "@emotion/react": "^11.10.5",
+    "@emotion/styled": "^11.10.5",
     "@material-ui/core": "^4.12.4",
     "@material-ui/icons": "^4.11.3",
+    "@material-ui/lab": "^4.0.0-alpha.61",
+    "@mui/material": "^5.11.6",
     "@testing-library/jest-dom": "^5.16.5",
     "@testing-library/react": "^13.4.0",
     "@testing-library/user-event": "^13.5.0",
@@ -14,6 +18,7 @@
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
     "react-dropzone": "^14.2.3",
+    "react-mui-pagination": "^1.1.0",
     "react-redux": "^8.0.5",
     "react-router-dom": "^5.3.0",
     "react-scripts": "5.0.1",

+ 41 - 268
src/App.js

@@ -1,18 +1,19 @@
 import {createStore, combineReducers, applyMiddleware} from 'redux';
 import thunk from 'redux-thunk';
-import {Provider, connect} from 'react-redux';
+import {Provider} from 'react-redux';
 import {Router, Route} from 'react-router-dom';
 import React from 'react';
 import './App.scss';
 import SignIn from './components/signIn';
 import SignUp from './components/signup';
-import MyProfile from './components/myprofile';
-import CreateAd from './components/add';
-import Good from './components/good';
-import Cards from './components/goods'
-import CardsUser from './components/productsUser';
-import Header from './components/header'
-import Message from './components/message'
+import Profile from './components/myprofile';
+import CreateAdConnect from './components/add';
+import GoodUser from './components/good';
+import MainList from './components/goods'
+import AllProductsUser from './components/productsUser';
+import HeaderConnect from './components/header'
+import Messages from './components/message'
+import ChangeAdConnect from './components/changeAd'
 const history = require("history").createBrowserHistory()
 
 const getGQL = url =>
@@ -48,20 +49,20 @@ const checkToken = () => {
   }
 }
 
-
-const url = 'http://marketplace.node.ed.asmer.org.ua/'
-const gql = getGQL(url + 'graphql')
+const defaultAvatar = "http://marketplace.node.ed.asmer.org.ua/images/744eed7a2030edd908ef3c59cc9405ce"
+const origUrl = "http://marketplace.node.ed.asmer.org.ua/"
+const gql = getGQL(origUrl + 'graphql')
 
 const actionPromise = (namePromise,promise) =>
     async dispatch => { 
-        dispatch(actionPending(namePromise)) //сигнализируем redux, что промис начался
+        dispatch(actionPending(namePromise))
         try{
-            const payload = await promise //ожидаем промиса
-            dispatch(actionFulfilled(namePromise,payload)) //сигнализируем redux, что промис успешно выполнен
-            return payload //в месте запуска store.dispatch с этим thunk можно так же получить результат промиса
+            const payload = await promise 
+            dispatch(actionFulfilled(namePromise,payload)) 
+            return payload 
         }
         catch (error){
-            dispatch(actionRejected(namePromise,error)) //в случае ошибки - сигнализируем redux, что промис несложился
+            dispatch(actionRejected(namePromise,error))
         }
     }
 
@@ -80,209 +81,6 @@ function promiseReducer(state={}, {type, status, payload, error,namePromise}){
 }
 
 
-const actionUpload = (files) =>
-	async (dispatch) => {
-		const formData = new FormData();
-		formData.append('photo', files);
-		await dispatch(actionUploadFile(formData));
-	}
-
-
-  const actionUploadFile = formData =>
-	actionPromise('upload',
-		fetch(`${url}upload`, {
-			method: "POST",
-			headers: localStorage.authToken ? {Authorization: 'Bearer ' + localStorage.authToken} : {},
-			body: formData
-		}).then(res => res.json())
-	);
-
-
-const actionlist = () => 
-actionPromise('list', gql(`query list{
-  AdFind(query:"[{}]") {
-    price 
-    _id 
-    owner {
-      _id 
-      login 
-      nick 
-      avatar {
-        _id 
-        url
-        }
-    }
-    title 
-    description 
-    images {
-      _id 
-      url
-    }
-  }
-}`))
-
-
-
-const actionOnelist = (_id) => 
-actionPromise('onelist', gql(`query onelist($q: String!) {
-    AdFindOne(query:$q) {
-      price _id owner {
-                  _id login nick avatar {
-                    _id url
-                  }
-      }
-      title description images {
-        _id url
-      }
-      comments {
-                  _id owner {
-                    _id login nick avatar {
-                      _id url
-                    }
-                  }
-                  createdAt
-                  text
-                  answerTo {
-                    _id
-                  }
-      }
-    }
-  }`,{q: JSON.stringify([{_id}])}
-)) 
-
-
-const actionLogin = (login, password) =>
-actionPromise('login', gql(`query Login($login: String!, $password: String!) {
-     login(login: $login, password: $password)
-   }`, {login, password}));
-
-
-const actionRegister = (login, password) => 
-actionPromise('reg', gql(`mutation Reg($login: String!, $password: String!) {
-     createUser(login: $login, password: $password) {
-       _id
-     }
-   }`, 
-{"login" : login,
-"password": password}
-))
-
-const actionUpdateMe = (user) =>
-    actionPromise('profile', gql(`mutation upsertProfile($user:UserInput) {
-                                        UserUpsert(user:$user) {
-                                            _id login nick
-                                        }
-                                    }`, {user}))
-
-
-
-const actioCreateAd = (ad) =>
-actionPromise('createAd', gql(`mutation userAd($ad:AdInput) {
-  AdUpsert(ad: $ad) {
-      _id title images{
-          _id url
-      }
-  }
-}`, {ad}))
-
-
-const actionOneUser = (_id) =>
-actionPromise('user', gql(`query userOne($qq: String!){
-  UserFindOne(query:$qq){
-    _id
-    login
-   phones
-   addresses
-   nick 
-   incomings{
-    _id text createdAt  owner{
-      _id login
-    }
-   }
-   avatar{
-      url
-    }
-  }
-}`, {qq: JSON.stringify([{_id}])}))
-
-
-
-
-
-const actionAdComment = (comment) =>
-actionPromise('adComment', gql(`mutation adComment($comment:CommentInput) {
-  CommentUpsert(comment: $comment) {
-    _id
-    text owner {
-      _id login nick 
-    }
-  }
-}`, {comment}))
-
-
-const actionAdMessage = (message) =>
-actionPromise('admessage', gql(`mutation admessage($message:MessageInput) {
-  MessageUpsert(message: $message) {
-    _id
-    text
-    createdAt
-    to{
-      _id login
-    }
-    owner{
-      _id
-      login
-      nick
-    }
-  }
-}`, {message}))
-
-
-const actionAllProductsUser = (_id) =>
-actionPromise("productsUser", gql(`query productsUser($userId: String) {
-                AdFind(query: $userId) {
-                  price _id owner {
-                                      _id login nick avatar {
-                                        _id url
-                                      }
-                                    }
-                                    title description images {
-                                      _id url
-                                    }
-                }
-              }`, {userId: JSON.stringify([{___owner: _id}])}));
-
-
-const actionMyUserMessage = (_id) => 
-actionPromise('allMeMessage', gql(`query allMeMessage($userId: String){
-  MessageFind(query: $userId){
-    _id
-  text
-  createdAt
-  to{
-    _id login
-  }
-  owner{
-    _id
-    login
-    nick
-  }
-  }
-}`, {userId: JSON.stringify([{___owner: _id}])}));
-
-
-const actionForMeMessage = (_id) =>
-actionPromise('allForMeMessage', gql(`query forMeMessage($qq: String!){
-  UserFindOne(query:$qq){
-   incomings{
-    _id text createdAt  owner{
-      _id login
-    }
-   }
-  }
-}`, {qq: JSON.stringify([{_id}])}))
-
-
 
 const store = createStore(combineReducers({auth: authReducer, promise:localStoredReducer(promiseReducer, 'promise')}), applyMiddleware(thunk))
 store.subscribe(() => console.log(store.getState()))
@@ -349,42 +147,8 @@ const actionAuthLogin = (token) =>
 
 
 
-const origUrl = "http://marketplace.node.ed.asmer.org.ua/"
-const defaultImg = "https://www.lionstroy.ru/published/publicdata/U70619SHOP/attachments/SC/products_pictures/nophoto.png"
-
-const mainList = connect(state => ({
-  cats: state.promise?.list?.payload, 
-  stat: state.promise?.list?.status
-}),
-{loadData: actionlist})(Cards)
-
-const goodUser = connect(state => ({
-  good: state.promise?.onelist?.payload||[],
-  myUser: state.promise?.user?.payload||[]}),{
-    loadData: actionOnelist, 
-    data:actionOneUser} )(Good)
-
-const Profile = connect(state => ({
-  myUser: state.promise?.user?.payload||[]}),
-  {loadData: actionOneUser} )(MyProfile)
-
-const Messages = connect(state => ({
-  myMessage: state.promise?.allMeMessage?.payload, 
-  forMeMessage: state.promise?.allForMeMessage?.payload?.incomings||[],
-  myNewMessage: state.promise?.admessage?.payload||[]}),{
-    loadData: actionMyUserMessage, 
-    dataMyUser:actionForMeMessage,
-    sendMessage:actionAdMessage} )(Message)
-
-const AllProductsUser = connect(state => ({
-  productsUser: state.promise?.productsUser?.payload||[], 
-  stat: state.promise?.list?.status||[]}),
-  {loadData: actionAllProductsUser} )(CardsUser)
-
-const CreateAdConnect = connect(state => ({
-  newImg: state.promise?.upload?.payload||[]}),
-  {action: actionUpload} )(CreateAd)
 
+const defaultImg = "https://www.lionstroy.ru/published/publicdata/U70619SHOP/attachments/SC/products_pictures/nophoto.png"
 
 
 store.dispatch(actionAuthLogin(localStorage.authToken))
@@ -396,24 +160,33 @@ function App() {
   return (
   <Router history = {history}>
     <Provider store={store}>
-    <Route path="/sign_in" component={SignIn} exact/>
-    <Route path="/sign_up" component={SignUp} exact/>
-    <Route path="/my_profile" component={Profile} exact/>
-    <Route path="/create_ad" component={CreateAdConnect} exact/>
-    <Header/>
-      <main className="mainHome" style={{ backgroundColor: '#EEEFF1' }}>
-        <main  className="mainCard">
-        <Route path="/message" component={Messages} exact/>
-        <Route path="/all_products_user" component={AllProductsUser} exact/>
-        <Route path="/" component={mainList} exact/>
-        <Route path="/good/:_id" component={goodUser} exact/>
-        </main>
-      </main>
+      <HeaderConnect/>
+      <Route path="/sign_in" component={SignIn} exact/>
+      <Route path="/sign_up" component={SignUp} exact/>
+      <Route path="/my_profile" component={Profile} exact/>
+      <Route path="/create_ad" component={CreateAdConnect} exact/>
+      <Route path="/change/:_id" component={ChangeAdConnect} exact/>
+      <Route path="/page/:_id" component={MainList} exact/>
+      <Route path="/message" component={Messages} exact/>
+      <Route path="/all_products_user" component={AllProductsUser} exact/>
+      <Route path="/page/:page/good/:_id" component={GoodUser} exact/>
+      <Route path="/good/:_id" component={GoodUser} exact/>
     </Provider>
   </Router>
   );
 }
 
-export {actionLogin,actionPromise, store, origUrl,defaultImg,actionUpload, actionOneUser,actionlist, actionAuthLogout,actionAdMessage, actionOnelist,actionAdComment, actioCreateAd, actionAuthLogin, actionRegister, mainList, history, actionUpdateMe, jwtDecode} 
+export {
+    store, 
+    defaultAvatar,  
+    origUrl,
+    defaultImg, 
+    actionAuthLogout, 
+    actionAuthLogin,
+    history,  
+    jwtDecode,
+    actionPromise,
+    gql
+  } 
 
 export default App;

+ 31 - 25
src/App.scss

@@ -37,14 +37,11 @@
   }
 }
 
-.mainCard{
-  margin-left: 10%;
-  margin-right: 10%;
-}
+
 
 .mainHome{
   background-color: #EEEFF1;
-  padding: 26px;
+  padding-top: 26px;
 }
 
 
@@ -61,26 +58,6 @@
   width: 100%;
 }
 
-.commentCard{
-  margin: 3%;
-  width: 50%;
-}
-
-.commentCardSend{
-  display: flex;
-  flex-direction: column;
-  align-items: flex-start;
-  margin: 3%;
-  padding: 10px;
-  width: 50%;
-}
-
-.messageCardSend{
-  display: flex;
-  padding: 10px;
-  align-items: center;
-}
-
 .commentAvatar{
   display: flex;
   align-items: center;
@@ -93,4 +70,33 @@
 .comment{
   padding-left: 4%;
   padding-bottom: 4%;
+}
+
+
+@media only screen and (min-width: 650px) {
+	.mainHome{
+    background-color: #EEEFF1;
+    padding-top: 26px;
+  }
+}
+
+@media only screen and (min-width: 868px) {
+	.mainHome{
+    background-color: #EEEFF1;
+    padding-top: 26px;
+  }
+}
+
+@media only screen and (min-width: 1100px) {
+	.mainHome{
+    background-color: #EEEFF1;
+    padding-left: 26px;
+    padding-right: 26px;
+    padding-top: 26px;
+  }
+
+  .mainCard{
+    margin-left: 5%;
+    margin-right: 5%;
+  }
 }

+ 264 - 0
src/actions/index.js

@@ -0,0 +1,264 @@
+import {actionPromise, gql,origUrl} from '../App';
+
+
+const actionUpload = (files) =>
+	async (dispatch) => {
+		const formData = new FormData();
+		formData.append('photo', files);
+		await dispatch(actionUploadFile(formData));
+	}
+
+
+  const actionUploadFile = formData =>
+	actionPromise('upload',
+		fetch(`${origUrl}upload`, {
+			method: "POST",
+			headers: localStorage.authToken ? {Authorization: 'Bearer ' + localStorage.authToken} : {},
+			body: formData
+		}).then(res => res.json())
+	);
+
+
+const actionlistCount = () => 
+  actionPromise('listCount', gql(`query listCount{
+    AdCount(query:"[{}]") }`))
+
+
+const actionOnelist = (_id) => 
+actionPromise('onelist', gql(`query onelist($q: String!) {
+    AdFindOne(query:$q) {
+      price _id createdAt owner {
+                  _id login nick avatar {
+                    _id url
+                  }
+      }
+      title description images {
+        _id url
+      }
+      comments {
+                  _id owner {
+                    _id login nick avatar {
+                      _id url
+                    }
+                  }
+                  createdAt
+                  text
+                  answerTo {
+                    _id
+                  }
+      }
+    }
+  }`,{q: JSON.stringify([{_id}])}
+)) 
+
+
+const actionLogin = (login, password) =>
+actionPromise('login', gql(`query Login($login: String!, $password: String!) {
+     login(login: $login, password: $password)
+   }`, {login, password}));
+
+
+const actionRegister = (login, password) => 
+actionPromise('reg', gql(`mutation Reg($login: String!, $password: String!) {
+     createUser(login: $login, password: $password) {
+       _id
+     }
+   }`, 
+{"login" : login,
+"password": password}
+))
+
+const actionUpdateMe = (user) =>
+    actionPromise('profile', gql(`mutation upsertProfile($user:UserInput) {
+                                        UserUpsert(user:$user) {
+                                            _id login nick
+                                        }
+                                    }`, {user}))
+
+
+
+const actioCreateAd = (ad) =>
+actionPromise('createAd', gql(`mutation userAd($ad:AdInput) {
+  AdUpsert(ad: $ad) {
+      _id title images{
+          _id url
+      }
+  }
+}`, {ad}))
+
+
+const actionOneUser = (_id) =>
+actionPromise('user', gql(`query userOne($qq: String!){
+  UserFindOne(query:$qq){
+    _id
+    login
+   phones
+   addresses
+   nick 
+   incomings{
+    _id text createdAt  owner{
+      _id login
+    }
+   }
+   avatar{
+      url _id
+    }
+  }
+}`, {qq: JSON.stringify([{_id}])}))
+
+
+
+const actionAdComment = (comment) =>
+actionPromise('adComment', gql(`mutation adComment($comment:CommentInput) {
+  CommentUpsert(comment: $comment) {
+    _id
+    text owner {
+      _id login nick 
+    }
+  }
+}`, {comment}))
+
+
+const actionAdMessage = (message) =>
+actionPromise('admessage', gql(`mutation admessage($message:MessageInput) {
+  MessageUpsert(message: $message) {
+    _id
+    text
+    createdAt
+    to{
+      _id login
+    }
+    owner{
+      _id
+      login
+      nick
+    }
+  }
+}`, {message}))
+
+
+const actionAllProductsUser = (_id) =>
+actionPromise("productsUser", gql(`query productsUser($userId: String) {
+                AdFind(query: $userId) {
+                  price _id owner {
+                                      _id login nick avatar {
+                                        _id url
+                                      }
+                                    }
+                                    title description images {
+                                      _id url
+                                    }
+                }
+              }`, {userId: JSON.stringify([{___owner: _id}])}));
+
+
+const actionMyUserMessage = (_id) => 
+actionPromise('allMeMessage', gql(`query allMeMessage($userId: String){
+  MessageFind(query: $userId){
+    _id
+  text
+  createdAt
+  to{
+    _id login avatar {_id url}
+  }
+  owner{
+    _id
+    login
+    nick
+  }
+  }
+}`, {userId: JSON.stringify([{___owner: _id}])}));
+
+
+const actionForMeMessage = (_id) =>
+actionPromise('allForMeMessage', gql(`query forMeMessage($qq: String!){
+  UserFindOne(query:$qq){
+   incomings{
+    _id text createdAt  owner{
+      _id login avatar {_id url}
+    }
+   }
+  }
+}`, {qq: JSON.stringify([{_id}])}))
+
+
+const actionList = (skip = 0, limit=15) =>
+    actionPromise('list', gql(`query List($query: String) {
+					  AdFind(query:$query) {
+					    price _id owner {
+                          _id login nick avatar {
+                            _id url
+                          }
+					    }
+					    title description createdAt images {
+					      _id url
+					    }
+					  }
+					}`, {query: JSON.stringify([
+                            {
+                                $or: [{}]
+                            },
+                            {
+                              sort: [{_id: -1}],
+                                limit: [limit],
+                                skip: [skip]
+                            }
+                        ])}
+    ));
+
+
+const actionListSearch = (searchText = '', skip = 0, limit=15) =>
+actionPromise('list', gql(`query searchList($query: String) {
+        AdFind(query:$query) {
+          price _id owner {
+                      _id login nick avatar {
+                        _id url
+                      }
+          }
+          title description createdAt images {
+            _id url
+          }
+        }
+      }`, {query: JSON.stringify([
+                        {
+                            $or: [{title: `/${searchText}/`}, {description: `/${searchText}/`}]
+                        },
+                        {
+                          sort: [{_id: -1}],
+                            limit: [limit],
+                            skip: [skip]
+                        }
+                    ])}
+));
+
+
+
+const actionSearchCount = (searchText = '') =>
+actionPromise('listCount', gql(`query searchCount($query: String) {
+        AdCount(query:$query)}`, 
+        {query: JSON.stringify([
+                        {
+                            $or: [{title: `/${searchText}/`}, {description: `/${searchText}/`}]
+                        }
+                    ])}
+));
+
+
+export {
+    actionAllProductsUser,
+    actionMyUserMessage,
+    actionForMeMessage,
+    actionList,
+    actionListSearch,
+    actionSearchCount,
+    actionlistCount,
+    actionLogin,
+    actionUpload,
+    actionOneUser,
+    actionAdMessage, 
+    actionOnelist,
+    actionAdComment, 
+    actioCreateAd,
+    actionRegister, 
+    actionUpdateMe,
+  } 

+ 31 - 3
src/components/add/Add.scss

@@ -19,8 +19,7 @@
     margin-top: 20px;
     margin-left: 78px;
 }
-.bannerr {
-    width: 50%;
+.textBox {
     display: flex;
     flex-direction: column;
     margin: 3%;
@@ -58,6 +57,35 @@
     transition: border .24s ease-in-out;
 }
 
-.imd__flex__boxx{
+.containerSection{
     display: flex;
+    flex-direction: column;
+    font-family: sans-serif;
+}
+
+@media only screen and (min-width: 650px) {
+	.textBox {
+        width: 50%;
+        display: flex;
+        flex-direction: column;
+        margin: 3%;
+    }
+}
+
+@media only screen and (min-width: 868px) {
+	.textBox {
+        width: 50%;
+        display: flex;
+        flex-direction: column;
+        margin: 3%;
+    }
+}
+
+@media only screen and (min-width: 1100px) {
+	.textBox {
+        width: 50%;
+        display: flex;
+        flex-direction: column;
+        margin: 3%;
+    }
 }

+ 117 - 105
src/components/add/index.js

@@ -5,7 +5,7 @@ import { makeStyles } from '@material-ui/core/styles';
 import './Add.scss';
 import {useState, useEffect} from "react";
 import {useDispatch, useSelector} from "react-redux";
-import {actioCreateAd,origUrl} from '../../App.js';
+import {origUrl,history} from '../../App.js';
 import AddCircleIcon from '@material-ui/icons/AddCircle';
 import {useDropzone} from 'react-dropzone';
 import {
@@ -18,6 +18,8 @@ import {
 import { sortableKeyboardCoordinates, rectSortingStrategy, SortableContext, useSortable, horizontalListSortingStrategy  } from "@dnd-kit/sortable";
 import { CSS } from "@dnd-kit/utilities";
 import {arrayMoveImmutable} from 'array-move';
+import {connect} from 'react-redux';
+import {actionUpload,actioCreateAd} from '../../actions';
 
 
 const SortableItem = (props) => {
@@ -85,7 +87,12 @@ function Dnd({items:startItems,render, itemProp, keyField, onChange, horizontal}
       });
   }
 
-  const containerStyle = { display: horizontal ? "flex" : '' };
+  const containerStyle = { 
+    display: horizontal ? "flex" : '',
+    flexWrap: "wrap",
+    marginBottom: "30px",
+    justifyContent: "center",
+  };
 
 return (
   <DndContext
@@ -104,64 +111,24 @@ return (
 }
 
 
-const ImgBox = ({imgArr})=>{
-
+const ImgBox = ({image, onDelete})=>{
   const useStyles = makeStyles((theme) => ({
     img:{
       borderRadius: "8px",
-      width: '100%'
+      width: '100%',
+      height: '100%',
+      margin: '5px',
+      maxWidth: '200px',
     }
   }));
   const classes = useStyles();
 
   return(<>
-        <img className={classes.img} src={origUrl+imgArr.url}/>
+        {image!== undefined && <img className={classes.img} src={origUrl+image.url} onClick={() => onDelete(image)}/>}
         </>
   )
 }
 
- function CreateAd({action, newImg}) {
-  const dispatch = useDispatch();
-  const {acceptedFiles, getRootProps, getInputProps} = useDropzone();
-  const [imgArr, setImgArr] = useState([]);
-  const [sortImgArr, setSortImgArr] = useState([]);
-  const [createAd, setCreateAd] = useState({ title:'', description:'', price:0});
-  const [sortOldImgArr, setOldSortImgArr] = useState([]);
-
-  useEffect(() => {
-    acceptedFiles.map(file =>action(file));
-  }, [acceptedFiles]);
-
-useEffect(() => {
-  if(JSON.stringify(newImg) !== JSON.stringify(sortOldImgArr)){
-    if(imgArr.length>0){
-    setImgArr([...imgArr,...[newImg]])
-    setOldSortImgArr(newImg)
-    }else{
-      setImgArr([newImg])
-      setOldSortImgArr(newImg)
-    }
-  }
-}, [newImg]);
-
-
-useEffect(() => {
-  setImgArr([])
-},[])
-
-
-
-
-const onclickCreate = ()=>{
-  if(sortImgArr.length>0){
-    let arrIdImg = sortImgArr.map((el)=> el={_id:el._id})
-    dispatch(actioCreateAd({images:arrIdImg,...createAd, tags: [''], address: owner.address}))
-  }else{
-    dispatch(actioCreateAd({...createAd, tags: [''], address: owner.address}))
-  }
-}
-
-  
 const useStyles = makeStyles((theme) => ({
   root: {
     height: '50vh',
@@ -183,69 +150,111 @@ const useStyles = makeStyles((theme) => ({
     margin: theme.spacing(3, 0, 2),
   },
 }));
-const owner = useSelector(state => state.promise?.user?.payload)
-  const classes = useStyles();
+
+
+  
+function CreateAd({action, newImg}) {
+  const classes = useStyles()
+  const dispatch = useDispatch();
+  const {acceptedFiles, getRootProps, getInputProps} = useDropzone();
+  const [createAd, setCreateAd] = useState({ title:'', description:'', price:0});
+  const [create, setCreate] = useState('');
+  console.log(create)
+
+  useEffect(() => {
+    if(newImg){
+      console.log(newImg)
+      if(newImg._id){
+        if(createAd.images){
+          setCreateAd({...createAd,images: [...createAd.images, newImg]})
+          console.log(createAd)
+        }else{
+          setCreateAd({...createAd,images: [newImg]})
+        }
+      }
+    }
+  }, [newImg]);
+  
+  useEffect(() => {
+    setCreateAd({images:[], title:'', description:'', price:0})
+  },[])
+
+  useEffect(() => {
+    acceptedFiles.map(file =>action(file));
+  }, [acceptedFiles]);
+
+
+
+  const deleteImage     = image => setCreateAd({...createAd, images: createAd.images.filter(i => i !== image)})
+  const localPostImage  = ({image}) => <ImgBox image={image} 
+                                                   onDelete={imgToDelete => deleteImage(imgToDelete)}/>
+
+  const onclickCreate = ()=>{
+    if(create.images.length>0){
+      let arrIdImg = create.images.map((el)=> el={_id:el._id})
+      console.log(arrIdImg)
+      dispatch(actioCreateAd({...createAd,images: arrIdImg, tags: ['']}))
+    }else{
+      dispatch(actioCreateAd({...createAd, tags: ['']}))
+    }
+    setCreateAd({ title:'', description:'', price:0})
+    history.push("/page/1")
+  }
+
 
   return (
     <main className="mainAdd">
-        <div className="bannerAdd" >
+      <div className="bannerAdd" >
+          <div className="imd__flex__boxx">
+            <Dnd items={createAd.images||[]} render={localPostImage} itemProp="image" keyField="_id"
+                onChange={newArray=>setCreate({...createAd,images: newArray})}
+                horizontal/>
+          </div>
           <div className="conteiner">
             <div className="flex__boxx">
-              <div className="imd__flex__boxx">
-                <Dnd items={imgArr.filter((el)=>el._id)} render={ImgBox} itemProp="imgArr" keyField="_id"
-                    onChange={newArray=>setSortImgArr(newArray)} //ставлю место консоль лога это: setSortImgArr(newArray)
+              <section className="containerSection">
+                <div {...getRootProps({className: 'dropzone'})}>
+                  <input {...getInputProps()} />
+                  <p>Drag 'n' drop some files here, or click to select files</p>
+                </div>
+              </section>
+              <div className="textBox">
+                  <TextField 
+                  type='number'
+                  value={createAd.price}
+                  onChange={(e) => setCreateAd({...createAd, price: +(e.target.value)})}
+                    className={classes.input} 
+                    required id="standard-required" 
+                    label="Price $" 
                     />
+                  <TextField
+                  value={createAd.title}
+                  onChange={(e) => setCreateAd({...createAd, title: e.target.value})} 
+                    className={classes.input} 
+                    required id="standard-required" 
+                    label="Title"  
+                    />
+                  <TextField 
+                  value={createAd.description}
+                  onChange={(e) => setCreateAd({...createAd, description: e.target.value})}
+                    id="outlined-multiline-static"
+                    label="Description"
+                    multiline
+                    rows={4}
+                    variant="outlined"
+                  />
+                  <Button
+                  onClick={onclickCreate}
+                  type="submit"
+                  fullWidth
+                  variant="contained"
+                  color="primary"
+                  className={classes.submit}
+                  startIcon={<AddCircleIcon/>}
+                  >
+                  create ad
+                  </Button>
               </div>
-            <section className="container">
-              <div {...getRootProps({className: 'dropzone'})}>
-                <input {...getInputProps()} />
-                <p>Drag 'n' drop some files here, or click to select files</p>
-              </div>
-              <aside>
-                <h4>Files</h4>
-              </aside>
-            </section>
-          
-                
-              <div className="bannerr">
-              <TextField 
-              type='number'
-              value={createAd.price}
-              onChange={(e) => setCreateAd({...createAd, price: +(e.target.value)})}
-                className={classes.input} 
-                required id="standard-required" 
-                label="Price $" 
-                />
-              <TextField
-              value={createAd.title}
-              onChange={(e) => setCreateAd({...createAd, title: e.target.value})} 
-                className={classes.input} 
-                required id="standard-required" 
-                label="Title"  
-                />
-              <TextField 
-              value={createAd.description}
-              onChange={(e) => setCreateAd({...createAd, description: e.target.value})}
-                id="outlined-multiline-static"
-                label="Description"
-                multiline
-                rows={4}
-                variant="outlined"
-              />
-              <Button
-              onClick={onclickCreate}
-              type="submit"
-              fullWidth
-              variant="contained"
-              color="primary"
-              className={classes.submit}
-              startIcon={<AddCircleIcon/>}
-            >
-              create ad
-            </Button>
-              </div>
-                
-               
             </div>
           </div>
         </div>
@@ -253,6 +262,9 @@ const owner = useSelector(state => state.promise?.user?.payload)
   );
 }
 
+const CreateAdConnect = connect(state => ({
+  newImg: state.promise?.upload?.payload||[]}),
+  {action: actionUpload} )(CreateAd)
 
 
-export default CreateAd
+export default CreateAdConnect

+ 110 - 0
src/components/changeAd/change.scss

@@ -0,0 +1,110 @@
+.mainChange {
+    background-color: #EEEFF1;
+    display: flex;
+    flex-direction: column;
+}
+.bannerChange {
+    margin: 85px 20px 0px 20px;
+}
+.conteiner__images__pc {
+    margin-top: 20px;
+    margin-left: 78px;
+}
+.flex__box__dnd {
+    display: flex;
+    flex-direction: column;
+}
+.conteiner__images__pc {
+    margin-top: 20px;
+    margin-left: 78px;
+}
+.banneText {
+    display: flex;
+    flex-direction: column;
+    margin: 3%;
+}
+.banner-link-wrap {
+    min-width: 225px;
+    height: 55px;  
+}
+.buttonPhoto{
+    margin: 20px;
+}
+
+.img{
+    border-radius: 8px;
+    box-shadow: 0.4em 0.4em 5px rgba(122,122,122,0.5);
+}
+
+.inputText{
+    margin-bottom: 3%;
+}
+
+.dropzone {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 20px;
+    border-width: 2px;
+    border-radius: 2px;
+    border-color: #eeeeee;
+    border-style: dashed;
+    background-color: #fafafa;
+    color: #bdbdbd;
+    outline: none;
+    transition: border .24s ease-in-out;
+}
+
+
+
+
+.containerSection{
+    display: flex;
+    flex-direction: column;
+    font-family: sans-serif;
+}
+
+
+@media only screen and (min-width: 650px) {
+	.banneText {
+        width: 50%;
+        display: flex;
+        flex-direction: column;
+        margin: 3%;
+    }
+
+    .flex__box__dnd {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+    }
+}
+
+@media only screen and (min-width: 868px) {
+	.banneText {
+        width: 50%;
+        display: flex;
+        flex-direction: column;
+        margin: 3%;
+    }
+    .flex__box__dnd {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+    }
+}
+
+@media only screen and (min-width: 1100px) {
+	.banneText {
+        width: 50%;
+        display: flex;
+        flex-direction: column;
+        margin: 3%;
+    }
+    .flex__box__dnd {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+    }
+}

+ 290 - 0
src/components/changeAd/index.js

@@ -0,0 +1,290 @@
+import React from 'react';
+import { useParams} from 'react-router-dom';
+import Button from '@material-ui/core/Button';
+import TextField from '@material-ui/core/TextField';
+import { makeStyles } from '@material-ui/core/styles';
+import './change.scss';
+import {useState, useEffect} from "react";
+import {useDispatch, useSelector} from "react-redux";
+import {origUrl,history} from '../../App.js';
+import CreateIcon from '@material-ui/icons/Create';
+import {useDropzone} from 'react-dropzone';
+import {
+  DndContext,
+  KeyboardSensor,
+  PointerSensor,
+  useSensor,
+  useSensors, useDroppable
+} from "@dnd-kit/core";
+import { sortableKeyboardCoordinates, rectSortingStrategy, SortableContext, useSortable, horizontalListSortingStrategy  } from "@dnd-kit/sortable";
+import { CSS } from "@dnd-kit/utilities";
+import {arrayMoveImmutable} from 'array-move';
+import {connect} from 'react-redux';
+import {actionUpload,actionOnelist,actioCreateAd} from '../../actions'; 
+
+const SortableItem = (props) => {
+  const {
+    attributes,
+    listeners,
+    setNodeRef,
+    transform,
+    transition
+  } = useSortable({ id: props.id });
+
+  const itemStyle = {
+    transform: CSS.Transform.toString(transform),
+    transition,
+    cursor: "grab",
+  };
+    
+    const Render = props.render
+
+  return (
+    <div style={itemStyle} ref={setNodeRef} {...attributes} {...listeners}>
+      <Render {...{[props.itemProp]:props.item}}/>
+    </div>
+  );
+};
+
+const Droppable = ({ id, items, itemProp, keyField, render }) => {
+  const { setNodeRef } = useDroppable({ id });
+
+  return (
+    <SortableContext id={id} items={items} strategy={rectSortingStrategy}>
+        {items.map((item) => (
+          <SortableItem render={render} key={item[keyField]} id={item} 
+                        itemProp={itemProp} item={item}/>
+        ))}
+    </SortableContext>
+  );
+};
+
+function Dnd({items:startItems,render, itemProp, keyField, onChange, horizontal}) {
+  const [items, setItems] = useState(
+      startItems
+  );
+  useEffect(() => setItems(startItems), [startItems])
+
+  useEffect(() => {
+      if (typeof onChange === 'function'){
+          onChange(items)
+      }
+  },[items])
+
+  const sensors = useSensors(
+      useSensor(PointerSensor,  { activationConstraint: { distance: 5 } }),
+      useSensor(KeyboardSensor, {
+          coordinateGetter: sortableKeyboardCoordinates
+      })
+  );
+
+  const handleDragEnd = ({ active, over }) => {
+      const activeIndex = active.data.current.sortable.index;
+      const overIndex = over.data.current?.sortable.index || 0;
+
+      setItems((items) => {
+          return arrayMoveImmutable( items, activeIndex, overIndex)
+      });
+  }
+
+  const containerStyle = { 
+    display: horizontal ? "flex" : '',
+    flexWrap: "wrap",
+    marginBottom: "30px",
+    justifyContent: "center",
+    margin: "30px"
+  };
+
+return (
+  <DndContext
+    sensors={sensors}
+    onDragEnd={handleDragEnd}
+  >
+    <div style={containerStyle}>
+        <Droppable id="aaa" 
+                   items={items} 
+                   itemProp={itemProp} 
+                   keyField={keyField} 
+                   render={render}/>
+    </div>
+  </DndContext>
+);
+}
+
+
+const ImgBox = ({image, onDelete})=>{
+  const useStyles = makeStyles((theme) => ({
+    img:{
+      borderRadius: "8px",
+      width: '100%',
+      height: '100%',
+      margin: '5px',
+      maxWidth: '200px',
+    }
+  }));
+  const classes = useStyles();
+
+  return(<>
+        {image!== undefined && <img className={classes.img} src={origUrl+image.url} onClick={() => onDelete(image)}/>}
+        </>
+  )
+}
+
+const useStyles = makeStyles((theme) => ({
+  root: {
+    height: '50vh',
+  },
+  paper: {
+    margin: theme.spacing(8, 4),
+    display: 'flex',
+    flexDirection: 'column',
+    alignItems: 'center',
+  },
+  input:{
+    marginBottom: '3%'
+  },
+  form: {
+    width: '100%', // Fix IE 11 issue.
+    marginTop: theme.spacing(1),
+  },
+  submit: {
+    margin: theme.spacing(3, 0, 2),
+  },
+}));
+
+
+  
+function ChangeAd({action,oneGood, newImg, good}) {
+  const {_id} = useParams()
+  const classes = useStyles();
+  const owner = useSelector(state => state.promise?.user?.payload)
+  const dispatch = useDispatch();
+  const {acceptedFiles, getRootProps, getInputProps} = useDropzone();
+  const [createAd, setCreateAd] = useState({ title:'', description:'', price:0});
+  const [create, setCreate] = useState('');
+  console.log(_id)
+
+  console.log(good)
+
+  useEffect(() => {
+    if(newImg){
+      console.log(newImg)
+      if(newImg._id){
+        if(createAd.images){
+          setCreateAd({...createAd,images: [...createAd.images, newImg]})
+          console.log(createAd)
+        }else{
+          setCreateAd({...createAd,images: [newImg]})
+        }
+      }
+    }
+  }, [newImg]);
+  
+  useEffect(() => {
+    setCreateAd({images:[], title:'', description:'', price:0})
+  },[])
+
+  useEffect(() => {
+    acceptedFiles.map(file =>action(file));
+  }, [acceptedFiles]);
+
+  useEffect(() => {
+    oneGood(_id)
+  },[_id])
+
+
+  useEffect(() => {
+    if(good!==[]){
+      if(good.images){
+        setCreateAd({images:good.images, title:good.title, description:good.description, price:good.price})
+      }else{
+        setCreateAd({images:[], title:good.title, description:good.description, price:good.price})
+      }
+      
+    }
+  },[good])
+
+  const deleteImage     = image => setCreateAd({...createAd, images: createAd.images.filter(i => i !== image)})
+  const localPostImage  = ({image}) => <ImgBox image={image} 
+                                                   onDelete={imgToDelete => deleteImage(imgToDelete)}/>
+
+  const onclickCreate = ()=>{
+    if(create.images.length>0){
+      let arrIdImg = create.images.map((el)=> el={_id:el._id})
+      console.log(arrIdImg)
+      dispatch(actioCreateAd({...createAd, _id:good._id, images: arrIdImg, tags: ['']}))
+    }else{
+      dispatch(actioCreateAd({...createAd,  _id:good._id, tags: ['']}))
+    }
+    history.push("/all_products_user")
+  }
+
+
+  return (<>
+    <main className="mainChange">
+      <div className="bannerChange" >
+          <div className="imd__flex">
+            <Dnd items={createAd.images||[]} render={localPostImage} itemProp="image" keyField="_id"
+                onChange={newArray=>setCreate({...createAd,images: newArray})}
+                horizontal/>
+          </div>
+          <div className="conteiner">
+            <div className="flex__box__dnd">
+              <section className="containerSection">
+                <div {...getRootProps({className: 'dropzone'})}>
+                  <input {...getInputProps()} />
+                  <p>Drag 'n' drop some files here, or click to select files</p>
+                </div>
+              </section>
+              <div className="banneText">
+                <TextField 
+                type='number'
+                value={createAd.price}
+                onChange={(e) => setCreateAd({...createAd, price: +(e.target.value)})}
+                  className={classes.input} 
+                  required id="standard-required" 
+                  label="Price $" 
+                  />
+                <TextField
+                value={createAd.title}
+                onChange={(e) => setCreateAd({...createAd, title: e.target.value})} 
+                  className={classes.input} 
+                  required id="standard-required" 
+                  label="Title"  
+                  />
+                <TextField 
+                value={createAd.description}
+                onChange={(e) => setCreateAd({...createAd, description: e.target.value})}
+                  id="outlined-multiline-static"
+                  label="Description"
+                  multiline
+                  rows={4}
+                  variant="outlined"
+                />
+                <Button
+                onClick={onclickCreate}
+                type="submit"
+                fullWidth
+                variant="contained"
+                color="primary"
+                className={classes.submit}
+                startIcon={<CreateIcon/>}
+                >
+                Сhange
+                </Button>
+              </div>
+            </div>
+          </div>
+      </div>
+    </main></>
+  );
+}
+
+const ChangeAdConnect = connect(state => ({
+  newImg: state.promise?.upload?.payload||[],
+  good: state.promise?.onelist?.payload||[]}),
+  {action: actionUpload,
+  oneGood: actionOnelist} )(ChangeAd)
+ 
+
+export default ChangeAdConnect

+ 108 - 0
src/components/good/good.scss

@@ -0,0 +1,108 @@
+.card{
+	display: flex;
+	align-items: center;
+}
+
+.cardContent{
+	width: 70%;
+}
+
+.commentCardSend{
+	display: flex;
+	flex-direction: column;
+	align-items: flex-start;
+	margin: 3%;
+	padding: 10px;
+	width: 50%;
+  }
+
+.messageCardSend{
+	display: flex;
+	padding: 10px;
+	align-items: center;
+	flex-direction: column;
+}
+
+
+.description{
+	display: flex;
+	padding: 12px;
+	margin: 10px
+}
+
+.goodImg{
+	width: 100%;
+	border-radius: 4px;
+	max-height: 500px;
+}
+
+.cardRoot{
+	margin-left: 30px;
+	margin-right: 30px;
+}
+
+.commentCard{
+	margin: 3%;
+	width: 50%;
+}
+
+
+.mainGood{
+	background-color: #EEEFF1;
+    padding: 26px 36px 20px 36px;
+}
+
+
+
+@media only screen and (max-width: 470px) {
+	.cardRoot{
+		margin-left: 3px;
+		margin-right: 3px;
+	}
+
+	.mainGood{
+		background-color: #EEEFF1;
+		padding: 26px 16px 20px 16px;
+	}
+	
+}
+
+
+@media only screen and (max-width: 660px) {
+	.card{
+		display: flex;
+		align-items: center;
+		flex-direction: column;
+	}
+
+	.commentCardSend{
+		display: flex;
+		flex-direction: column;
+		align-items: flex-start;
+		margin: 3%;
+		padding: 10px;
+		width: 90%;
+	  }
+
+	.commentCard{
+		margin: 3%;
+		width: 90%;
+	}
+	
+}
+
+@media only screen and (min-width: 868px) {
+	.card{
+		display: flex;
+		align-items: center;
+	}
+	
+}
+
+@media only screen and (min-width: 1100px) {
+	.card{
+		display: flex;
+		align-items: center;
+	}
+	
+}

+ 231 - 125
src/components/good/index.js

@@ -1,145 +1,251 @@
-import {useState, useEffect} from 'react';
-import {useSelector, useDispatch} from 'react-redux';
-import { useParams} from 'react-router-dom';
-import {Typography,  Button} from '@material-ui/core';
+import { useState, useEffect } from 'react';
+import { useSelector, useDispatch } from 'react-redux';
+import { useParams } from 'react-router-dom';
+import { Typography, Button } from '@material-ui/core';
 import React from 'react';
 import { makeStyles } from '@material-ui/core/styles';
 import Avatar from '@material-ui/core/Avatar';
 import Card from '@material-ui/core/Card';
 import CardActionArea from '@material-ui/core/CardActionArea';
 import CardContent from '@material-ui/core/CardContent';
-import CardMedia from '@material-ui/core/CardMedia';
 import '../../App.scss';
+import './good.scss';
 import TextField from '@material-ui/core/TextField';
-import {actionAdComment,origUrl,actionAdMessage} from '../../App.js';
+import { origUrl, defaultAvatar } from '../../App.js';
+import Snackbar from '@material-ui/core/Snackbar';
+import MuiAlert from '@material-ui/lab/Alert';
+import { connect } from 'react-redux';
+import { actionOneUser, actionOnelist, actionAdComment, actionAdMessage } from '../../actions';
 
+const useStyles = makeStyles({
+  root: {
+    marginTop: 50,
+    margin: "auto",
+    textAlign: "-webkit-center"
+  },
+  comment: {
+    width: "75%",
+    marginBottom: '4px'
+  },
+  media: {
+    height: '100%',
+  },
+  alert: {
+    left: '75%'
+  },
+  time: {
+    margin: "5px",
+    float: "right"
+  },
+  actionArea: {
+    width: "100%"
+  }
+})
 
+const useStylesAlert = makeStyles((theme) => ({
+  root: {
+    width: '100%',
+    '& > * + *': {
+      marginTop: theme.spacing(2),
+    },
+  },
+}));
 
 const defaultImg = "https://www.lionstroy.ru/published/publicdata/U70619SHOP/attachments/SC/products_pictures/nophoto.png"
-const url = 'http://marketplace.node.ed.asmer.org.ua/'
-
-const Good = ({loadData,data, good, myUser })=>{
-    const {_id} = useParams()
-    const dispatch = useDispatch();
-    const id = useSelector(state => state.auth?.payload?.sub?.id)
-    const [comment, setComment] = useState('');
-    const [message, setMessage] = useState('');
-      useEffect(() => {
-          loadData(_id)
-      },[_id])
-      useEffect(() => {
-        data(id)
-      },[id])
-    const [indexArr, setindexArr] = useState(0)
-  
-    
-    const useStylesImgGood = makeStyles({
-      root: {
-        maxWidth: "80%",
-        marginTop: 50,
-        margin: "auto"
-      },
-      comment:{
-        width: "100%",
-        marginBottom: '4px'
-      },
-      media: {
-        height: 430,
-      },
-    })
-    const onclickSend =()=>{
-      dispatch(actionAdComment({text:comment, ad:{_id}}))
-      setComment('')
-    }
-    const onclickMessage=()=>{
-      dispatch(actionAdMessage({text:message, to:{_id:good.owner._id}}))
-      setMessage('')
+
+
+function timeConverter(UNIX_timestamp) {
+  const time = new Date(UNIX_timestamp);
+  const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+  const month = months[time.getMonth()];
+  const date = time.getDate();
+  const hour = time.getHours();
+  const min = time.getMinutes();
+  const newTime = date + ' ' + month + ' ' + hour + ':' + min;
+  return newTime;
+}
+
+
+function Alert(props) {
+  return <MuiAlert elevation={6} variant="filled" {...props} />;
+}
+
+const Commets = ({ good }) => {
+  const classes = useStyles()
+  return (<>
+    {good.comments.map(el =>
+      <div className='commentCard'>
+        <Card >
+          <Typography className={classes.time} gutterBottom component="h5">
+            {timeConverter(+el.createdAt)}
+          </Typography>
+          <CardContent className='commentAvatar'>
+            <Avatar alt="Remy Sharp" src={el.owner.avatar ? origUrl + el.owner.avatar.url : defaultAvatar} />
+            <p className="avatarName">
+              {el.owner.login}
+            </p>
+          </CardContent>
+          <div className='comment'>
+            {el.text && el.text}
+          </div>
+        </Card>
+      </div>)}</>
+  )
+}
+
+const Good = ({ loadData, data, good, myUser, status, statusMessage, admessage }) => {
+  const { _id, page } = useParams()
+  const dispatch = useDispatch();
+  const id = useSelector(state => state.auth?.payload?.sub?.id)
+  const [comment, setComment] = useState('');
+  const [message, setMessage] = useState('');
+  const [send, setSend] = useState(false);
+  const [open, setOpen] = useState(false);
+  const [messageId, setMessageId] = useState(admessage._id);
+  const [statusAlert, setStatusAlert] = useState('success');
+  useEffect(() => {
+    loadData(_id)
+  }, [send])
+
+  useEffect(() => {
+    data(id)
+  }, [])
+
+  const [indexArr, setindexArr] = useState(0)
+
+
+  const onclickSend = () => {
+    dispatch(actionAdComment({ text: comment, ad: { _id } }))
+    setSend(!send)
+    setComment('')
+  }
+  const onclickMessage = () => {
+    dispatch(actionAdMessage({ text: message, to: { _id: good.owner._id } }))
+    setMessage('')
+  }
+  const closeAlert = (event, reason) => {
+    if (reason === 'clickaway') {
+      return;
     }
-    const Commets = ()=>{
-      return(<>
-          {good.comments.map(el=>
-          <div className='commentCard'>
-            <Card >
-              <CardContent className='commentAvatar'>
-                <Avatar  alt="Remy Sharp" src={el.owner.avatar?url+el.owner.avatar.url:''} />
-                <p className="avatarName">
-                  {el.owner.login}
-                </p>
-              </CardContent>
-              <div className='comment'>
-                {el.text&&el.text}
-              </div>
-            </Card>
-          </div>)}</>
-      )
+
+    setOpen(false);
+  };
+
+
+  const classes = useStyles()
+  const classAlert = useStylesAlert()
+
+  useEffect(() => {
+    if (messageId !== admessage._id) {
+      if (statusMessage === 'FULFILLED') {
+        setStatusAlert('success')
+        setOpen(true);
+        setMessageId(admessage._id)
+      }
+      if (statusMessage === 'REJECTED') {
+        setStatusAlert('error')
+        setOpen(true);
+        setMessageId(admessage._id)
+      }
     }
+  }, [statusMessage])
+
+  if (status === 'PENDING') {
+    return (
+      <img className='preloader' src='https://i.pinimg.com/originals/c8/a1/76/c8a1765ffc8243f3a7b176c0ca84c3c1.gif' />
+    )
+  }
 
-    
-    
-    return(<>
-        <Card className={useStylesImgGood().root}>
-          <CardActionArea>
-          <CardMedia
-            className={useStylesImgGood().media}
-            onClick={()=>indexArr=== good.images.length-1?setindexArr(0) :setindexArr(indexArr+1)}
-            image={good.images&&good.images[indexArr]?origUrl+good.images[indexArr].url:defaultImg}
-            title="Contemplative Reptile"/>
+  return (<>
+    <main className="mainGood">
+      <div className='cardRoot'>
+        <Card className={classes.root}>
+          <div className='card'>
+            <CardActionArea className={classes.actionArea} >
+              <img className="goodImg"
+                onClick={() => indexArr === good.images.length - 1 ? setindexArr(0) : setindexArr(indexArr + 1)}
+                src={good.images && good.images[indexArr] ? origUrl + good.images[indexArr].url : defaultImg} />
             </CardActionArea>
-            <CardContent>
-              <Typography gutterBottom variant="h5" component="h2">
-              {good.title?good.title:""}
-              </Typography>
-              <Typography variant="body2" color="textSecondary" component="p">
-              {good.description?good.description:""}
-              </Typography>
-              <Typography gutterBottom variant="h6" component="h3">
-              {"Цена: "+(good.price?good.price:0)+" грн"}
-              </Typography>
+            <CardContent className='cardContent'>
               <div className='messageCardSend'>
-              <CardContent className='commentAvatar'>
-                <Avatar  alt="Remy Sharp"  />
-                <p className="avatarName">
-                  {good.owner?good.owner.login:""}
-                </p>
-              </CardContent>
-            <TextField 
-              value={message}
-              onChange={(e) => setMessage(e.target.value)} 
-              className={useStylesImgGood().comment}
-              id="outlined-multiline-static"
-              label="Message"
-              multiline
-              variant="outlined"/>
-              <Button size="small" color="primary" onClick={onclickMessage}>
-            SEND
-          </Button>
-          
-        </div>
+                <CardContent className='commentAvatar'>
+                  <Avatar alt="Remy Sharp" src={good?.owner?.avatar ? origUrl + good.owner.avatar.url : defaultAvatar} />
+                  <p className="avatarName">
+                    {good.owner ? good.owner.login : ""}
+                  </p>
+                </CardContent>
+                <TextField
+                  value={message}
+                  onChange={(e) => setMessage(e.target.value)}
+                  className={classes.comment}
+                  id="outlined-multiline-static"
+                  label="Message"
+                  multiline
+                  variant="outlined" />
+                <Button size="small" color="primary" onClick={onclickMessage}>
+                  SEND
+                </Button>
+                <Typography gutterBottom variant="h5" component="h2">
+                  {good.title ? good.title : ""}
+                </Typography>
+                <Typography gutterBottom variant="h6" component="h3">
+                  {"Цена: " + (good.price ? good.price : 0) + " грн"}
+                </Typography>
+              </div>
             </CardContent>
-          
-        </Card>
-        <Card className='commentCardSend'>
-              <CardContent className='commentAvatar'>
-                <Avatar  alt="Remy Sharp" src={myUser.avatar?url+myUser.avatar.url:''} />
-                <p className="avatarName">
-                  {myUser.login?myUser.login:''}
-                </p>
-              </CardContent>
-            <TextField 
-              value={comment}
-              onChange={(e) => setComment(e.target.value)} 
-              className={useStylesImgGood().comment}
-              id="outlined-multiline-static"
-              label="Comment"
-              multiline
-              variant="outlined"/>
-              <Button size="small" color="primary" onClick={onclickSend}>
-            SEND
-          </Button>
-          
+          </div>
+          <div className='description'>
+            <Typography variant="body2" color="textSecondary" component="p">
+              {good.description ? good.description : ""}
+            </Typography>
+          </div>
+          <Typography className={classes.time} gutterBottom component="h5">
+            {timeConverter(+good.createdAt)}
+          </Typography>
         </Card>
-        {good.comments&&<Commets/>}
-        </>
-  )}
+      </div>
+      <Card className='commentCardSend'>
+        <CardContent className='commentAvatar'>
+          <Avatar alt="Remy Sharp" src={myUser.avatar ? origUrl + myUser.avatar.url : defaultAvatar} />
+          <p className="avatarName">
+            {myUser.login ? myUser.login : ''}
+          </p>
+        </CardContent>
+        <TextField
+          value={comment}
+          onChange={(e) => setComment(e.target.value)}
+          className={classes.comment}
+          id="outlined-multiline-static"
+          label="Comment"
+          multiline
+          variant="outlined" />
+        <Button size="small" color="primary" onClick={onclickSend}>
+          SEND
+        </Button>
+        <div className={classAlert.root}>
+          <Snackbar className={classes.alert} open={open} autoHideDuration={3000} onClose={closeAlert}>
+            <Alert onClose={closeAlert} severity={statusAlert}>
+              Message sent successfully!
+            </Alert>
+          </Snackbar>
+        </div>
+      </Card>
+      {good.comments && <Commets good={good} />}
+    </main>
+  </>
+  )
+}
+
+const GoodUser = connect(state => ({
+  good: state.promise?.onelist?.payload || [],
+  status: state.promise?.onelist?.status || [],
+  admessage: state.promise?.admessage?.payload || [],
+  statusMessage: state.promise?.admessage?.status || [],
+  myUser: state.promise?.user?.payload || []
+}), {
+  loadData: actionOnelist,
+  data: actionOneUser
+})(Good)
+
 
-  export default Good
+export default GoodUser

+ 55 - 0
src/components/goods/goods.scss

@@ -0,0 +1,55 @@
+.cards{
+    display: flex;
+    flex-wrap: wrap;
+}
+
+.product-wrapper {
+	display: block;
+	width: 100%;
+	float: left;
+	transition: width .2s;
+}
+
+.product {
+	display: block;
+	border: 1px solid #b5e9a7;
+	border-radius: 3px;
+	position: relative;
+	background: #fff;
+	margin: 0 20px 20px 0;
+	text-decoration: none;
+	color: #474747;
+	z-index: 0;
+	height: 300px;
+}
+
+.mainGoodsList{
+	background-color: #EEEFF1;
+    padding: 26px 36px 20px 36px;
+}
+
+
+@media only screen and (max-width: 650px) {
+	.mainGoodsList{
+		background-color: #EEEFF1;
+		padding: 26px 16px 20px 16px;
+	}
+}
+
+@media only screen and (min-width: 650px) {
+	.product-wrapper {
+		width: 50%;
+	}
+}
+
+@media only screen and (min-width: 868px) {
+	.product-wrapper {
+		width: 33.333%;
+	}
+}
+
+@media only screen and (min-width: 1100px) {
+	.product-wrapper {
+		width: 25%;
+	}
+}

+ 199 - 74
src/components/goods/index.js

@@ -1,104 +1,229 @@
-import {useState, useEffect} from 'react';
-import {Typography,  Button} from '@material-ui/core';
+import { useState, useEffect } from 'react';
+import { Typography, Button } from '@material-ui/core';
 import React from 'react';
+import { useParams } from 'react-router-dom';
 import { makeStyles } from '@material-ui/core/styles';
 import Card from '@material-ui/core/Card';
 import CardContent from '@material-ui/core/CardContent';
 import CardMedia from '@material-ui/core/CardMedia';
 import '../../App.scss';
-import {origUrl} from '../../App.js';
+import './goods.scss';
+import { origUrl } from '../../App.js';
 import SearchIcon from '@material-ui/icons/Search';
-import Grid from '@material-ui/core/Grid';
 import CardActionArea from '@material-ui/core/CardActionArea';
-import CardActions from '@material-ui/core/CardActions';
 import Paper from '@material-ui/core/Paper';
 import InputBase from '@material-ui/core/InputBase';
-import {IconButton} from '@material-ui/core';
-import {history} from '../../App.js';
+import { IconButton } from '@material-ui/core';
+import { history } from '../../App.js';
+import Pagination from '@mui/material/Pagination';
+import Stack from '@mui/material/Stack';
+import {connect } from 'react-redux';
+import { actionList, actionlistCount, actionListSearch, actionSearchCount } from '../../actions';
 
+const useStyles = makeStyles((theme) => ({
+  root: {
+    padding: '2px 4px',
+    display: 'flex',
+    alignItems: 'center',
+    marginTop: '55px',
+    marginBottom: '0px',
+    width: '70%',
+    marginLeft: '16%'
+  },
+  input: {
+    marginLeft: theme.spacing(1),
+    flex: 1,
+  },
+  iconButton: {
+    padding: 10,
+  },
+  pagination: {
+    display: 'flex',
+    justifyContent: 'space-around',
+    margin: '40px'
+  }
+}));
 
 const defaultImg = "https://www.lionstroy.ru/published/publicdata/U70619SHOP/attachments/SC/products_pictures/nophoto.png"
-const url = 'http://marketplace.node.ed.asmer.org.ua/'
-const GoodCard = ({good}) => {
+
+const GoodCard = ({ good, page }) => {
   const [indexArr, setindexArr] = useState(0)
+
+  function timeConverter(UNIX_timestamp) {
+    const time = new Date(UNIX_timestamp);
+    const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+    const month = months[time.getMonth()];
+    const date = time.getDate();
+    const hour = time.getHours();
+    const min = time.getMinutes();
+    const newTime = date + ' ' + month + ' ' + hour + ':' + min;
+    return newTime;
+  }
+
   const useStylesImg = makeStyles({
     root: {
-      maxWidth: 345,
+      margin: '14px'
     },
     media: {
       height: 280,
     },
+    mediaButton: {
+      justifyContent: 'center'
+    },
+    time: {
+      margin: "5px",
+      float: "right"
+    },
+    card: {
+      textAlign: "center"
+    }
   })
-  const onClickGood = ()=>{
-    history.push("/good/"+good._id)
+  const onClickGood = () => {
+    history.push(page + "/good/" + good._id)
   }
   return (
-  <Grid item xs={6} md={3} >
-    <Card className={useStylesImg().root}>
-    <CardActionArea>
-    <CardMedia
-      className={useStylesImg().media}
-      onClick={()=>indexArr=== good.images.length-1?setindexArr(0) :setindexArr(indexArr+1)}
-      image={good.images&&good.images[indexArr]?origUrl+good.images[indexArr].url:defaultImg}
-      title="Contemplative Reptile"/>
-      <CardContent>
-          <Typography gutterBottom variant="h5" component="h2">
-          {good.title?good.title:""}
-          </Typography>
-          <Typography gutterBottom variant="h6" component="h3">
-          {"Цена: "+(good.price?good.price:0)+" грн"}
-          </Typography>
-        </CardContent>
-    </CardActionArea>
-    <CardActions>
-        <Button size="small" color="primary" onClick={onClickGood}>
-          Подробнее
-        </Button>
-      </CardActions>
-    </Card>
-  </Grid>
-)}
-
-const Cards = ({loadData, cats=[], stat}) => {
+    <div className="product-wrapper">
+      <Card className={useStylesImg().root}>
+        <CardActionArea className={useStylesImg().card}>
+          <CardMedia
+            className={useStylesImg().media}
+            onClick={() => indexArr === good.images.length - 1 ? setindexArr(0) : setindexArr(indexArr + 1)}
+            image={good.images && good.images[indexArr] ? origUrl + good.images[indexArr].url : defaultImg}
+            title="Contemplative Reptile" />
+          <CardContent onClick={onClickGood}>
+            <Typography gutterBottom variant="h5" component="h2">
+              {good.title ? good.title : ""}
+            </Typography>
+            <Typography gutterBottom variant="h6" component="h3">
+              {"Цена: " + (good.price ? good.price : 0) + " грн"}
+            </Typography>
+            <Typography className={useStylesImg().time} gutterBottom component="h5">
+              {timeConverter(+good.createdAt)}
+            </Typography>
+          </CardContent>
+        </CardActionArea>
+      </Card>
+    </div>
+  )
+}
+
+
+// const ButtonAllList = ({allList,goodsArr,searchList})=>{
+//   if(JSON.stringify(goodsArr)===JSON.stringify(searchList)||goodsArr.length===0){
+//     return(<Button variant="outlined" onClick={allList}>all goods</Button>)
+//   }
+// }
+
+
+const Cards = ({ actionList, actionlistCount, actionListSearch, actionSearchCount, status, count, list }) => {
+  const [search, setSearch] = useState('');
+  const [goodsArr, setGoodsArr] = useState([]);
+  const { _id } = useParams()
+  const [page, setPage] = useState(1);
+  const [buttonAllList, setButtonAllList] = useState(false);
+
+  console.log(page)
+  const limit = 15
+
+  const handleChange = (event, value) => {
+    let skip = value * limit - limit
+    history.push("/page/" + value)
+    setPage(value);
+    buttonAllList ? actionListSearch(search, skip, limit) : actionList(skip, limit)
+  };
+
+
   useEffect(() => {
-    loadData()
-  },[])
-  const useStyles = makeStyles((theme) => ({
-    root: {
-      padding: '2px 4px',
-      display: 'flex',
-      alignItems: 'center',
-      marginTop: '55px',
-      marginBottom: '20px',
-      width: '70%',
-      marginLeft: '16%'
-    },
-    input: {
-      marginLeft: theme.spacing(1),
-      flex: 1,
-    },
-    iconButton: {
-      padding: 10,
-    },
-  }));
+    let skip = _id * limit - limit
+    actionlistCount()
+    actionList(skip, limit)
+    setPage(+_id)
+  }, [])
+
+  useEffect(() => {
+    setGoodsArr(list)
+  }, [list])
+
+  const onclickSearch = () => {
+    if (search) {
+      setButtonAllList(true)
+      actionListSearch(search)
+      actionSearchCount(search)
+    }
+  }
+
+  const onClickAllList = () => {
+    actionList()
+    actionlistCount()
+    setButtonAllList(false)
+    setSearch('')
+  }
+
+  const enterHandler = (event) => {
+    if (event.key === 'Enter') {
+      onclickSearch()
+    }
+  }
+
   const classes = useStyles()
-  if(stat==='PENDING'){
-    return(
+
+  if (status === 'PENDING') {
+    return (
       <img className='preloader' src='https://i.pinimg.com/originals/c8/a1/76/c8a1765ffc8243f3a7b176c0ca84c3c1.gif' />
     )
   }
-  return(<>
-    <Paper component="form" className={classes.root}>
-    <IconButton className={classes.iconButton} aria-label="search">
-        <SearchIcon />
-      </IconButton>
-      <InputBase
-        className={classes.input}
-        placeholder="Search"/>
-    </Paper>
-  <Grid container spacing={4} >
-  {cats.reverse().map(el=><GoodCard key={el._id} good={el}/>)}
-  </Grid></>)
+  return (<>
+    <main className="mainGoodsList">
+      <Paper component="form" className={classes.root}>
+        <IconButton
+          onClick={onclickSearch}
+          className={classes.iconButton}
+          aria-label="search">
+          <SearchIcon />
+        </IconButton>
+        <InputBase
+          onKeyPress={enterHandler}
+          value={search}
+          onChange={(e) => setSearch(e.target.value)}
+          className={classes.input}
+          placeholder="Search" />
+        {buttonAllList && <Button variant="outlined" onClick={onClickAllList}>all goods</Button>}
+      </Paper>
+      <Stack spacing={2}>
+        <Pagination
+          className={classes.pagination}
+          color="primary"
+          variant="outlined"
+          count={Math.ceil(count / limit)}
+          page={page}
+          onChange={handleChange} />
+      </Stack>
+      <div className='cards'>
+        {goodsArr.map(el => <GoodCard key={el._id} page={_id} good={el} />)}
+      </div>
+      <Stack spacing={2}>
+        <Pagination
+          className={classes.pagination}
+          color="primary"
+          variant="outlined"
+          count={Math.ceil(count / limit)}
+          page={page}
+          onChange={handleChange} />
+      </Stack>
+    </main></>)
 }
 
-  export default Cards
+
+const MainList = connect(state => ({
+  status: state.promise?.list?.status || [],
+  list: state.promise?.list?.payload || [],
+  count: state.promise?.listCount?.payload || [],
+}),
+  {
+    actionList: actionList,
+    actionlistCount: actionlistCount,
+    actionListSearch: actionListSearch,
+    actionSearchCount: actionSearchCount
+  })(Cards)
+
+export default MainList

+ 107 - 93
src/components/header/index.js

@@ -1,10 +1,12 @@
-import {useSelector} from 'react-redux';
+import { useSelector } from 'react-redux';
 import React from 'react';
 import '../../App.scss';
-import {history, actionlist, actionAuthLogout, store} from '../../App.js';
+import { history, actionAuthLogout, store, defaultAvatar, origUrl } from '../../App.js';
+import { connect } from 'react-redux';
+import { actionOneUser } from '../../actions';
 import MenuItem from '@material-ui/core/MenuItem';
 import Menu from '@material-ui/core/Menu';
-import {AppBar, Container, Toolbar, IconButton, Typography, Box, Button} from '@material-ui/core';
+import { AppBar, Container, Toolbar, IconButton, Typography, Box, Button } from '@material-ui/core';
 import { makeStyles } from '@material-ui/core/styles';
 import Avatar from '@material-ui/core/Avatar';
 import HomeIcon from '@material-ui/icons/Home';
@@ -13,75 +15,83 @@ import AccountBoxIcon from '@material-ui/icons/AccountBox';
 import AddCircleIcon from '@material-ui/icons/AddCircle';
 import BallotIcon from '@material-ui/icons/Ballot';
 import EmailIcon from '@material-ui/icons/Email';
+import { useEffect, useState } from "react";
+
+const useStyles = makeStyles((theme) => ({
+  menuButton: {
+    position: "absolute",
+    right: "-10px",
+  },
+  Buttons: {
+    position: "absolute",
+    marginTop: "-20px"
+  },
+  title: {
+    flexGrow: 1,
+    cursor: "pointer"
+  },
+  root: {
+    display: 'flex',
+    '& > *': {
+      margin: theme.spacing(1),
+    },
+  },
+  small: {
+    width: theme.spacing(3),
+    height: theme.spacing(3),
+  },
+  large: {
+    width: theme.spacing(7),
+    height: theme.spacing(7),
+    position: "absolute",
+    right: 50,
+    cursor: "pointer"
+
+  },
+
+}))
 
 
 
-const Header = ()=> {
+const Header = ({ data, myUser }) => {
   const logined = useSelector(state => state?.auth?.token);
-  const useStyles = makeStyles((theme)=>({
-    menuButton:{
-      position: "absolute",
-      right: 100,
-    },
-    Buttons:{
-      position: "absolute",
-      left: 50,
-      marginTop: "-20px"
-    },
-    title:{
-      flexGrow:1,
-      cursor: "pointer"
-    },
-    root: {
-      display: 'flex',
-      '& > *': {
-        margin: theme.spacing(1),
-      },
-    },
-    small: {
-      width: theme.spacing(3),
-      height: theme.spacing(3),
-    },
-    large: {
-      width: theme.spacing(7),
-      height: theme.spacing(7),
-      position: "absolute",
-      right: 50,
+  const id = useSelector(state => state.auth?.payload?.sub?.id)
 
-    },
-    menu:{
-      marginLeft: "6%"
+
+  useEffect(() => {
+    if(id){
+      data(id)
     }
-    
-  }))
+  }, [id])
+
+
   const classes = useStyles()
-  const onclickHome = ()=>{
+  const onclickHome = () => {
     handleClose()
-    if(store.getState().auth.token){
-      history.push("/")
-      store.dispatch(actionlist())
-    }else{
+    if (store.getState().auth.token) {
+      history.push("/page/1")
+    } else {
       history.push("/sign_in")
     }
   }
-  const onclickLogout = ()=>{
+  const onclickLogout = () => {
     store.dispatch(actionAuthLogout())
     handleClose()
     history.push("/sign_in")
   }
-  const onclickMyProfile = ()=>{
+  const onclickMyProfile = () => {
     handleClose()
     history.push("/my_profile")
   }
-  const onclickAllProductsUser = ()=>{
+  const onclickAllProductsUser = () => {
     handleClose()
     history.push("/all_products_user")
   }
-  const onclickCreateAd = ()=>{
+  const onclickCreateAd = () => {
     handleClose()
     history.push("/create_ad")
   }
-  const onclickMessage = ()=>{
+  const onclickMessage = () => {
     handleClose()
     history.push("/message")
   }
@@ -94,55 +104,59 @@ const Header = ()=> {
   const handleClose = () => {
     setAnchorEl(null);
   };
-  const Buttons = ()=>{
-    if (logined){
-      return(<>
-      
-      <Avatar alt="Remy Sharp" src="https://d18jg6w55vcmy1.cloudfront.net/media/resume_images/38beb2471ba34320baae996ce289a7ed.png" className={classes.large} />
-      
-      
-      <div>
-        <Button className={classes.Buttons} variant="outlined" color="inherit" aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
-          Open Menu
-        </Button>
-        <Menu
-        className={classes.menu}
-          id="simple-menu"
-          anchorEl={anchorEl}
-          keepMounted
-          open={Boolean(anchorEl)}
-          onClose={handleClose}
-        >
-          <MenuItem onClick={onclickHome}><HomeIcon/> Home</MenuItem>
-          <MenuItem onClick={onclickMessage}><EmailIcon/> Message</MenuItem>
-          <MenuItem onClick={onclickMyProfile}><AccountBoxIcon/> Profile</MenuItem>
-          <MenuItem onClick={onclickCreateAd}><AddCircleIcon/> Create Ad</MenuItem>
-          <MenuItem onClick={onclickAllProductsUser}><BallotIcon/> My Products</MenuItem>
-          <MenuItem onClick={onclickLogout}><MeetingRoomIcon/> Logout</MenuItem>
-        </Menu>
-      </div>
-    </>)
-    }else{
-      return<>
+  const Buttons = () => {
+    if (logined) {
+      return (<>
+        <Avatar onClick={onclickMyProfile} alt="Remy Sharp" src={myUser.avatar ? origUrl + myUser.avatar.url : defaultAvatar} className={classes.large} />
+        <div>
+          <Button className={classes.Buttons} variant="outlined" color="inherit" aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
+            Open Menu
+          </Button>
+          <Menu
+            className={classes.menu}
+            id="simple-menu"
+            anchorEl={anchorEl}
+            keepMounted
+            open={Boolean(anchorEl)}
+            onClose={handleClose}
+          >
+            <MenuItem onClick={onclickHome}><HomeIcon /> Home</MenuItem>
+            <MenuItem onClick={onclickMessage}><EmailIcon /> Message</MenuItem>
+            <MenuItem onClick={onclickMyProfile}><AccountBoxIcon /> Profile</MenuItem>
+            <MenuItem onClick={onclickCreateAd}><AddCircleIcon /> Create Ad</MenuItem>
+            <MenuItem onClick={onclickAllProductsUser}><BallotIcon /> My Products</MenuItem>
+            <MenuItem onClick={onclickLogout}><MeetingRoomIcon /> Logout</MenuItem>
+          </Menu>
+        </div>
+      </>)
+    } else {
+      return <>
         <Box mr={3}>
-        <Button  color="inherit" variant="outlined" onClick={()=>history.push("/sign_in")}>Sign in</Button>
+          <Button color="inherit" variant="outlined" onClick={() => history.push("/sign_in")}>Sign in</Button>
         </Box>
-        <Button color="secondary" variant="contained" onClick={()=>history.push("/sign_up")}>Sign Up</Button></>
+        <Button color="secondary" variant="contained" onClick={() => history.push("/sign_up")}>Sign Up</Button></>
     }
   }
-  return (
-  <AppBar position="fixed" className='myButt'>
-          <Container fixed>
-          <Toolbar>
+  return (<>
+    <AppBar position="fixed" className='myButt'>
+      <Container fixed>
+        <Toolbar>
           <Buttons />
-            <IconButton edge='start'
-            color='inherit'  className={classes.menuButton} onClick={onclickHome}>
-              <Typography variant='h6' className={classes.title}>OLX</Typography>
-            </IconButton>
-          </Toolbar>
-          </Container>
-        </AppBar>
-        )
+          <IconButton edge='start'
+            color='inherit' className={classes.menuButton} onClick={onclickHome}>
+            <Typography variant='h6' className={classes.title}>OLX</Typography>
+          </IconButton>
+        </Toolbar>
+      </Container>
+    </AppBar>
+  </>
+  )
 }
 
-  export default Header
+
+const HeaderConnect = connect(state => ({
+  myUser: state.promise?.user?.payload || []
+}),
+  { data: actionOneUser })(Header)
+
+export default HeaderConnect

+ 228 - 151
src/components/message/index.js

@@ -1,39 +1,50 @@
 import React from 'react';
-import Button from '@material-ui/core/Button';
+import { Typography, Button } from '@material-ui/core';
 import TextField from '@material-ui/core/TextField';
-import SaveIcon from '@material-ui/icons/Save';
 import { makeStyles } from '@material-ui/core/styles';
-import AddAPhotoIcon from '@material-ui/icons/AddAPhoto';
 import './message.scss';
-import {useState, useEffect} from "react";
+import { useState, useEffect } from "react";
 import Avatar from '@material-ui/core/Avatar';
-import {useDispatch, useSelector, connect} from "react-redux";
-import {useParams} from 'react-router-dom';
+import { useDispatch, useSelector, connect } from "react-redux";
 import Card from '@material-ui/core/Card';
 import CardActionArea from '@material-ui/core/CardActionArea';
-import CardContent from '@material-ui/core/CardContent';
-import CardMedia from '@material-ui/core/CardMedia';
-import {actionAdMessage} from '../../App.js';
+import { defaultAvatar, origUrl } from '../../App.js';
+import ImageList from '@material-ui/core/ImageList';
+import MenuOpenIcon from '@material-ui/icons/MenuOpen';
+import HighlightOffIcon from '@material-ui/icons/HighlightOff';
+import { actionMyUserMessage, actionForMeMessage, actionAdMessage } from '../../actions';
 
 
 const useStyles = makeStyles((theme) => ({
   messageList: {
-    width: "70%",
+    width: "50%",
     maxWidth: "70%",
     backgroundColor: '#ccd7e3',
     display: 'flex',
     flexDirection: 'column-reverse',
   },
+  messageListClose: {
+    width: "90%",
+    backgroundColor: '#ccd7e3',
+    display: 'flex',
+    flexDirection: 'column-reverse',
+  },
   userList: {
     width: "30%",
     marginRight: "5px",
     minWidth: "max-content",
     backgroundColor: '#ccd7e3'
   },
-  MessageInput:{
+  userListButton: {
+    minWidth: "max-content",
+    backgroundColor: '#ccd7e3',
+    height: '498px',
+    cursor: 'pointer'
+  },
+  MessageInput: {
     margin: '10px'
   },
-  user:{
+  user: {
     display: 'flex',
     height: '60px',
     backgroundColor: '#88a0b9',
@@ -41,209 +52,275 @@ const useStyles = makeStyles((theme) => ({
     alignItems: 'center',
     padding: '5px'
   },
-  avatar:{
+  avatar: {
     marginRight: '5px'
   },
-  messageCard:{
+  messageCard: {
     maxWidth: '80%',
-    margin: '10px',
+    margin: '10px 10px 0px 10px',
     width: 'max-content',
-    padding: '4px'
+    padding: '4px',
+    height: 'max-content'
   },
-  myUserColor:{
+  myUserColor: {
     backgroundColor: "#848bd8",
     maxWidth: '80%',
-    margin: '10px',
+    margin: '10px 10px 0px 10px',
     marginRight: '-6px',
     marginLeft: '-5px',
     width: 'max-content',
     padding: '4px',
   },
-  userColor:{
+  imageList: {
+    width: 'auto',
+    height: '402px',
+    display: 'block',
+    overflowY: 'scroll'
+  },
+  imageListUsers: {
+    width: 'auto',
+    height: '502px',
+    display: 'block',
+    overflowY: 'scroll'
+  },
+  userColor: {
     backgroundColor: "#50905f",
     maxWidth: '80%',
     maxHeight: '21px',
-    margin: '10px',
+    margin: '10px 10px 0px 10px',
     marginRight: '-6px',
     width: 'max-content',
     padding: '4px',
   },
-  UserDiv:{
+  UserDiv: {
     display: 'flex',
   },
-  myUserDiv:{
+  myUserDiv: {
     display: 'flex',
     flexDirection: 'row-reverse',
     marginRight: '15px',
+  },
+  time: {
+    float: "right",
+    fontSize: "80%",
+    marginLeft: "12px",
   }
 }));
 
-function MyMessage({user, message}) {
+function timeConverter(UNIX_timestamp) {
+  const time = new Date(UNIX_timestamp);
+  const months = ["01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12"];
+  const month = months[time.getMonth()];
+  const date = time.getDate();
+  const hour = time.getHours();
+  const min = time.getMinutes();
+  const newTime = date + '.' + month + ' ' + hour + ':' + min;
+  return newTime;
+}
+
+
+function MyMessage({ user, message, time }) {
   const login = useSelector(state => state.auth?.payload?.sub?.login)
   const classes = useStyles();
-  return(<div className={login===user?classes.myUserDiv:classes.UserDiv}>
-    <Card className={login===user?classes.myUserColor:classes.userColor}>{user} </Card>
-    <Card className={classes.messageCard}>{message} </Card>
+  return (<>
+    <div className={login === user ? classes.myUserDiv : classes.UserDiv}>
+      <Card className={login === user ? classes.myUserColor : classes.userColor}>{user} </Card>
+      <Card className={classes.messageCard}>{message} </Card>
     </div>
+    <div className={login === user ? classes.myUserDiv : classes.UserDiv}>
+      <Typography className={classes.time} gutterBottom >
+        {timeConverter(+time)}
+      </Typography></div></>
   )
 }
 
 
-const Users = ({myOnclick, user})=>{
+const Users = ({ myOnclick, user }) => {
   const classes = useStyles();
-  return(
-      <CardActionArea onClick={()=>myOnclick(user._id)}>
-        <Card className={classes.user}>
-        <Avatar  className={classes.avatar} alt="Remy Sharp" />
-                <p >{user.login} </p>
-        </Card>
-      </CardActionArea>
+  return (
+    <CardActionArea onClick={() => myOnclick(user._id)}>
+      <Card className={classes.user}>
+        <Avatar className={classes.avatar} src={user.avatar ? origUrl + user.avatar.url : defaultAvatar} alt="Remy Sharp" />
+        <p >{user.login} </p>
+      </Card>
+    </CardActionArea>
   )
 }
 
-  const Message = ({loadData,dataMyUser ,sendMessage, myMessage=[],forMeMessage=[] , myNewMessage=[]})=>{
-    const classes = useStyles();
-    const dispatch = useDispatch();
-    const id = useSelector(state => state.auth?.payload?.sub?.id)
-    const [time, setTime] = useState(true);
-    
-    const [users, setUsers] = useState([]);
-    
-    useEffect(() => {
-      if(forMeMessage.length>0||myMessage.length>0){
-        let allmessages=[]
-        if(forMeMessage.length>0){
-          allmessages = [...forMeMessage] 
+
+const Spoiler = ({ open, children }) => {
+  return <>
+    <div>{open && children}</div>
+  </>
+}
+
+
+const Message = ({ loadData, dataMyUser, myMessage = [], forMeMessage = [], forMeStatus, myMessageStatus }) => {
+  const classes = useStyles();
+  const dispatch = useDispatch();
+  const id = useSelector(state => state.auth?.payload?.sub?.id)
+  const [time, setTime] = useState(true);
+  const [users, setUsers] = useState([]);
+  const [send, setSend] = useState(false);
+  const [message, setMessage] = useState('');
+  const [iduser, setIduser] = useState("");
+  const [messageArr, setMessageArr] = useState([]);
+  const [allmessage, setAllMessage] = useState([]);
+
+  useEffect(() => {
+    if (forMeStatus === 'FULFILLED' && myMessageStatus === 'FULFILLED') {
+      if (forMeMessage.length > 0 || myMessage.length > 0) {
+        let allmessages = []
+        if (forMeMessage.length > 0) {
+          allmessages = [...forMeMessage]
         }
-        if(myMessage.length>0){
-          allmessages = [...myMessage] 
+        if (myMessage.length > 0) {
+          allmessages = [...myMessage]
         }
-        if(forMeMessage.length>0&&myMessage.length>0){
-          allmessages = [...forMeMessage,...myMessage] 
+        if (forMeMessage.length > 0 && myMessage.length > 0) {
+          allmessages = [...forMeMessage, ...myMessage]
         }
-        
-        if(allmessages.length>0){
-          
-          let usersList = allmessages.map((el)=>{
-            if(el.to){
-              return{login:el.to.login, _id:el.to._id}
+
+        if (allmessages.length > 0) {
+
+          let usersList = allmessages.map((el) => {
+            if (el.to) {
+              return { login: el.to.login, _id: el.to._id, avatar: el.to.avatar }
             }
-            return{login:el.owner.login, _id:el.owner._id}
-          } )
-        usersList = usersList.reduce((a, b) => {
-          if (!a.find(v => v._id == b._id)) {
-            a.push(b);
-          }
-          return a;
-        }, []);
-        setUsers(usersList)
+            return { login: el.owner.login, _id: el.owner._id, avatar: el.owner.avatar }
+          })
+          usersList = usersList.reduce((a, b) => {
+            if (!a.find(v => v._id == b._id)) {
+              a.push(b);
+            }
+            return a;
+          }, []);
+          setUsers(usersList)
         }
-        
+
       }
+    }
+  }, [forMeMessage, myMessage])
 
-    },[forMeMessage,myMessage])
-    
-    const [send, setSend] = useState(false);
-    useEffect(() => {
-      loadData(id)
-    },[send])
-    const [message, setMessage] = useState('');
 
+  useEffect(() => {
+    loadData(id)
+  }, [send])
 
-    const [iduser, setIduser]= useState("");
+  useEffect(() => {
+    const element = document.getElementById('list');
+    element.scrollTop = element.scrollHeight;
+  }, [messageArr])
 
-    
 
-    
-    const [messageArr, setMessageArr] = useState([]);
-    const [allmessage, setAllMessage] = useState([]);
+  const onclickSend = () => {
+    if (message) {
+      dispatch(actionAdMessage({ text: message, to: { _id: iduser } }))
+      setSend(!send)
+      setMessage('')
+    }
+  }
 
-    const onclickSend =()=>{
-      if(message){
-        dispatch(actionAdMessage({text:message, to:{_id:iduser}}))
+  const enterHandler = (event) => {
+    if (event.key === 'Enter') {
+      if (message) {
+        dispatch(actionAdMessage({ text: message, to: { _id: iduser } }))
         setSend(!send)
         setMessage('')
       }
     }
+  }
 
+  const upDate = () => {
+    let usersMessage = []
+    forMeMessage.map((el) => {
+      if (el.owner._id === iduser) {
+        usersMessage.push(el)
+      }
+    })
+    myMessage.map((el) => {
+      if (el.to._id === iduser) {
+        usersMessage.push(el)
+      }
+    })
+    const sort = usersMessage.sort((a, b) => a.createdAt - b.createdAt)
+    setMessageArr(sort)
+    setAllMessage([...forMeMessage, ...myMessage])
+  }
 
+  useEffect(() => {
+    setTimeout(() => {
+      dataMyUser(id)
+      setTime(!time);
+    }, 3000)
+  }, [time])
 
-  const upDate=()=>{
-      let usersMessage = []
-      forMeMessage.map((el)=>{
-        if(el.owner._id===iduser){
-          usersMessage.push(el)
-        } 
-      })
-      
-      myMessage.map((el)=>{
-        if(el.to._id===iduser){
-          usersMessage.push(el)
-        } 
-      })
-  
-      const sort = usersMessage.sort((a,b)=>a.createdAt-b.createdAt)
-      setMessageArr(sort)
-      setAllMessage([...forMeMessage,...myMessage]) 
-    }
-
-    useEffect(() => {
-      setTimeout(()=>{
-        dataMyUser(id)
-        setTime(!time);
-      },3000)
-    },[time])
-
-
-
-
-    const onclickUser =(id)=>{
-     setIduser(id)
-     let usersMessage = []
-     forMeMessage.map((el)=>{
-        if(el.owner._id===id){
-          usersMessage.push(el)
-        } 
-      })
-      
-      myMessage.map((el)=>{
-        if(el.to._id===id){
-          usersMessage.push(el)
-        } 
-      })
-        
-      const sort = usersMessage.sort((a,b)=>a.createdAt-b.createdAt)
-      setMessageArr(sort) 
-    }
+  const onclickUser = (id) => {
+    setIduser(id)
+    let usersMessage = []
+    forMeMessage.map((el) => {
+      if (el.owner._id === id) {
+        usersMessage.push(el)
+      }
+    })
+    myMessage.map((el) => {
+      if (el.to._id === id) {
+        usersMessage.push(el)
+      }
+    })
+    const sort = usersMessage.sort((a, b) => a.createdAt - b.createdAt)
+    setMessageArr(sort)
+  }
 
-   if(allmessage.length<forMeMessage.length+myMessage.length){
+  if (allmessage.length < forMeMessage.length + myMessage.length) {
     upDate()
-   }
-    
-    
+  }
+
+  const [open, setOpen] = useState(true);
+
+  const onclickOpen = () => {
+    setOpen(!open)
+  }
+
   return (
     <main className='mainMessage'>
-    <Card className={classes.userList}>
-    {users.map((el)=><Users myOnclick={onclickUser} user={el}/>)}
-    </Card>
-    <Card className={classes.messageList}>
-      <div className='divButtonText'>
-      <Button onClick={onclickSend} size="small" color="primary">SEND</Button>
-        <TextField
-          value={message}
-          onChange={(e) => setMessage(e.target.value)} 
-          className={classes.MessageInput} 
-          id="standard-basic" 
-          label="Message" />
-        <div >{messageArr.map((el)=><MyMessage user={el.owner.login} message={el.text}/>)}</div>
-      </div>
-    </Card>
+      <Card onClick={onclickOpen} className={classes.userListButton} >{open ? <HighlightOffIcon /> : <MenuOpenIcon />}</Card>
+      <Spoiler open={open}>
+        <Card className={classes.userList}>
+          <ImageList rowHeight={180} className={classes.imageListUsers}>
+            {users.map((el) => <Users myOnclick={onclickUser} user={el} />)}
+          </ImageList>
+        </Card>
+      </Spoiler>
+      <Card className={open ? classes.messageList : classes.messageListClose}>
+        <div className='divButtonText'>
+          <Button onClick={onclickSend} size="small" color="primary">SEND</Button>
+          <TextField
+            onKeyPress={enterHandler}
+            value={message}
+            onChange={(e) => setMessage(e.target.value)}
+            className={classes.MessageInput}
+            id="standard-basic"
+            label="Message" />
+          <ImageList id='list' rowHeight={180} className={classes.imageList}>
+            {messageArr.map((el) => <MyMessage user={el.owner.login} message={el.text} time={el.createdAt} />)}
+          </ImageList>
+        </div>
+      </Card>
     </main>
   );
-  }
+}
 
-  
 
+const Messages = connect(state => ({
+  myMessage: state.promise?.allMeMessage?.payload,
+  forMeMessage: state.promise?.allForMeMessage?.payload?.incomings || [],
+  forMeStatus: state.promise?.allForMeMessage?.status || [],
+  myMessageStatus: state.promise?.allMeMessage?.status || []
+}), {
+  loadData: actionMyUserMessage,
+  dataMyUser: actionForMeMessage
+})(Message)
 
 
-export default Message
+export default Messages

+ 3 - 0
src/components/message/message.scss

@@ -2,6 +2,9 @@
     display: flex;
     margin-top: 65px;
     height: 500px;
+    justify-content: center;
+    background-color: #EEEFF1;
+    padding: 26px 36px 100px 36px;
 }
 
 .messageList{

+ 0 - 35
src/components/myprofile/App.scss

@@ -1,35 +0,0 @@
-.main1 {
-    background-color: #EEEFF1;
-}
-.banner-wrap {
-    padding: 147px 0 146px;
-}
-.conteiner__images__pc {
-    margin-top: 20px;
-    margin-left: 78px;
-}
-.flex__box {
-    display: flex;
-    justify-content: space-evenly;
-}
-.conteiner__images__pc {
-    margin-top: 20px;
-    margin-left: 78px;
-}
-.banner {
-    width: 50%;
-    margin-left: 3%;
-    margin-right: 3%;
-}
-.banner-link-wrap {
-    min-width: 225px;
-    height: 55px;  
-}
-.buttonPhoto{
-    margin: 20px;
-}
-
-.imgx{
-    border-radius: 8px;
-    box-shadow: 0.4em 0.4em 5px rgba(122,122,122,0.5);
-}

+ 161 - 95
src/components/myprofile/index.js

@@ -3,12 +3,28 @@ import Button from '@material-ui/core/Button';
 import TextField from '@material-ui/core/TextField';
 import SaveIcon from '@material-ui/icons/Save';
 import { makeStyles } from '@material-ui/core/styles';
-import AddAPhotoIcon from '@material-ui/icons/AddAPhoto';
-import './App.scss';
-import {useState, useEffect} from "react";
-import {useDispatch, useSelector, connect} from "react-redux";
-import {actionUpdateMe} from '../../App.js';
-import {useParams} from 'react-router-dom';
+import Snackbar from '@material-ui/core/Snackbar';
+import MuiAlert from '@material-ui/lab/Alert';
+import './myprofile.scss';
+import { useState, useEffect } from "react";
+import { useDispatch, useSelector, connect } from "react-redux";
+import { origUrl, defaultAvatar } from '../../App.js';
+import { useParams } from 'react-router-dom';
+import { useDropzone } from 'react-dropzone';
+import { actionOneUser, actionUpload, actionUpdateMe } from '../../actions';
+
+
+function Alert(props) {
+  return <MuiAlert elevation={6} variant="filled" {...props} />;
+}
+const useStylesAlert = makeStyles((theme) => ({
+  root: {
+    width: '100%',
+    '& > * + *': {
+      marginTop: theme.spacing(2),
+    },
+  },
+}));
 
 
 const useStyles = makeStyles((theme) => ({
@@ -21,7 +37,7 @@ const useStyles = makeStyles((theme) => ({
     flexDirection: 'column',
     alignItems: 'center',
   },
-  
+
   form: {
     width: '100%', // Fix IE 11 issue.
     marginTop: theme.spacing(1),
@@ -31,112 +47,162 @@ const useStyles = makeStyles((theme) => ({
   },
 }));
 
- function MyProfile({loadData, myUser=[] }) {
+function MyProfile({ loadData, action, myUser = [], newImg, status }) {
   const id = useSelector(state => state.auth?.payload?.sub?.id)
+  const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
+  const [profile, setProfile] = useState({ avatar: '', login: '', nick: '', addresses: '', phones: '' });
+  const classAlert = useStylesAlert();
+  const [open, setOpen] = useState(false);
+  useEffect(() => {
+    acceptedFiles.map(file => action(file));
+  }, [acceptedFiles]);
+  console.log(profile)
+
+  useEffect(() => {
+    setProfile({ ...profile, avatar: newImg })
+  }, [newImg])
+
   useEffect(() => {
     loadData(id)
-},[id])
+  }, [id])
   const dispatch = useDispatch();
-  const [user, setUser] = useState(myUser)
-  const [profile, setProfile] = useState({ login:'', nick: '', addresses:'', phones:''});
+
   useEffect(() => {
-    if(myUser!==[]){
-        setProfile({ login:myUser.login, nick:myUser.nick, addresses:myUser.addresses, phones:myUser.phones})
+    if (myUser !== []) {
+      setProfile({ avatar: myUser.avatar, login: myUser.login, nick: myUser.nick, addresses: myUser.addresses, phones: myUser.phones })
     }
-},[myUser])
+  }, [myUser])
+
+
+  const handleClose = (event, reason) => {
+    if (reason === 'clickaway') {
+      return;
+    }
+
+    setOpen(false);
+  };
+  const onClickChange = () => {
+    dispatch(actionUpdateMe({ ...profile, _id: id, avatar: { _id: profile.avatar._id } }))
+    loadData(id)
+    setOpen(true)
+  }
+
+  const enterHandler = (event) => {
+    if (event.key === 'Enter') {
+      onClickChange()
+    }
+  }
+
+
 
   const classes = useStyles();
+  if (status === 'PENDING') {
+    return (
+      <img className='preloader' src='https://i.pinimg.com/originals/c8/a1/76/c8a1765ffc8243f3a7b176c0ca84c3c1.gif' />
+    )
+  }
   return (
     <main className="main1">
-        <div className="banner-wrap" >
-          <div className="conteiner">
-            <div className="flex__box">
-              <div className="conteiner__images__pc">
-                <img className="imgx" src="https://d18jg6w55vcmy1.cloudfront.net/media/resume_images/38beb2471ba34320baae996ce289a7ed.png" alt=""/>
-                <div className="buttonPhoto">
-                <Button
-              type="submit"
-              fullWidth
-              variant="outlined"
-              color='primary'
-              startIcon={<AddAPhotoIcon />}>
-              Сhange photo
-            </Button>
+      <div className="banner-wrap" >
+        <div className="conteiner">
+          <div className="flex__box" onKeyPress={enterHandler}>
+            <div className="conteiner__images">
+              <div className="photo">
+                <img className="imgDnd" src={profile.avatar ? origUrl + profile.avatar.url : defaultAvatar} alt="" />
+                <div {...getRootProps({ className: 'dropzon' })}>
+                  <input {...getInputProps()} />
+                  <p>Drag 'n' drop some files here, or click to select files</p>
                 </div>
               </div>
-              <div className="banner">
-                <TextField
-              variant="outlined"
-              margin="normal"
-              required
-              fullWidth
-              id="Login"
-              label="Login"
-              name="Login"
-              autoComplete="Login"
-              autoFocus
-              value={profile.login}
-              onChange={(e) => setProfile({...profile, login: e.target.value})}
-            />
-            <TextField
-              variant="outlined"
-              margin="normal"
-              required
-              fullWidth
-              id="Name"
-              label="Name"
-              name="Name"
-              autoComplete="Name"
-              autoFocus
-              value={profile.nick}
-              onChange={(e) => setProfile({...profile, nick: e.target.value})}
-            />
-            <TextField
-              variant="outlined"
-              margin="normal"
-              required
-              fullWidth
-              id="Number phone"
-              label="Number phone"
-              name="Number phone"
-              autoComplete="Number phone"
-              autoFocus
-              value={profile.phones}
-              onChange={(e) => setProfile({...profile, phones: e.target.value})}
-            />
-            <TextField
-              variant="outlined"
-              margin="normal"
-              required
-              fullWidth
-              id="City"
-              label="City"
-              name="City"
-              autoComplete="City"
-              autoFocus
-              value={profile.addresses}
-              onChange={(e) => setProfile({...profile, addresses: e.target.value})}
-            />
-            <Button
-              onClick={() => {dispatch(actionUpdateMe({...profile, _id: id}))}}
-              type="submit"
-              fullWidth
-              variant="contained"
-              color="primary"
-              className={classes.submit}
-              startIcon={<SaveIcon />}
-            >
-              Сhange profile
-            </Button>
-                
-               </div>
+            </div>
+            <div className="banner">
+              <TextField
+                variant="outlined"
+                margin="normal"
+                required
+                fullWidth
+                id="Login"
+                label="Login"
+                name="Login"
+                autoComplete="Login"
+                autoFocus
+                value={profile.login}
+                onChange={(e) => setProfile({ ...profile, login: e.target.value })}
+              />
+              <TextField
+                variant="outlined"
+                margin="normal"
+                required
+                fullWidth
+                id="Name"
+                label="Name"
+                name="Name"
+                autoComplete="Name"
+                autoFocus
+                value={profile.nick}
+                onChange={(e) => setProfile({ ...profile, nick: e.target.value })}
+              />
+              <TextField
+                variant="outlined"
+                margin="normal"
+                required
+                fullWidth
+                id="Number phone"
+                label="Number phone"
+                name="Number phone"
+                autoComplete="Number phone"
+                autoFocus
+                value={profile.phones}
+                onChange={(e) => setProfile({ ...profile, phones: e.target.value })}
+              />
+              <TextField
+                variant="outlined"
+                margin="normal"
+                required
+                fullWidth
+                id="City"
+                label="City"
+                name="City"
+                autoComplete="City"
+                autoFocus
+                value={profile.addresses}
+                onChange={(e) => setProfile({ ...profile, addresses: e.target.value })}
+              />
+              <Button
+                onClick={onClickChange}
+                type="submit"
+                fullWidth
+                variant="contained"
+                color="primary"
+                className={classes.submit}
+                startIcon={<SaveIcon />}
+              >
+                Сhange profile
+              </Button>
+              <div className={classAlert.root}>
+                <Snackbar open={open} autoHideDuration={6000} onClose={handleClose}>
+                  <Alert onClose={handleClose} severity="success">
+                    Profile changed successfully!
+                  </Alert>
+                </Snackbar>
+              </div>
             </div>
           </div>
         </div>
+      </div>
     </main>
   );
 }
 
+const Profile = connect(state => ({
+  myUser: state.promise?.user?.payload || [],
+  status: state.promise?.user?.status || [],
+  newImg: state.promise?.upload?.payload || []
+}),
+  {
+    loadData: actionOneUser,
+    action: actionUpload
+  })(MyProfile)
 
 
-export default MyProfile
+export default Profile

+ 89 - 0
src/components/myprofile/myprofile.scss

@@ -0,0 +1,89 @@
+.main1 {
+    background-color: #EEEFF1;
+}
+.banner-wrap {
+    padding: 147px 0 146px;
+}
+.conteiner__images {
+    margin-top: 20px;
+}
+.flex__box {
+    display: flex;
+}
+.banner {
+    width: 50%;
+    margin-left: 3%;
+    margin-right: 3%;
+}
+.banner-link-wrap {
+    min-width: 225px;
+    height: 55px;  
+}
+.photo{
+    margin: 20px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    max-width: min-content;
+}
+
+.imgDnd{
+    border-radius: 8px;
+    box-shadow: 0.4em 0.4em 5px rgba(122,122,122,0.5);
+    margin-bottom: 10px;
+    max-width: 270px;
+}
+
+.dropzon {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 20px;
+    border-width: 2px;
+    border-radius: 2px;
+    border-color: #eeeeee;
+    border-style: dashed;
+    background-color: #fafafa;
+    color: #bdbdbd;
+    outline: none;
+    transition: border .24s ease-in-out;
+}
+
+
+@media only screen and (max-width: 615px) {
+    .flex__box {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+    }
+
+    .banner-wrap {
+        padding: 40px 0 146px;
+    }
+    .conteiner__images__pc {
+        margin-top: 20px;
+        margin-left: 5px;
+    }
+}
+
+@media only screen and (max-width: 700px) {
+    .conteiner__images__pc {
+        margin-top: 20px;
+        margin-left: 15px;
+    }
+}
+
+@media only screen and (min-width: 868px) {
+    .conteiner__images {
+        margin-top: 20px;
+        margin-left: 78px;
+    }
+}
+
+@media only screen and (min-width: 1100px) {
+    .conteiner__images {
+        margin-top: 20px;
+        margin-left: 78px;
+    }
+}

+ 142 - 156
src/components/productsUser/index.js

@@ -1,173 +1,159 @@
-import {useState, useEffect, useRef} from 'react';
-import {Provider, useDispatch, useSelector} from 'react-redux';
+import { useState, useEffect} from 'react';
+import { useDispatch, useSelector } from 'react-redux';
 import { makeStyles } from '@material-ui/core/styles';
-import Grid from '@material-ui/core/Grid';
 import Card from '@material-ui/core/Card';
-import TextField from '@material-ui/core/TextField';
 import CardActions from '@material-ui/core/CardActions';
 import CardContent from '@material-ui/core/CardContent';
 import CardMedia from '@material-ui/core/CardMedia';
-import { IconButton, Typography, Button} from '@material-ui/core';
-import AddAPhotoIcon from '@material-ui/icons/AddAPhoto';
+import {Typography, Button } from '@material-ui/core';
 import DeleteIcon from '@material-ui/icons/Delete';
 import CreateIcon from '@material-ui/icons/Create';
 import Paper from '@material-ui/core/Paper';
-import SearchIcon from '@material-ui/icons/Search';
-import InputBase from '@material-ui/core/InputBase';
 import VisibilityIcon from '@material-ui/icons/Visibility';
-import {origUrl, defaultImg, actioCreateAd, history} from '../../App.js';
+import { origUrl, defaultImg, history } from '../../App.js';
+import './productsUser.scss';
+import {connect } from 'react-redux';
+import { actionAllProductsUser} from '../../actions';
 
 
 
-const GoodCard = ({good}) => {
-    const dispatch = useDispatch();
-    const owner = useSelector(state => state.promise?.user?.payload)
-    const [indexArr, setindexArr] = useState(0)
-    const [createAd, setCreateAd] = useState({ title:good.title?good.title:"", description:good.description?good.description:"", price:good.price?good.price:0});
-    const onClickGoods = ()=>{
-        dispatch(actioCreateAd({...createAd, _id:good._id, tags: [''], address: owner.address}))
+const GoodCard = ({ good }) => {
+  const dispatch = useDispatch();
+  const owner = useSelector(state => state.promise?.user?.payload)
+  const [indexArr, setindexArr] = useState(0)
+  const [createAd, setCreateAd] = useState({ title: good.title ? good.title : "", description: good.description ? good.description : "", price: good.price ? good.price : 0 });
+
+  const onClickGoods = () => {
+    history.push("/change/" + good._id)
+  }
+  const useStylesImg = makeStyles({
+    button: {
+      margin: "3%"
+    },
+    input: {
+      margin: '3px'
+    },
+    inputDescription: {
+      margin: '3px',
+      width: '90%'
+    },
+
+    root: {
+      margin: "2%",
+      marginTop: "15px",
+      backgroundColor: '#a9a9a96b',
+    },
+    media: {
+      width: "100%",
+      height: 280,
+      borderRadius: "15px",
+    },
+    text: {
+      padding: '10px',
+      margin: '5px',
+      backgroundColor: '#3f51b500',
+    },
+    viev: {
+      marginLeft: '0px'
     }
-    const useStylesImg = makeStyles({
-        button:{
-            margin: "3%"
-        },
-        input:{
-            margin: '3px'
-        },
-        inputDescription:{
-            margin: '3px',
-            width: '90%'
-        },
-        mediaButton:{
-            display: "flex",
-            flexDirection: "column",
-            justifyContent: "space-around",
-            alignItems: "stretch"
-        },
-        contentCard:{
-            display: "flex",
-            flexDirection: "column",
-            width: "40%",
-        },
-        content:{
-            width: "60%",
-            display: "flex",
-            flexWrap: "wrap",
-            alignContent: "space-around",
-            justifyContent: "space-evenly",
-        },
-        root: {
-            display: "flex",
-            margin: "2%",
-            marginTop: "15px",
-        },
-        media: {
-            width: "100%",
-            height: 280,
-        },
-    })
-    return (
-    
-      <Card className={useStylesImg().root}>
-        <CardContent className={useStylesImg().contentCard}>
-            <CardMedia
-                className={useStylesImg().media}
-                onClick={()=>indexArr=== good.images.length-1?setindexArr(0) :setindexArr(indexArr+1)}
-                image={good.images&&good.images[indexArr]?origUrl+good.images[indexArr].url:defaultImg}
-                title="Contemplative Reptile"/>
-            <Button
-                className={useStylesImg().button}
-                type="submit"
-                fullWidth
-                variant="outlined"
-                color='primary'
-                startIcon={<AddAPhotoIcon />}>
-                Сhange photo
-            </Button>
-        </CardContent>
-        <CardContent className={useStylesImg().content}>
-        <TextField
-              value={createAd.title}
-              onChange={(e) => setCreateAd({...createAd, title: e.target.value})} 
-                className={useStylesImg().input} 
-                required id="standard-required" 
-                label="Title"  
-                />
-            <TextField 
-              type='number'
-              value={createAd.price}
-              onChange={(e) => setCreateAd({...createAd, price: +(e.target.value)})}
-                className={useStylesImg().input} 
-                required id="standard-required" 
-                label="Price $" 
-                />
-                <TextField 
-              value={createAd.description}
-              onChange={(e) => setCreateAd({...createAd, description: e.target.value})}
-                id="outlined-multiline-static"
-                label="Description"
-                className={useStylesImg().inputDescription} 
-                multiline
-                rows={4}
-                variant="outlined"
-              />
-          </CardContent>
-          <CardActions className={useStylesImg().mediaButton}>
-          <Button onClick={onClickGoods} color="inherit" variant="outlined" ><CreateIcon/> Сhange </Button>
-          <Button onClick={()=> history.push("/good/"+good._id)} color="inherit" variant="outlined" ><VisibilityIcon/> Open </Button>
-          <Button color="secondary" variant="contained"><DeleteIcon/> Delete </Button>
-        </CardActions>
-      
-      </Card>
-    
-  )}
-  
-  const CardsUser = ({loadData, productsUser=[], stat}) => {
-    const id = useSelector(state => state.auth?.payload?.sub?.id)
-    useEffect(() => {
-      loadData(id)
-    },[id])
-    const useStyles = makeStyles((theme) => ({
-      root: {
-        padding: '2px 4px',
-        display: 'flex',
-        alignItems: 'center',
-        marginTop: '55px',
-        marginBottom: '20px',
-        width: '70%',
-        marginLeft: '16%'
-      },
-      rootGrid:{
-        display: 'flex',
-        flexDirection: 'column',
-      },
-      input: {
-        marginLeft: theme.spacing(1),
-        flex: 1,
-      },
-      iconButton: {
-        padding: 10,
-      },
-    }));
-    const classes = useStyles()
-    if(stat==='PENDING'){
-      return(
-        <img className='preloader' src='https://i.pinimg.com/originals/c8/a1/76/c8a1765ffc8243f3a7b176c0ca84c3c1.gif' />
-      )
+  })
+  return (
+    <Card className='cardproducts'>
+      <CardContent className='contentCard'>
+        <CardMedia
+          className={useStylesImg().media}
+          onClick={() => indexArr === good.images.length - 1 ? setindexArr(0) : setindexArr(indexArr + 1)}
+          image={good.images && good.images[indexArr] ? origUrl + good.images[indexArr].url : defaultImg}
+          title="Contemplative Reptile" />
+      </CardContent>
+      <CardContent className='content'>
+        <Card className={useStylesImg().text}>
+          <Typography gutterBottom variant="h5" component="h2">
+            {good.title ? good.title : ""}
+          </Typography>
+        </Card>
+        <Card className={useStylesImg().text}>
+          <Typography gutterBottom variant="h6" component="h3">
+            {"Цена: " + (good.price ? good.price : 0) + " грн"}
+          </Typography>
+        </Card>
+        <Card className={useStylesImg().text}>
+          <Typography gutterBottom variant="h6" component="h5">
+            {good.description ? good.description : ""}
+          </Typography>
+        </Card>
+      </CardContent>
+      <CardActions className='mediaButton'>
+        <Button onClick={onClickGoods} color="inherit" variant="outlined" ><CreateIcon /> Сhange </Button>
+        <Button className={useStylesImg().viev} onClick={() => history.push("/good/" + good._id)} color="inherit" variant="outlined" ><VisibilityIcon /> view </Button>
+        <Button color="secondary" variant="contained"><DeleteIcon /> Delete </Button>
+      </CardActions>
+    </Card>
+  )
+}
+
+const CardsUser = ({ loadData, productsUser = [], stat }) => {
+  const id = useSelector(state => state.auth?.payload?.sub?.id)
+  useEffect(() => {
+    loadData(id)
+  }, [id])
+  const useStyles = makeStyles((theme) => ({
+    root: {
+      padding: '2px 4px',
+      display: 'flex',
+      justifyContent: 'space-around',
+      marginTop: '125px',
+      marginBottom: '20px',
+      width: '70%',
+      marginLeft: '16%',
+      padding: '15px'
+    },
+    rootGrid: {
+      flexDirection: 'column',
+      minHeight: '560px',
+      marginTop: '50px'
+    },
+    input: {
+      flex: 1,
+    },
+    iconButton: {
+      padding: 10,
+    },
+    div: {
+      minHeight: '560px'
     }
-    return(<>
-      <Paper component="form" className={classes.root}>
-      <IconButton className={classes.iconButton} aria-label="search">
-          <SearchIcon />
-        </IconButton>
-        <InputBase
-          className={classes.input}
-          placeholder="Search"/>
-      </Paper>
-    <Grid className={classes.rootGrid} container spacing={4} >
-    {productsUser.map(el=><GoodCard key={el._id} good={el} />)}
-    </Grid></>)
+  }));
+  const classes = useStyles()
+  if (stat === 'PENDING') {
+    return (
+      <img className='preloader' src='https://i.pinimg.com/originals/c8/a1/76/c8a1765ffc8243f3a7b176c0ca84c3c1.gif' />
+    )
+  } else if (stat === 'FULFILLED' && productsUser.length === 0) {
+    return (<>
+      <div className={classes.div}>
+        <Paper component="form" className={classes.root}>
+          You haven't posted any items yet
+        </Paper>
+      </div>
+    </>
+    )
   }
 
+  return (
+    <main className="mainProductsList">
+      <div className='products' >
+        {productsUser.reverse().map(el => <GoodCard key={el._id} good={el} />)}
+      </div>
+    </main>
+  )
+}
+
+
+const AllProductsUser = connect(state => ({
+  productsUser: state.promise?.productsUser?.payload || [],
+  stat: state.promise?.list?.status || []
+}),
+  { loadData: actionAllProductsUser })(CardsUser)
+
 
-  export default CardsUser
+export default AllProductsUser

+ 87 - 0
src/components/productsUser/productsUser.scss

@@ -0,0 +1,87 @@
+.mediaButton{
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+    align-items: stretch;
+}
+
+.contentCard{
+    flex-direction: column;
+    width: 40%;
+}
+
+.content{
+    width: 60%;
+    justify-content: space-evenly;
+    flex-direction: column;
+    max-width: 45%;
+}
+
+.products{
+    display: flex;
+    margin-top: 50px;
+    min-height: 560px;
+    flex-direction: column;
+}
+
+.cardproducts{
+    display: flex;
+    margin-bottom: 15px;
+}
+
+@media only screen and (max-width: 650px) {
+    .cardproducts{
+        display: flex;
+        margin-bottom: 15px;
+        flex-direction: column;
+    }
+
+    .contentCard{
+        flex-direction: column;
+        width: 90%;
+    }
+
+    .content{
+        width: 90%;
+        justify-content: space-evenly;
+        flex-direction: column;
+        max-width: 90%;
+    }
+
+    .mediaButton{
+        display: flex;
+        flex-direction: column;
+        justify-content: space-around;
+        align-items: stretch;
+        flex-direction: row;
+    }
+	
+}
+
+.mainProductsList{
+    background-color: #EEEFF1;
+    padding: 26px 36px 20px 36px;
+}
+
+@media only screen and (max-width: 650px) {
+	.mainProductsList{
+		background-color: #EEEFF1;
+		padding: 26px 16px 20px 16px;
+	}
+}
+
+@media only screen and (min-width: 868px) {
+    .cardproducts{
+        display: flex;
+        margin-bottom: 15px;
+    }
+	
+}
+
+@media only screen and (min-width: 1100px) {
+    .cardproducts{
+        display: flex;
+        margin-bottom: 15px;
+    }
+	
+}

+ 115 - 81
src/components/signIn/index.js

@@ -1,19 +1,23 @@
 import React from 'react';
 import Avatar from '@material-ui/core/Avatar';
-import  {Button} from '@material-ui/core';
+import { Button } from '@material-ui/core';
 import CssBaseline from '@material-ui/core/CssBaseline';
 import TextField from '@material-ui/core/TextField';
-import FormControlLabel from '@material-ui/core/FormControlLabel';
-import Checkbox from '@material-ui/core/Checkbox';
 import Link from '@material-ui/core/Link';
 import Grid from '@material-ui/core/Grid';
 import Box from '@material-ui/core/Box';
 import LockOutlinedIcon from '@material-ui/icons/LockOutlined';
 import Typography from '@material-ui/core/Typography';
+import { useSelector } from 'react-redux';
 import { makeStyles } from '@material-ui/core/styles';
 import Container from '@material-ui/core/Container';
-import {useState, useEffect, useRef} from 'react';
-import {actionLogin, store, actionAuthLogin, history} from '../../App.js';
+import { useState } from 'react';
+import { store, actionAuthLogin, history } from '../../App.js';
+import VisibilityIcon from '@material-ui/icons/Visibility';
+import InputAdornment from '@mui/material/InputAdornment';
+import { IconButton } from '@material-ui/core';
+import { actionLogin } from '../../actions';
+import VisibilityOffIcon from '@material-ui/icons/VisibilityOff';
 
 function Copyright() {
   return (
@@ -51,84 +55,114 @@ const useStyles = makeStyles((theme) => ({
 
 
 
-export default function SignIn() {
+function SignIn() {
   const classes = useStyles();
-  const [text, setText] = useState({login: '', pass: ''})
-  console.log(text)
-    async function buttonOnckick(){
-        const token = await store.dispatch(actionLogin(text.login, text.pass))
-        if (token){
-            store.dispatch(actionAuthLogin(token));
-            history.push("/")
-        }
+  const [text, setText] = useState({ login: '', pass: '' })
+  const [inputPass, setInputPass] = useState('password')
+  const [jwtToken, setJwtToken] = useState(false)
+
+  async function buttonOnckick() {
+    const token = await store.dispatch(actionLogin(text.login, text.pass))
+    if (token) {
+      store.dispatch(actionAuthLogin(token));
+      setJwtToken(false)
+      history.push("/page/1")
+    }else{
+      setJwtToken(true)
+    }
+  }
+  
+  const enterHandler = (event) => {
+    if (event.key === 'Enter') {
+      buttonOnckick()
     }
+  }
+
+  const seePassword = () => {
+    if (inputPass === 'password') {
+      setInputPass('text')
+    } else {
+      setInputPass('password')
+    }
+  }
+
   return (
-        <Container component="main" maxWidth="xs" >
-        <CssBaseline />
-        <div className={classes.paper}>
-            <Avatar className={classes.avatar}>
-            <LockOutlinedIcon />
-            </Avatar>
-            <Typography component="h1" variant="h5">
-            Sign in
-            </Typography>
-            <form className={classes.form} noValidate>
-            <TextField
-                value={text.login}
-                onChange={e => setText({...text, login: e.target.value})}
-                variant="outlined"
-                margin="normal"
-                required
-                fullWidth
-                id="email"
-                label="Email Address"
-                name="email"
-                autoComplete="email"
-                autoFocus
-            />
-            <TextField
-                value={text.pass}
-                onChange={e => setText({...text, pass: e.target.value})}
-                variant="outlined"
-                margin="normal"
-                required
-                fullWidth
-                name="password"
-                label="Password"
-                type="password"
-                id="password"
-                autoComplete="current-password"
-            />
-            <FormControlLabel
-                control={<Checkbox value="remember" color="primary" />}
-                label="Remember me"
-            />
-            <Button
-                onClick={buttonOnckick}
-                fullWidth
-                variant="contained"
-                color="primary"
-                className={classes.submit}
-            >
-                Sign In
-            </Button>
-            <Grid container>
-                <Grid item xs>
-                <Link href="#" variant="body2">
-                    Forgot password?
-                </Link>
-                </Grid>
-                <Grid item>
-                <Link href="#" variant="body2">
-                    {"Don't have an account? Sign Up"}
-                </Link>
-                </Grid>
+    <Container component="main" maxWidth="xs" >
+      <CssBaseline />
+      <div className={classes.paper}>
+        <Avatar className={classes.avatar}>
+          <LockOutlinedIcon />
+        </Avatar>
+        <Typography component="h1" variant="h5">
+          Sign in
+        </Typography>
+        <form className={classes.form} noValidate>
+          <TextField
+            onKeyPress={enterHandler}
+            value={text.login}
+            onChange={e => setText({ ...text, login: e.target.value })}
+            variant="outlined"
+            margin="normal"
+            required
+            fullWidth
+            id="email"
+            label="Email Address"
+            name="email"
+            autoComplete="email"
+            autoFocus
+          />
+          <TextField
+            onKeyPress={enterHandler}
+            value={text.pass}
+            onChange={e => setText({ ...text, pass: e.target.value })}
+            variant="outlined"
+            margin="normal"
+            required
+            fullWidth
+            InputProps={{
+              endAdornment: <InputAdornment position="end">
+                <IconButton onClick={seePassword}>
+                  {inputPass !== 'password' ? <VisibilityOffIcon /> : <VisibilityIcon />}
+                </IconButton>
+              </InputAdornment>,
+            }}
+            name="password"
+            label="Password"
+            type={inputPass}
+            id="password"
+            autoComplete="current-password"
+          />
+          <Typography variant="body2" color="secondary" >{jwtToken && 'Please enter a valid Email and/or password.'}</Typography>
+          <Button
+            onClick={buttonOnckick}
+            fullWidth
+            variant="contained"
+            color="primary"
+            className={classes.submit}
+          >
+            Sign In
+          </Button>
+          <Grid container>
+            <Grid item xs>
+              <Link href="#" variant="body2">
+                Forgot password?
+              </Link>
             </Grid>
-            </form>
-        </div>
-        <Box mt={8}>
-            <Copyright />
-        </Box>
-        </Container>
+            <Grid item>
+              <Link href="#" variant="body2">
+                {"Don't have an account? Sign Up"}
+              </Link>
+            </Grid>
+          </Grid>
+        </form>
+      </div>
+      <Box mt={8}>
+        <Copyright />
+      </Box>
+    </Container>
   );
-}
+}
+
+
+
+export default SignIn

+ 74 - 27
src/components/signup/index.js

@@ -12,16 +12,21 @@ import LockOutlinedIcon from '@material-ui/icons/LockOutlined';
 import Typography from '@material-ui/core/Typography';
 import { makeStyles } from '@material-ui/core/styles';
 import Container from '@material-ui/core/Container';
-import {useState, useEffect, useRef} from 'react';
-import {actionLogin, store, actionAuthLogin, actionRegister, history, actionUpdateMe, jwtDecode} from '../../App.js';
-import {useSelector, useDispatch} from "react-redux";
+import { useState} from 'react';
+import { store, actionAuthLogin, history, jwtDecode } from '../../App.js';
+import { useDispatch } from "react-redux";
+import VisibilityIcon from '@material-ui/icons/Visibility';
+import InputAdornment from '@mui/material/InputAdornment';
+import { IconButton } from '@material-ui/core';
+import VisibilityOffIcon from '@material-ui/icons/VisibilityOff';
+import { actionRegister, actionUpdateMe, actionLogin } from '../../actions';
 
 function Copyright() {
   return (
     <Typography variant="body2" color="textSecondary" align="center">
       {'Anton project © '}
       <Link color="inherit" href="https://mui.com/">
-      OLX
+        OLX
       </Link>{' '}
       {new Date().getFullYear()}
       {'.'}
@@ -55,23 +60,44 @@ const useStyles = makeStyles((theme) => ({
 export default function SignUp() {
   const classes = useStyles();
   const dispatch = useDispatch();
-  const [text, setText] = useState({login: '', pass: '', pass2: '', lastName:'', firstName:''})
-  
-    async function buttonOnckick(){
+  const [text, setText] = useState({ login: '', pass: '', pass2: '', lastName: '', firstName: '' })
+  const [inputPass, setInputPass] = useState('password')
+  const [user, setUser] = useState(false)
+  const [checkPass, setCheckPass] = useState(false)
+
+  async function buttonOnckick() {
+    if(text.pass.length>=6){
       const user = await dispatch(actionRegister(text.login, text.pass))
-      if(user) {
+      if (user) {
         const token = await dispatch(actionLogin(text.login, text.pass))
-        if (token){
+        if (token) {
 
-            await store.dispatch(actionAuthLogin(token));
-            const nick = text.lastName+" "+text.firstName
-            let profile={ login:text.login, nick: nick, addresses:'', phones:''}
-            const id=jwtDecode(token).sub?.id
-            dispatch(actionUpdateMe({nick, _id: id}));
-            history.push("/")
+          await store.dispatch(actionAuthLogin(token));
+          const nick = text.lastName + " " + text.firstName
+          let profile = { login: text.login, nick: nick, addresses: '', phones: '' }
+          const id = jwtDecode(token).sub?.id
+          dispatch(actionUpdateMe({ nick, _id: id }));
+          history.push("/page/1")
         }
+      }else{
+        setUser(true)
       }
+    }else{setCheckPass(true)}
+  }
+
+  const enterHandler = (event) => {
+    if (event.key === 'Enter') {
+      buttonOnckick()
     }
+  }
+
+  const seePassword = () => {
+    if (inputPass === 'password') {
+      setInputPass('text')
+    } else {
+      setInputPass('password')
+    }
+  }
   return (
     <Container component="main" maxWidth="xs">
       <CssBaseline />
@@ -84,10 +110,11 @@ export default function SignUp() {
         </Typography>
         <form className={classes.form} noValidate>
           <Grid container spacing={2}>
-          <Grid item xs={12} sm={6}>
+            <Grid item xs={12} sm={6}>
               <TextField
-              value={text.firstName}
-              onChange={e => setText({...text, firstName: e.target.value})}
+                onKeyPress={enterHandler}
+                value={text.firstName}
+                onChange={e => setText({ ...text, firstName: e.target.value })}
                 autoComplete="fname"
                 name="firstName"
                 variant="outlined"
@@ -100,8 +127,9 @@ export default function SignUp() {
             </Grid>
             <Grid item xs={12} sm={6}>
               <TextField
-              value={text.lastName}
-              onChange={e => setText({...text, lastName: e.target.value})}
+                onKeyPress={enterHandler}
+                value={text.lastName}
+                onChange={e => setText({ ...text, lastName: e.target.value })}
                 variant="outlined"
                 required
                 fullWidth
@@ -113,8 +141,9 @@ export default function SignUp() {
             </Grid>
             <Grid item xs={12}>
               <TextField
+                onKeyPress={enterHandler}
                 value={text.login}
-                onChange={e => setText({...text, login: e.target.value})}
+                onChange={e => setText({ ...text, login: e.target.value })}
                 variant="outlined"
                 required
                 fullWidth
@@ -126,33 +155,51 @@ export default function SignUp() {
             </Grid>
             <Grid item xs={12}>
               <TextField
+                onKeyPress={enterHandler}
                 value={text.pass}
-                onChange={e => setText({...text, pass: e.target.value})}
+                onChange={e => setText({ ...text, pass: e.target.value })}
                 variant="outlined"
                 required
                 fullWidth
+                InputProps={{
+                  endAdornment: <InputAdornment position="end">
+                    <IconButton onClick={seePassword}>
+                      {inputPass !== 'password' ? <VisibilityOffIcon /> : <VisibilityIcon />}
+                    </IconButton>
+                  </InputAdornment>,
+                }}
                 name="password"
                 label="Password"
-                type="password"
+                type={inputPass}
                 id="password"
                 autoComplete="current-password"
               />
             </Grid>
             <Grid item xs={12}>
               <TextField
+                onKeyPress={enterHandler}
                 value={text.pass2}
-                onChange={e => setText({...text, pass2: e.target.value})}
+                onChange={e => setText({ ...text, pass2: e.target.value })}
                 variant="outlined"
                 required
                 fullWidth
+                InputProps={{
+                  endAdornment: <InputAdornment position="end">
+                    <IconButton onClick={seePassword}>
+                      {inputPass !== 'password' ? <VisibilityOffIcon /> : <VisibilityIcon />}
+                    </IconButton>
+                  </InputAdornment>,
+                }}
                 name="password"
                 label="Password"
-                type="password"
+                type={inputPass}
                 id="password"
                 autoComplete="current-password"
               />
             </Grid>
-            <Typography variant="body2" color="secondary" className={classes.typography}>{text.pass!==text.pass2&&'Passwords do not match'}</Typography>
+            <Typography variant="body2" color="secondary" className={classes.typography}>{text.pass !== text.pass2 && 'Passwords do not match'}</Typography>
+            <Typography variant="body2" color="secondary" className={classes.typography}>{user && 'Such user already exists'}</Typography>
+            <Typography variant="body2" color="secondary" className={classes.typography}>{checkPass && 'Password must contain at least 6 characters'}</Typography>
             <Grid item xs={12}>
               <FormControlLabel
                 control={<Checkbox value="allowExtraEmails" color="primary" />}
@@ -161,7 +208,7 @@ export default function SignUp() {
             </Grid>
           </Grid>
           <Button
-            onClick={text.pass===text.pass2&&buttonOnckick}
+            onClick={text.pass === text.pass2 && buttonOnckick}
             fullWidth
             variant="contained"
             color="primary"