Browse Source

add mui not all

Vitalii Polishchuk 2 years ago
parent
commit
118a9dbca6

+ 315 - 2
package-lock.json

@@ -1203,6 +1203,120 @@
       "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-10.1.0.tgz",
       "integrity": "sha512-ij4wRiunFfaJxjB0BdrYHIH8FxBJpOwNPhhAcunlmPdXudL1WQV1qoP9un6JsEBAgQH+7UXyyjh0g7jTxXK6tg=="
     },
+    "@emotion/babel-plugin": {
+      "version": "11.3.0",
+      "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.3.0.tgz",
+      "integrity": "sha512-UZKwBV2rADuhRp+ZOGgNWg2eYgbzKzQXfQPtJbu/PLy8onurxlNCLvxMQEvlr1/GudguPI5IU9qIY1+2z1M5bA==",
+      "requires": {
+        "@babel/helper-module-imports": "^7.12.13",
+        "@babel/plugin-syntax-jsx": "^7.12.13",
+        "@babel/runtime": "^7.13.10",
+        "@emotion/hash": "^0.8.0",
+        "@emotion/memoize": "^0.7.5",
+        "@emotion/serialize": "^1.0.2",
+        "babel-plugin-macros": "^2.6.1",
+        "convert-source-map": "^1.5.0",
+        "escape-string-regexp": "^4.0.0",
+        "find-root": "^1.1.0",
+        "source-map": "^0.5.7",
+        "stylis": "^4.0.3"
+      },
+      "dependencies": {
+        "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=="
+        }
+      }
+    },
+    "@emotion/cache": {
+      "version": "11.5.0",
+      "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.5.0.tgz",
+      "integrity": "sha512-mAZ5QRpLriBtaj/k2qyrXwck6yeoz1V5lMt/jfj6igWU35yYlNKs2LziXVgvH81gnJZ+9QQNGelSsnuoAy6uIw==",
+      "requires": {
+        "@emotion/memoize": "^0.7.4",
+        "@emotion/sheet": "^1.0.3",
+        "@emotion/utils": "^1.0.0",
+        "@emotion/weak-memoize": "^0.2.5",
+        "stylis": "^4.0.10"
+      }
+    },
+    "@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.1.0",
+      "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.1.0.tgz",
+      "integrity": "sha512-9RkilvXAufQHsSsjQ3PIzSns+pxuX4EW8EbGeSPjZMHuMx6z/MOzb9LpqNieQX4F3mre3NWS2+X3JNRHTQztUQ==",
+      "requires": {
+        "@emotion/memoize": "^0.7.4"
+      }
+    },
+    "@emotion/memoize": {
+      "version": "0.7.5",
+      "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz",
+      "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ=="
+    },
+    "@emotion/react": {
+      "version": "11.5.0",
+      "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.5.0.tgz",
+      "integrity": "sha512-MYq/bzp3rYbee4EMBORCn4duPQfgpiEB5XzrZEBnUZAL80Qdfr7CEv/T80jwaTl/dnZmt9SnTa8NkTrwFNpLlw==",
+      "requires": {
+        "@babel/runtime": "^7.13.10",
+        "@emotion/cache": "^11.5.0",
+        "@emotion/serialize": "^1.0.2",
+        "@emotion/sheet": "^1.0.3",
+        "@emotion/utils": "^1.0.0",
+        "@emotion/weak-memoize": "^0.2.5",
+        "hoist-non-react-statics": "^3.3.1"
+      }
+    },
+    "@emotion/serialize": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.2.tgz",
+      "integrity": "sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A==",
+      "requires": {
+        "@emotion/hash": "^0.8.0",
+        "@emotion/memoize": "^0.7.4",
+        "@emotion/unitless": "^0.7.5",
+        "@emotion/utils": "^1.0.0",
+        "csstype": "^3.0.2"
+      }
+    },
+    "@emotion/sheet": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.0.3.tgz",
+      "integrity": "sha512-YoX5GyQ4db7LpbmXHMuc8kebtBGP6nZfRC5Z13OKJMixBEwdZrJ914D6yJv/P+ZH/YY3F5s89NYX2hlZAf3SRQ=="
+    },
+    "@emotion/styled": {
+      "version": "11.3.0",
+      "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.3.0.tgz",
+      "integrity": "sha512-fUoLcN3BfMiLlRhJ8CuPUMEyKkLEoM+n+UyAbnqGEsCd5IzKQ7VQFLtzpJOaCD2/VR2+1hXQTnSZXVJeiTNltA==",
+      "requires": {
+        "@babel/runtime": "^7.13.10",
+        "@emotion/babel-plugin": "^11.3.0",
+        "@emotion/is-prop-valid": "^1.1.0",
+        "@emotion/serialize": "^1.0.2",
+        "@emotion/utils": "^1.0.0"
+      }
+    },
+    "@emotion/unitless": {
+      "version": "0.7.5",
+      "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz",
+      "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="
+    },
+    "@emotion/utils": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.0.0.tgz",
+      "integrity": "sha512-mQC2b3XLDs6QCW+pDQDiyO/EdGZYOygE8s5N5rrzjSI4M3IejPE/JPndCBwRT9z982aqQNi6beWs1UeayrQxxA=="
+    },
+    "@emotion/weak-memoize": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz",
+      "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA=="
+    },
     "@eslint/eslintrc": {
       "version": "0.4.3",
       "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
@@ -1836,6 +1950,120 @@
         }
       }
     },
+    "@mui/core": {
+      "version": "5.0.0-alpha.51",
+      "resolved": "https://registry.npmjs.org/@mui/core/-/core-5.0.0-alpha.51.tgz",
+      "integrity": "sha512-Dum1SM5qk9eGeC6TLw6Au/53yuHqpkFM65hFYEtZccjJhUtdQMve+XVsmhgYPNkhiC0HyWgIR8Q5E1q5Fkc+pQ==",
+      "requires": {
+        "@babel/runtime": "^7.15.4",
+        "@emotion/is-prop-valid": "^1.1.0",
+        "@mui/utils": "^5.0.1",
+        "clsx": "^1.1.1",
+        "prop-types": "^15.7.2",
+        "react-is": "^17.0.2"
+      },
+      "dependencies": {
+        "react-is": {
+          "version": "17.0.2",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+          "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+        }
+      }
+    },
+    "@mui/icons-material": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.0.4.tgz",
+      "integrity": "sha512-pW/2bjRGnBZujoLdtH/C+ghT0Tmlk9HmZHF6HuALuVOnRiHF9VwrcNrx0FLHYT0aMARZR4dBA15nU/53R1YNeQ==",
+      "requires": {
+        "@babel/runtime": "^7.15.4"
+      }
+    },
+    "@mui/material": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.0.4.tgz",
+      "integrity": "sha512-075EXSBHoEYeFkE5WDtXyxfd+bNIQRvqlgiouukvMqLGta1EmLq9H6+ONYV4I0Luug8NvNyRocVyRwdjH0Ufmw==",
+      "requires": {
+        "@babel/runtime": "^7.15.4",
+        "@mui/core": "5.0.0-alpha.51",
+        "@mui/system": "^5.0.4",
+        "@mui/types": "^7.0.0",
+        "@mui/utils": "^5.0.1",
+        "@popperjs/core": "^2.4.4",
+        "@types/react-transition-group": "^4.4.3",
+        "clsx": "^1.1.1",
+        "csstype": "^3.0.9",
+        "hoist-non-react-statics": "^3.3.2",
+        "prop-types": "^15.7.2",
+        "react-is": "^17.0.2",
+        "react-transition-group": "^4.4.2"
+      },
+      "dependencies": {
+        "react-is": {
+          "version": "17.0.2",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+          "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+        }
+      }
+    },
+    "@mui/private-theming": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.0.1.tgz",
+      "integrity": "sha512-R8Cf2+32cG1OXFAqTighA5Mx9R5BQ57cN1ZVaNgfgdbI87Yig2fVMdFSPrw3txcjKlnwsvFJF8AdwQMqq1tJ3Q==",
+      "requires": {
+        "@babel/runtime": "^7.15.4",
+        "@mui/utils": "^5.0.1",
+        "prop-types": "^15.7.2"
+      }
+    },
+    "@mui/styled-engine": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.0.1.tgz",
+      "integrity": "sha512-j40nCbaKr1HAZYqpX61XvZYsadYskjo3u6+pRFFaewSViAkkD1rjjbubpnh15nqVfYmijtHMZJ9/l1x1hamvfQ==",
+      "requires": {
+        "@babel/runtime": "^7.15.4",
+        "@emotion/cache": "^11.4.0",
+        "prop-types": "^15.7.2"
+      }
+    },
+    "@mui/system": {
+      "version": "5.0.4",
+      "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.0.4.tgz",
+      "integrity": "sha512-d+7dhT0eBGrPoah91GX1Q2i4S/5QsiVAp7e06lIMC/LXFWQSrsSnvNbVnW8TgttCvo0ypQ/RHNmWZ/f1eAbd/Q==",
+      "requires": {
+        "@babel/runtime": "^7.15.4",
+        "@mui/private-theming": "^5.0.1",
+        "@mui/styled-engine": "^5.0.1",
+        "@mui/types": "^7.0.0",
+        "@mui/utils": "^5.0.1",
+        "clsx": "^1.1.1",
+        "csstype": "^3.0.9",
+        "prop-types": "^15.7.2"
+      }
+    },
+    "@mui/types": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.0.0.tgz",
+      "integrity": "sha512-M/tkF2pZ4uoPhZ8pnNhlVnOFtz6F3dnYKIsnj8MuXKT6d26IE2u0UjA8B0275ggN74dR9rlHG5xJt5jgDx/Ung=="
+    },
+    "@mui/utils": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.0.1.tgz",
+      "integrity": "sha512-GWO104N+o9KG5fKiTEYnAg7kONKEg3vLN+VROAU0f3it6lFGLCVPcQYex/1gJ4QAy96u6Ez8/Hmmhi1+3cX0tQ==",
+      "requires": {
+        "@babel/runtime": "^7.15.4",
+        "@types/prop-types": "^15.7.4",
+        "@types/react-is": "^16.7.1 || ^17.0.0",
+        "prop-types": "^15.7.2",
+        "react-is": "^17.0.2"
+      },
+      "dependencies": {
+        "react-is": {
+          "version": "17.0.2",
+          "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
+          "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+        }
+      }
+    },
     "@nodelib/fs.scandir": {
       "version": "2.1.5",
       "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1914,6 +2142,11 @@
         }
       }
     },
+    "@popperjs/core": {
+      "version": "2.10.2",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.2.tgz",
+      "integrity": "sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ=="
+    },
     "@rollup/plugin-node-resolve": {
       "version": "7.1.3",
       "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz",
@@ -2534,6 +2767,14 @@
         "csstype": "^3.0.2"
       }
     },
+    "@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-redux": {
       "version": "7.1.18",
       "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz",
@@ -2545,6 +2786,14 @@
         "redux": "^4.0.0"
       }
     },
+    "@types/react-transition-group": {
+      "version": "4.4.4",
+      "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz",
+      "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==",
+      "requires": {
+        "@types/react": "*"
+      }
+    },
     "@types/resolve": {
       "version": "0.0.8",
       "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
@@ -3850,6 +4099,15 @@
       "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
       "optional": true
     },
+    "bindings": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+      "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+      "optional": true,
+      "requires": {
+        "file-uri-to-path": "1.0.0"
+      }
+    },
     "blob": {
       "version": "0.0.5",
       "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
@@ -4347,6 +4605,11 @@
         "wrap-ansi": "^6.2.0"
       }
     },
+    "clsx": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
+      "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="
+    },
     "co": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -5338,6 +5601,15 @@
         "utila": "~0.4"
       }
     },
+    "dom-helpers": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
+      "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
+      "requires": {
+        "@babel/runtime": "^7.8.7",
+        "csstype": "^3.0.2"
+      }
+    },
     "dom-serializer": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
@@ -6819,6 +7091,12 @@
         }
       }
     },
+    "file-uri-to-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+      "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+      "optional": true
+    },
     "filesize": {
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz",
@@ -6871,6 +7149,11 @@
         "pkg-dir": "^3.0.0"
       }
     },
+    "find-root": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
+      "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
+    },
     "find-up": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@@ -10518,6 +10801,12 @@
       "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
       "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
     },
+    "nan": {
+      "version": "2.15.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz",
+      "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==",
+      "optional": true
+    },
     "nanocolors": {
       "version": "0.2.12",
       "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.2.12.tgz",
@@ -12943,6 +13232,17 @@
         "raf": "^3.4.1"
       }
     },
+    "react-transition-group": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz",
+      "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==",
+      "requires": {
+        "@babel/runtime": "^7.5.5",
+        "dom-helpers": "^5.0.1",
+        "loose-envify": "^1.4.0",
+        "prop-types": "^15.6.2"
+      }
+    },
     "read-pkg": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
@@ -14648,6 +14948,11 @@
         }
       }
     },
+    "stylis": {
+      "version": "4.0.10",
+      "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.10.tgz",
+      "integrity": "sha512-m3k+dk7QeJw660eIKRRn3xPF6uuvHs/FFzjX3HQ5ove0qYsiygoAhwn5a3IYKaZPo5LrYD0rfVmtv1gNY1uYwg=="
+    },
     "supports-color": {
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -15602,7 +15907,11 @@
           "version": "1.2.13",
           "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
           "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
-          "optional": true
+          "optional": true,
+          "requires": {
+            "bindings": "^1.5.0",
+            "nan": "^2.12.1"
+          }
         },
         "glob-parent": {
           "version": "3.1.0",
@@ -16177,7 +16486,11 @@
           "version": "1.2.13",
           "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
           "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
-          "optional": true
+          "optional": true,
+          "requires": {
+            "bindings": "^1.5.0",
+            "nan": "^2.12.1"
+          }
         },
         "glob-parent": {
           "version": "3.1.0",

+ 4 - 0
package.json

@@ -3,6 +3,10 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
+    "@emotion/react": "^11.5.0",
+    "@emotion/styled": "^11.3.0",
+    "@mui/icons-material": "^5.0.4",
+    "@mui/material": "^5.0.4",
     "@testing-library/jest-dom": "^5.14.1",
     "@testing-library/react": "^11.2.7",
     "@testing-library/user-event": "^12.8.3",

+ 4 - 0
src/App.css

@@ -216,3 +216,7 @@ textarea {
 .btn-scroll {
   position: fixed;
 }
+
+.new-chat {
+  width: 50%;
+}

+ 3 - 13
src/App.js

@@ -3,27 +3,17 @@ import React from 'react';
 import { Provider } from 'react-redux';
 import store from './reducers';
 import ConnectRoutes from './components/routes';
-
-
-// const Preloading = ({ promiseName, promiseState, children }) => {
-//   return (
-//     <>
-//       {(promiseState[promiseName] && promiseState[promiseName].status === "RESOLVED") ? children : null}
-//     </>
-//   )
-// }
-
-// const CPreloading = connect(state => ({ promiseState: state.promise }))
+import { CssBaseline } from '@mui/material';
 
 store.subscribe(() => console.log(store.getState()))
 
 function App() {
   return (
-    <div className="app">
+    <CssBaseline>
       <Provider store={store}>
         <ConnectRoutes />
       </Provider>
-    </div >
+    </ CssBaseline>
   );
 }
 

+ 2 - 2
src/actions/index.js

@@ -305,8 +305,8 @@ let changeNick = async (userID, nick) => {
 }
 
 let changeUserAvatar = async (userID, imageID) => {
-  let query = `mutation setUserAvatar($avatar: MediaInput){
-    MediaUpsert(media: $avatar){
+  let query = `mutation setUserAvatar($avatar: ImageInput){
+    ImageUpsert(image: $avatar){
       _id text url
     }
   }`

+ 19 - 0
src/components/chatBar.js

@@ -0,0 +1,19 @@
+import { Button } from "@mui/material"
+import { Box } from "@mui/system"
+
+export const ChatBar = ({ chat_title, onInfo }) => {
+    return (
+        <Box
+            sx={{
+                display: 'flex',
+                alignItems: 'center',
+                justifyContent: 'space-between',
+                color: 'white',
+            }}
+        >
+            <span>{chat_title}</span>
+            <Button onClick={() => onInfo()} variant="text" sx={{ color: "white", }}>Инфо</Button>
+        </Box >
+
+    )
+}

+ 21 - 7
src/components/chatEditForm.js

@@ -1,3 +1,4 @@
+import { Avatar, Button, ButtonGroup, TextField } from "@mui/material"
 import { useEffect, useState } from "react"
 import { connect } from "react-redux"
 import { actionFullEditChat, actionUserSearch } from "../actions"
@@ -10,7 +11,7 @@ const ChatEditForm = ({ chat_id, chat, searchState, onUserSearch, onChangeChat }
     let [newAvatar, setNewAvatar] = useState([])
     let [newMembers, setNewMembers] = useState(chat.members)
 
-    console.log(newAvatar)
+
     useEffect(() => {
         setEdit(false)
         setNewTitle(chat.title)
@@ -33,19 +34,32 @@ const ChatEditForm = ({ chat_id, chat, searchState, onUserSearch, onChangeChat }
 
     return (
         <div className="chat-edit-form">
-            {edit ? <input onChange={(e) => setNewTitle(e.target.value)} value={newTitle} /> : <span>Название чата: {chat.title}</span>}
             {edit ? <div>
                 <span>Загрузите новый аватар</span>
                 <ConnectDropzone maxFiles={1} onSet={setNewAvatar} />
             </div> :
-                chat.avatar && <img src={"/" + chat.avatar.url} alt="chatAvatar" />}
+                chat.avatar && <Avatar src={"/" + chat.avatar.url} alt="chatAvatar" sx={{ width: 60, height: 60 }} />}
+            {edit ? <TextField
+                label="Сменить название чата"
+                variant="standard"
+                onChange={(e) => setNewTitle(e.target.value)}
+                value={newTitle}
+                placeholder="Сменить название чата" /> : <span>Название чата: {chat.title}</span>}
 
             {<MemberList members={newMembers} onDeleteMember={edit && memberDeleteHandler} />}
             {edit && <UserSearch searchState={searchState} onUserSearch={onUserSearch} onAddMember={userAddHandler} />}
-            <div className="edit-btn-container">
-                <button onClick={() => editChatHandler()} >{edit ? "Отменить редактирование" : "Редактировать чат"}</button>
-                {edit && <button onClick={() => onChangeChat(chat_id, newTitle, newAvatar[0]?._id, newMembers)}>Применить изменения</button>}
-            </div>
+
+            <ButtonGroup size="small">
+                <Button variant="outlined" onClick={() => editChatHandler()} >
+                    {edit ? "Отменить редактирование" : "Редактировать чат"}
+                </Button>
+
+                {edit &&
+                    <Button variant="contained" onClick={() => onChangeChat(chat_id, newTitle, newAvatar[0]?._id, newMembers)}>
+                        Применить изменения
+                    </Button>}
+            </ButtonGroup>
+
         </div>
     )
 }

+ 20 - 9
src/components/chatForm.js

@@ -1,3 +1,4 @@
+import { Button, Chip, TextField } from "@mui/material";
 import { useEffect, useState } from "react";
 import { connect } from "react-redux";
 import { actionAddChatBack, actionUserSearch } from "../actions"
@@ -6,8 +7,8 @@ const UserList = ({ users, onAddMember }) => {
     return (
         <ul className="user-search-list">
             {users.map(user =>
-                <li key={user._id}>
-                    <button onClick={() => onAddMember(user)}>{user.nick || user.login}</button>
+                <li key={user._id} >
+                    <Button variant="text" onClick={() => onAddMember(user)}>{user.nick || user.login}</Button>
                 </li>)}
         </ul>
     )
@@ -33,8 +34,12 @@ export const UserSearch = ({ searchState, onUserSearch, onAddMember }) => {
 
     return (
         <div className="user-search-panel">
-            <span>Добавьте пользователей</span>
-            <input onInput={e => searchHandler(e)} value={searchInput} placeholder="Введите имя пользователя..." />
+            <TextField
+                label="Найти юзеров..."
+                variant="standard"
+                onInput={e => searchHandler(e)}
+                value={searchInput}
+                placeholder="Найти юзеров..." />
             {searchInput && users && users.length > 0 && <UserList users={users} onAddMember={onAddMember} />}
             {searchState && searchInput && users && !users.length && <span>Пользователей с таким именем не существует</span>}
         </div>
@@ -48,8 +53,10 @@ export const MemberList = ({ members, onDeleteMember }) => {
             <ul>
                 {members.map(m =>
                     <li key={m._id}>
-                        <span>{m.nick || m.login}</span>
-                        {onDeleteMember && <button onClick={() => onDeleteMember(m)}>x</button>}
+                        {onDeleteMember ? <Chip
+                            label={m.nick || m.login}
+                            onDelete={() => onDeleteMember(m)}
+                        /> : <span>{m.nick || m.login}</span>}
                     </li>
                 )}
             </ul>
@@ -71,11 +78,15 @@ const ChatForm = ({ searchState, onUserSearch, onNewChat }) => {
 
     return (
         <div className="new-chat">
-            <span>Выберите чат или создайте новый</span>
-            <input onInput={e => setTitle(e.target.value)} value={title} placeholder="Введите название чата" />
+            <TextField
+                label="Название чата"
+                variant="standard"
+                onInput={e => setTitle(e.target.value)}
+                value={title}
+                placeholder="Название чата" />
             <UserSearch searchState={searchState} onUserSearch={onUserSearch} onAddMember={userAddHandler} />
             {members && members.length > 0 && <MemberList members={members} onDeleteMember={memberDeleteHandler} />}
-            <button onClick={() => onNewChat(title, members)} disabled={!title || !members.length}>Создать чат</button>
+            <Button variant="contained" onClick={() => onNewChat(title, members)} disabled={!title || !members.length}>Создать чат</Button>
         </div>
     )
 }

+ 20 - 0
src/components/chatItem.js

@@ -0,0 +1,20 @@
+import * as React from 'react';
+import ListItemText from '@mui/material/ListItemText';
+import ReactTimeAgo from 'react-time-ago'
+import { ListItemAvatar, ListItem, Avatar } from '@mui/material';
+import TimeAgo from 'javascript-time-ago'
+import ru from 'javascript-time-ago/locale/ru.json'
+import { Link } from 'react-router-dom'
+
+TimeAgo.addLocale(ru)
+
+export const ChatItem = ({ id, chat }) => {
+
+    return (
+        <ListItem button component={Link} to={`/chat_id.${id}`} divider >
+            <ListItemAvatar>{chat.avatar ? <Avatar src={chat.avatar.url} alt="chat-avatar" sx={{ width: 60, height: 60 }} /> : <Avatar>{chat.title[0]}</Avatar>}</ListItemAvatar>
+            < ListItemText primary={chat.title} />
+            {chat.lastModified && <ReactTimeAgo date={+(chat.lastModified)} locale="ru" timeStyle="round" />}
+        </ListItem >
+    )
+}

+ 38 - 14
src/components/chatWindow.js

@@ -1,12 +1,17 @@
 import { useEffect, useRef, useState } from "react"
 import { Message, ShortMessage } from "./message"
 import { MyDropzone } from "./dropzone"
+import { Backdrop, Button, CircularProgress, List, TextField } from "@mui/material"
+import SendIcon from '@mui/icons-material/Send';
+import AttachFileIcon from '@mui/icons-material/AttachFile';
+import { Box } from "@mui/system";
+import { ArrowCircleDown } from "@mui/icons-material";
 
 const updateScroll = (el) => {
     el.scrollTop = el.scrollHeight
 }
 
-const Chat = ({ chat_id, chat_title, user_id, messages, onUpload, onSend, onMSGEdit, onScrollTopComplete, onInfo }) => {
+const Chat = ({ chat_id, chat_title, user_id, messages, isLoad, onUpload, onSend, onMSGEdit, onScrollTopComplete }) => {
     let [msg, setMSG] = useState("")
     let [isUpload, setIsUpload] = useState(false)
     let [files, setFiles] = useState([])
@@ -77,13 +82,15 @@ const Chat = ({ chat_id, chat_title, user_id, messages, onUpload, onSend, onMSGE
     }
 
     return (
-        <div className="chat-window">
-            <div className="chat-nav">
-                <span>{chat_title}</span>
-                <button onClick={() => onInfo()}>Инфо</button>
-            </div>
-
-            <ul ref={scrollRef} onScroll={() => scrollHandler(scrollRef.current)} className="message-list">
+        <Box>
+            {isLoad === "PENDING" && <Backdrop
+                sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer + 1 }}
+                open={true}
+            >
+                <CircularProgress color="inherit" />
+            </Backdrop>}
+
+            <List ref={scrollRef} onScroll={() => scrollHandler(scrollRef.current)} sx={{ maxWidth: '100%', height: '85vh', overflowY: 'auto', display: 'flex', flexDirection: 'column' }}>
                 {messages.length > 0 &&
                     messages.map(message => {
                         return <Message key={message._id}
@@ -98,7 +105,7 @@ const Chat = ({ chat_id, chat_title, user_id, messages, onUpload, onSend, onMSGE
                             onMSGReply={setIsReply}
                             onMSGForward={setIsForward} />
                     })}
-            </ul>
+            </List>
 
             {isReply[0] &&
                 messages.filter(message => message._id === isReply[1]).map(m =>
@@ -106,15 +113,32 @@ const Chat = ({ chat_id, chat_title, user_id, messages, onUpload, onSend, onMSGE
                         text={m.text}
                         date={m.createdAt} />)}
 
-            {!isScroll && <button className="btn-scroll" onClick={() => buttonScrollHandler()}>Вниз</button>}
+            {!isScroll && <Button size='large'
+                onClick={() => buttonScrollHandler()}
+                sx={{
+                    position: 'fixed',
+                    bottom: '10vh',
+                    left: '25vw',
+                }}><ArrowCircleDown /></Button>}
 
             <div className="message-input">
-                <textarea ref={input} placeholder="Введите сообщение..." value={msg} onFocus={() => updateScroll(scrollRef.current)} onInput={(e) => setMSG(e.target.value)} onKeyDown={(e) => sendHandler(e)} />
-                <button onClick={() => setIsUpload(!isUpload)}>Прикрепить файл</button>
+                <TextField
+                    label="Введите сообщение..."
+                    placeholder="Введите сообщение..."
+                    variant="outlined"
+                    fullWidth
+                    multiline
+                    ref={input}
+                    value={msg}
+                    onFocus={() => updateScroll(scrollRef.current)}
+                    onInput={(e) => setMSG(e.target.value)}
+                    onKeyDown={(e) => sendHandler(e)}
+                />
                 {isUpload && <MyDropzone onUpload={onUpload} onSet={filesHandler} />}
-                <button onClick={(e) => sendHandler(e)}>Отправить</button>
+                <Button onClick={() => setIsUpload(!isUpload)} variant="outlined"><AttachFileIcon /></Button>
+                <Button onClick={(e) => sendHandler(e)} variant="contained" endIcon={<SendIcon />}>Отправить</Button>
             </div>
-        </div >
+        </ Box>
     )
 }
 

+ 30 - 27
src/components/chatsList.js

@@ -1,39 +1,42 @@
-import { Link } from "react-router-dom"
-import ReactTimeAgo from 'react-time-ago'
 import TimeAgo from 'javascript-time-ago'
 import ru from 'javascript-time-ago/locale/ru.json'
-import React from 'react';
+import React, { useState } from 'react';
 import { connect } from "react-redux";
+import { ChatItem } from "./chatItem";
+import { Box, List, Fab, ListItem } from '@mui/material'
+import history from '../components/history';
+import AddIcon from '@mui/icons-material/Add';
 
 TimeAgo.addLocale(ru)
 
-const ChatItem = ({ id, chat }) => {
-
-    return (
-        <li className="aside-chat" >
-            <Link to={`/chat_id.${id}`}>
-                {chat.avatar && <img src={chat.avatar.url} alt="chat-avatar" />}
-                <div className="aside-chat-info">
+const ChatsList = ({ chats }) => {
+    const [selected, setSelected] = useState(false)
 
-                    <h5>{chat.title}</h5>
-                    <span>Последнее обновление: </span>
-                    {chat.lastModified && <ReactTimeAgo date={+(chat.lastModified)} locale="ru" timeStyle="round" />}
-                </div>
-            </Link>
-        </li>
-    )
-}
+    const handleListItemClick = (event, id) => {
+        setSelected(id)
+    }
 
-const ChatsList = ({ chats }) => {
     return (
-        <>
-            <ul className="chat-list">
-                <li className="aside-chat-btn">
-                    <Link to="/chat">Новый чат</Link>
-                </li>
-                {Object.entries(chats).map(([id, chat]) => <ChatItem key={id} id={id} chat={chat} />)}
-            </ul>
-        </>
+        <Box sx={{ width: '100%', bgcolor: 'background.paper' }}>
+            <List component="nav" aria-label="main mailbox folders" sx={{
+                width: '100%',
+                bgcolor: 'background.paper',
+                position: 'relative',
+                overflow: 'auto',
+                maxHeight: '93vh',
+            }}>
+                {Object.entries(chats).map(([id, chat]) => <ChatItem key={id} id={id} chat={chat} selected={selected} handle={handleListItemClick} />)}
+                <ListItem sx={{
+                    position: 'fixed',
+                    bottom: '10px',
+                    left: '18%',
+                }}>
+                    <Fab color="primary" aria-label="add" onClick={() => history.push("/chat")}>
+                        <AddIcon />
+                    </Fab>
+                </ListItem>
+            </List>
+        </Box >
     )
 }
 

+ 1 - 6
src/components/dropzone.js

@@ -26,13 +26,8 @@ export const MyDropzone = ({ maxFiles, onUpload, onSet }) => {
         <div>
             <div {...getRootProps()}>
                 <input {...getInputProps()} />
-                <p>Drag 'n' drop some files here, or click to select files</p>
-                {maxFiles && <span>Max files: {maxFiles}</span>}
+                <span>Drag 'n' drop here, or click to select</span>
             </div>
-            <aside>
-                <h4>Files</h4>
-                <ul>{files}</ul>
-            </aside>
         </div>
     )
 }

+ 50 - 48
src/components/message.js

@@ -2,50 +2,10 @@ import ReactTimeAgo from 'react-time-ago'
 import TimeAgo from 'javascript-time-ago'
 import ru from 'javascript-time-ago/locale/ru.json'
 import { useCallback, useState, useEffect, useRef } from 'react'
+import { ListItem, Menu, MenuItem } from '@mui/material'
 
 TimeAgo.addLocale(ru)
 
-const ContextMenu = ({ element, message, owner, onEdit, onReplyTo, onForwardTo }) => {
-    const [points, setPoints] = useState({ x: 0, y: 0 })
-    const [show, setShow] = useState("none")
-
-    const handler = useCallback(e => {
-        e.preventDefault()
-        setPoints({ x: e.pageX, y: e.pageY })
-        setShow("flex")
-    }, [setShow, setPoints])
-
-    const clickHandler = useCallback(() => setShow("none"), [setShow]);
-
-    useEffect(() => {
-        if (element) {
-            element.addEventListener("contextmenu", handler);
-            element.addEventListener("click", clickHandler);
-        }
-        return () => {
-            if (element) {
-                element.removeEventListener("contextmenu", handler);
-                element.removeEventListener("click", clickHandler);
-            }
-        }
-    });
-
-    return (
-        <div
-            className="context-menu"
-            style={{
-                display: show,
-                top: points.y,
-                left: points.x
-            }}
-        >
-            <button onClick={() => onReplyTo([true, message])}>Ответить</button>
-            <button onClick={() => onForwardTo([true, ""])}>Переслать</button>
-            {owner && <button onClick={() => onEdit(true)}>Редактировать</button>}
-        </div>
-    )
-}
-
 export const ShortMessage = ({ nick, text, date }) => {
     return (
         <>
@@ -62,7 +22,38 @@ export const ShortMessage = ({ nick, text, date }) => {
 export const Message = ({ id, nick, msg, date, media, own = false, replyTo, onMSGEdit, onMSGReply, onMSGForward }) => {
     let [isEdit, setIsEdit] = useState(false)
     let [messageEdit, setMessageEdit] = useState("" || msg)
-    let el = useRef(null)
+
+    const [contextMenu, setContextMenu] = useState(null);
+
+    const handleContextMenu = (event) => {
+        event.preventDefault();
+        setContextMenu(
+            contextMenu === null
+                ? {
+                    mouseX: event.clientX - 2,
+                    mouseY: event.clientY - 4,
+                }
+                : // repeated contextmenu when it is already open closes it with Chrome 84 on Ubuntu
+                // Other native context menus might behave different.
+                // With this behavior we prevent contextmenu from the backdrop to re-locale existing context menus.
+                null,
+        );
+    };
+
+    const handleClose = (e, type, msg_id) => {
+        if (type === "edit") {
+            setIsEdit(true)
+        }
+        if (type === "reply") {
+            onMSGReply([true, msg_id])
+        }
+        if (type === "forward") {
+            alert("Сорян пока не работает)")
+            // onMSGForward([true, ""])
+        }
+
+        setContextMenu(null);
+    };
 
     let msgEditHandler = () => {
         setIsEdit(false)
@@ -70,8 +61,23 @@ export const Message = ({ id, nick, msg, date, media, own = false, replyTo, onMS
     }
 
     return (
-        <li ref={el} className={own ? "msg-user" : "msg-someone"} >
-            <ContextMenu message={id} element={el.current} owner={own} onEdit={setIsEdit} onForwardTo={onMSGForward} onReplyTo={onMSGReply} />
+
+        <li className={own ? "msg-user" : "msg-someone"} onContextMenu={handleContextMenu} >
+            <Menu
+                open={contextMenu !== null}
+                onClose={handleClose}
+                anchorReference="anchorPosition"
+                anchorPosition={
+                    contextMenu !== null
+                        ? { top: contextMenu.mouseY, left: contextMenu.mouseX }
+                        : undefined
+                }
+            >
+                <MenuItem onClick={e => handleClose(e, "reply", id)}>Ответить</MenuItem>
+                <MenuItem onClick={e => handleClose(e, "forward", id)}>Переслать</MenuItem>
+                <MenuItem onClick={e => handleClose(e, "edit", id)}>Редактировать</MenuItem>
+            </Menu>
+            {/* <ContextMenu message={id} element={el.current} owner={own} onEdit={setIsEdit} onForwardTo={onMSGForward} onReplyTo={onMSGReply} /> */}
 
             {replyTo && <div className="msg-reply">В ответ на сообщение: {replyTo.text}</div>}
 
@@ -110,10 +116,6 @@ export const Message = ({ id, nick, msg, date, media, own = false, replyTo, onMS
                                     </video>
                                 }
 
-                                {
-                                    file.type === null && <a href={"/" + file.url}>Скачать</a>
-                                }
-
                             </li>)
                         })}
                     </ul>}

+ 96 - 10
src/components/profileBar.js

@@ -1,19 +1,105 @@
+// import { Avatar, Button, AppBar } from "@mui/material"
 import { connect } from "react-redux"
 import { actionAuthLogout } from "../actions"
+import { useState } from "react";
+import Box from '@mui/material/Box';
+import Avatar from '@mui/material/Avatar';
+import Menu from '@mui/material/Menu';
+import MenuItem from '@mui/material/MenuItem';
+import ListItemIcon from '@mui/material/ListItemIcon';
+import Divider from '@mui/material/Divider';
+import IconButton from '@mui/material/IconButton';
+import Typography from '@mui/material/Typography';
+import Tooltip from '@mui/material/Tooltip';
+import PersonAdd from '@mui/icons-material/PersonAdd';
+import Settings from '@mui/icons-material/Settings';
+import Logout from '@mui/icons-material/Logout';
+import { ListItem } from "@mui/material";
+import { Link } from "react-router-dom";
+
+export default function AccountMenu() {
+
+}
 
 const Profile = ({ user, onLogout }) => {
+    const [anchorEl, setAnchorEl] = useState(null);
+    const open = Boolean(anchorEl);
+
+    const handleClick = (event) => {
+        setAnchorEl(event.currentTarget);
+    }
+
+    const handleClose = () => {
+        setAnchorEl(null);
+    }
     return (
+        // <>
+        //     {user && <div>
+        //         {user.avatar ?
+        //             <Avatar src={user.avatar.url} alt={user.login} />
+        //             :
+        //             <Avatar>{(user.nick && user.nick[0]) || user.login[0]}</Avatar>}
+        //         <span>{user.nick || user.login}</span>
+        //         <a href="/profile">Редактировать профиль</a>
+        //         <Button onClick={() => onLogout()}>Выйти</Button>
+        //     </div>}
+        // </>
+
         <>
-            {user && <div>
-                {user.avatar ?
-                    <img src={user.avatar.url} alt="ava" />
-                    :
-                    <img src="https://img.icons8.com/external-bearicons-glyph-bearicons/64/000000/external-User-essential-collection-bearicons-glyph-bearicons.png"
-                        alt="ava" />}
-                <span>{user.nick || user.login}</span>
-                <a href="/profile">Редактировать профиль</a>
-                <button onClick={() => onLogout()}>Выйти</button>
-            </div>}
+            <Box sx={{ display: 'flex', alignItems: 'center', textAlign: 'center' }}>
+                {user && <Tooltip title="Account settings">
+                    <IconButton onClick={handleClick} size="small" sx={{ ml: 2 }}>
+                        {user.avatar ?
+                            <Avatar src={user.avatar.url} alt={user.login} />
+                            :
+                            <Avatar>{(user.nick && user.nick[0]) || user.login[0]}</Avatar>}
+                    </IconButton>
+                </Tooltip>}
+            </Box>
+            <Menu
+                anchorEl={anchorEl}
+                open={open}
+                onClose={handleClose}
+                onClick={handleClose}
+                PaperProps={{
+                    elevation: 0,
+                    sx: {
+                        overflow: 'visible',
+                        filter: 'drop-shadow(0px 2px 8px rgba(0,0,0,0.32))',
+                        mt: 1.5,
+                        '& .MuiAvatar-root': {
+                            width: 32,
+                            height: 32,
+                            ml: -0.5,
+                            mr: 1,
+                        },
+                        '&:before': {
+                            content: '""',
+                            display: 'block',
+                            position: 'absolute',
+                            top: 0,
+                            right: 14,
+                            width: 10,
+                            height: 10,
+                            bgcolor: 'background.paper',
+                            transform: 'translateY(-50%) rotate(45deg)',
+                            zIndex: 0,
+                        },
+                    },
+                }}
+                transformOrigin={{ horizontal: 'right', vertical: 'top' }}
+                anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
+            >
+                <MenuItem component={Link} to={`/profile`}>
+                    Profile                </MenuItem>
+                <Divider />
+                <MenuItem onClick={onLogout}>
+                    <ListItemIcon>
+                        <Logout fontSize="small" />
+                    </ListItemIcon>
+                    Logout
+                </MenuItem>
+            </Menu>
         </>
     )
 }

+ 36 - 14
src/pages/main.js

@@ -6,13 +6,15 @@ import ChatsList from "../components/chatsList";
 import ConnectChatForm from "../components/chatForm";
 import ConnectChatEditForm from "../components/chatEditForm";
 import { ConnectProfile } from "../components/profileBar";
+import { ChatBar } from "../components/chatBar";
 import {
     actionAddChat, actionAddChatBack, actionAddMSG, actionAddMSGBack,
     actionEditMSGback, actionFullGetChats, actionFullGetMessages,
     actionGetUserInfo, actionUploadFile
 } from "../actions";
+import { Grid, Container, AppBar } from "@mui/material";
 
-const Main = ({ match: { params: { _id } }, userID, chats, getUserInfo, getChat, getMessages, addChat, addMSG, editMSG, sendMSG, addFile }) => {
+const Main = ({ match: { params: { _id } }, userID, chats, isLoad, getUserInfo, getChat, getMessages, addChat, addMSG, editMSG, sendMSG, addFile }) => {
     let [isEdit, setIsEdit] = useState(false)
     let onInfoHandler = () => {
         setIsEdit(!isEdit)
@@ -57,33 +59,53 @@ const Main = ({ match: { params: { _id } }, userID, chats, getUserInfo, getChat,
     }, [_id, chat_id, getMessages])
 
     return (
-        <>
-            <ConnectProfile />
-            <main>
+        <Grid container spacing={0} sx={{
+            width: '100%',
+            bgcolor: 'background.paper',
+            position: 'relative',
+            maxHeight: '95vh',
+        }}>
+            <Grid container lg="12" sx={{
+                display: 'flex',
+                alignItems: 'center',
+                bgcolor: 'primary.main',
+            }}>
+                <Grid item lg="3">
+                    <ConnectProfile />
+                </Grid>
+                {chat_id && <Grid item lg="9" >
+                    <ChatBar
+                        chat_title={chats[chat_id]?.title || ""}
+                        onInfo={onInfoHandler} />
+                </Grid>}
+            </Grid>
+
+            <Grid item lg="3">
                 <ChatsList />
-                {_id === "chat" && <ConnectChatForm />}
-
-                {chats[chat_id] &&
+            </Grid>
+            <Grid item lg={isEdit ? "6" : "9"} sx={{ bgcolor: '#c7deed', }}>
+                {chats[chat_id] ?
                     <Chat chat_id={chat_id}
-                        chat_title={chats[chat_id].title}
-                        chat_avatar={chats[chat_id].avatar?.url}
                         user_id={userID}
                         messages={chats[chat_id].messages || []}
+                        isLoad={isLoad}
                         onUpload={addFile}
                         onSend={sendMSG}
                         onMSGEdit={editMSG}
                         onScrollTopComplete={getMessages}
-                        onInfo={onInfoHandler} />}
-
-                {isEdit && chats[chat_id] && <ConnectChatEditForm chat_id={chat_id} chat={chats[chat_id]} />}
-            </main>
-        </>
+                    /> : <ConnectChatForm />}
+            </Grid>
+            {isEdit && chats[chat_id] && <Grid item lg="3">
+                <ConnectChatEditForm chat_id={chat_id} chat={chats[chat_id]} />
+            </Grid>}
+        </Grid>
     )
 }
 
 export const ConnectMain = connect(state => ({
     userID: state.auth.payload.sub.id,
     chats: state.chat,
+    isLoad: state.promise?.messages?.status
 }),
     {
         getUserInfo: actionGetUserInfo,