diff --git a/README.md b/README.md index 9d9614c4fd32e65dcbefff34b758d7824b397181..763ec537cf8f086611fc5d3a5a238ee45684a314 100755 --- a/README.md +++ b/README.md @@ -27,6 +27,20 @@ Your app is ready to be deployed! See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. +#### Building for Relative Paths + +By default, the build is produced assuming your app is hosted at the server root.<br> +To override this, specify the homepage in your package.json, for example: + +```js +"homepage": "https://api.portalmec.c3sl.ufpr.br/relativepath" +``` +You will also need to set the relative path in the basename property from BrowserReact in src/App.js: + +```js +<BrowserRouter basename="/relativepath"> +``` + ### `npm run eject` **Note: this is a one-way operation. Once you `eject`, you can’t go back!** diff --git a/package-lock.json b/package-lock.json index 8966c047e184beb875625ece3e4010da442722d9..2311a4adb00c8bb9ea6d93f28f62e25340c3367d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1031,16 +1031,6 @@ "regenerator-runtime": "^0.13.4" } }, - "@babel/runtime-corejs3": { - "version": "7.10.2", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.10.2.tgz", - "integrity": "sha512-+a2M/u7r15o3dV1NEizr9bRi+KUVnrs/qYxF0Z06DAPx/4VCWaz1WA7EcbE+uqGgt39lp5akWGmHsTseIkHkHg==", - "dev": true, - "requires": { - "core-js-pure": "^3.0.0", - "regenerator-runtime": "^0.13.4" - } - }, "@babel/template": { "version": "7.10.1", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.1.tgz", @@ -1207,53 +1197,53 @@ "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" }, "@material-ui/core": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.10.2.tgz", - "integrity": "sha512-Uf4iDLi9sW6HKbVQDyDZDr1nMR4RUAE7w/RIIJZGNVZResC0xwmpLRZMtaUdSO43N0R0yJehfxTi4Z461Cd49A==", + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.2.tgz", + "integrity": "sha512-/D1+AQQeYX/WhT/FUk78UCRj8ch/RCglsQLYujYTIqPSJlwZHKcvHidNeVhODXeApojeXjkl0tWdk5C9ofwOkQ==", "requires": { "@babel/runtime": "^7.4.4", - "@material-ui/styles": "^4.10.0", - "@material-ui/system": "^4.9.14", + "@material-ui/styles": "^4.11.2", + "@material-ui/system": "^4.11.2", "@material-ui/types": "^5.1.0", - "@material-ui/utils": "^4.10.2", + "@material-ui/utils": "^4.11.2", "@types/react-transition-group": "^4.2.0", "clsx": "^1.0.4", "hoist-non-react-statics": "^3.3.2", "popper.js": "1.16.1-lts", "prop-types": "^15.7.2", - "react-is": "^16.8.0", + "react-is": "^16.8.0 || ^17.0.0", "react-transition-group": "^4.4.0" } }, "@material-ui/icons": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.9.1.tgz", - "integrity": "sha512-GBitL3oBWO0hzBhvA9KxqcowRUsA0qzwKkURyC8nppnC3fw54KPKZ+d4V1Eeg/UnDRSzDaI9nGCdel/eh9AQMg==", + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz", + "integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==", "requires": { "@babel/runtime": "^7.4.4" } }, "@material-ui/lab": { - "version": "4.0.0-alpha.56", - "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.56.tgz", - "integrity": "sha512-xPlkK+z/6y/24ka4gVJgwPfoCF4RCh8dXb1BNE7MtF9bXEBLN/lBxNTK8VAa0qm3V2oinA6xtUIdcRh0aeRtVw==", + "version": "4.0.0-alpha.57", + "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.57.tgz", + "integrity": "sha512-qo/IuIQOmEKtzmRD2E4Aa6DB4A87kmY6h0uYhjUmrrgmEAgbbw9etXpWPVXuRK6AGIQCjFzV6WO2i21m1R4FCw==", "requires": { "@babel/runtime": "^7.4.4", - "@material-ui/utils": "^4.10.2", + "@material-ui/utils": "^4.11.2", "clsx": "^1.0.4", "prop-types": "^15.7.2", - "react-is": "^16.8.0" + "react-is": "^16.8.0 || ^17.0.0" } }, "@material-ui/styles": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.10.0.tgz", - "integrity": "sha512-XPwiVTpd3rlnbfrgtEJ1eJJdFCXZkHxy8TrdieaTvwxNYj42VnnCyFzxYeNW9Lhj4V1oD8YtQ6S5Gie7bZDf7Q==", + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.2.tgz", + "integrity": "sha512-xbItf8zkfD3FuGoD9f2vlcyPf9jTEtj9YTJoNNV+NMWaSAHXgrW6geqRoo/IwBuMjqpwqsZhct13e2nUyU9Ljw==", "requires": { "@babel/runtime": "^7.4.4", "@emotion/hash": "^0.8.0", "@material-ui/types": "^5.1.0", - "@material-ui/utils": "^4.9.6", + "@material-ui/utils": "^4.11.2", "clsx": "^1.0.4", "csstype": "^2.5.2", "hoist-non-react-statics": "^3.3.2", @@ -1269,12 +1259,12 @@ } }, "@material-ui/system": { - "version": "4.9.14", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.9.14.tgz", - "integrity": "sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w==", + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.11.2.tgz", + "integrity": "sha512-BELFJEel5E+5DMiZb6XXT3peWRn6UixRvBtKwSxqntmD0+zwbbfCij6jtGwwdJhN1qX/aXrKu10zX31GBaeR7A==", "requires": { "@babel/runtime": "^7.4.4", - "@material-ui/utils": "^4.9.6", + "@material-ui/utils": "^4.11.2", "csstype": "^2.5.2", "prop-types": "^15.7.2" } @@ -1285,13 +1275,13 @@ "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" }, "@material-ui/utils": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.10.2.tgz", - "integrity": "sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw==", + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", + "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", "requires": { "@babel/runtime": "^7.4.4", "prop-types": "^15.7.2", - "react-is": "^16.8.0" + "react-is": "^16.8.0 || ^17.0.0" } }, "@mrmlnc/readdir-enhanced": { @@ -1546,71 +1536,71 @@ } }, "@syncfusion/ej2-base": { - "version": "18.2.44", - "resolved": "https://registry.npmjs.org/@syncfusion/ej2-base/-/ej2-base-18.2.44.tgz", - "integrity": "sha512-q1aHQr9DXpCQh1iqWsYcIg2eGzsQZXBCu6XvFzMIXp6aWFu6fmW/2WYceg+F5B3cVfo1xCivthdrhlHzxiicGg==", + "version": "18.3.52", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-base/-/ej2-base-18.3.52.tgz", + "integrity": "sha512-g32+xrxnktzz7PhAPlmVhM/Lu4Ad+VuEYDOIw6+/tTHc4FkfNglZxyNmom+9J4bfDkz9AyVv0JmbPyeBxDvETg==", "requires": { - "@syncfusion/ej2-icons": "~18.2.44" + "@syncfusion/ej2-icons": "~18.3.47" } }, "@syncfusion/ej2-buttons": { - "version": "18.2.44", - "resolved": "https://registry.npmjs.org/@syncfusion/ej2-buttons/-/ej2-buttons-18.2.44.tgz", - "integrity": "sha512-mKhZ8DJEiRHyGdfQgti72Ul0UmTxVgPYzBnpB80/iif67tWsxLnqVJ53CWgxkXJq0fm6fAneIFSXztMffN2fmw==", + "version": "18.3.47", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-buttons/-/ej2-buttons-18.3.47.tgz", + "integrity": "sha512-V/uzgfaE4f0bfbxKbztIs4Px6cVEVYKKoSMMTWxGFOAD1Ol2Hp055MJzDjQTzmoaq7TlLjyHXGZDsYoKGuguGw==", "requires": { - "@syncfusion/ej2-base": "~18.2.44" + "@syncfusion/ej2-base": "~18.3.47" } }, "@syncfusion/ej2-icons": { - "version": "18.2.44", - "resolved": "https://registry.npmjs.org/@syncfusion/ej2-icons/-/ej2-icons-18.2.44.tgz", - "integrity": "sha512-4jOb0RtpTU+s+IXbaQxxcWhFpXXn9aYyakGmrF7A6smbpndM7do28mDybJMFIns/IoRsQokOnrDhqqAIaoDRVQ==" + "version": "18.3.47", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-icons/-/ej2-icons-18.3.47.tgz", + "integrity": "sha512-SSasO60RF0wZuPvz7KUMhvqeZgHCBOrCy2IjPywg3YDOgH244E90NasE0jfGm/1HDdkkVhxWATh8bZh79Ivg/g==" }, "@syncfusion/ej2-inputs": { - "version": "18.2.45", - "resolved": "https://registry.npmjs.org/@syncfusion/ej2-inputs/-/ej2-inputs-18.2.45.tgz", - "integrity": "sha512-1lyunOQFT77PXB2gZuJjmgRfyQqFcsTBmj9fGA5PIm5dwipsq4fy6IKOhTMcGCO64q7NZieNXcWOWdSws0lqAQ==", + "version": "18.3.52", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-inputs/-/ej2-inputs-18.3.52.tgz", + "integrity": "sha512-+uN/eGlCsoPISsx/j/HA3MO1TQALDiRVVPe/Cr9kmtxirgIFfkFeY5kOZ3vbYho+5fomSU/4JQX1FMXNV3xQ9A==", "requires": { - "@syncfusion/ej2-base": "~18.2.44", - "@syncfusion/ej2-buttons": "~18.2.44", - "@syncfusion/ej2-popups": "~18.2.44", - "@syncfusion/ej2-splitbuttons": "~18.2.44" + "@syncfusion/ej2-base": "~18.3.52", + "@syncfusion/ej2-buttons": "~18.3.47", + "@syncfusion/ej2-popups": "~18.3.52", + "@syncfusion/ej2-splitbuttons": "~18.3.52" } }, "@syncfusion/ej2-popups": { - "version": "18.2.44", - "resolved": "https://registry.npmjs.org/@syncfusion/ej2-popups/-/ej2-popups-18.2.44.tgz", - "integrity": "sha512-+1riSvOH+nhoQtRbgX3Yl2W50Ql5YceiaucyQXNV/WKC9JqHuamRj3PINzd11HjAubvkAMOoYLQQ7B7wP4UmaA==", + "version": "18.3.52", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-popups/-/ej2-popups-18.3.52.tgz", + "integrity": "sha512-5+dAQaUkMYH59Ka82Rg7d4RvjP5dQm5GtZWGbAkN9TpIh4wfDhLTeBOhN87f7n8RsuDA9bBtCRk1YEdBfTpEGw==", "requires": { - "@syncfusion/ej2-base": "~18.2.44", - "@syncfusion/ej2-buttons": "~18.2.44" + "@syncfusion/ej2-base": "~18.3.52", + "@syncfusion/ej2-buttons": "~18.3.47" } }, "@syncfusion/ej2-react-base": { - "version": "18.2.44", - "resolved": "https://registry.npmjs.org/@syncfusion/ej2-react-base/-/ej2-react-base-18.2.44.tgz", - "integrity": "sha512-lvIdLzDd2f3V9CEpHBV0FLnJVbb0Nucu7qbdOKQ4dQDRCO0QfM3dqyuC6Wd20R0cyaNGyjucXIpqcueLPtqSvA==", + "version": "18.3.52", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-react-base/-/ej2-react-base-18.3.52.tgz", + "integrity": "sha512-dpNnTPjUUxfkdb0BxeUcBs9DPJ/ngf9ipbd5eLwJPE7XFlrOJ1owEoqDqXIeW9pI+eVu9L3hF25TI287T5b9Sw==", "requires": { - "@syncfusion/ej2-base": "~18.2.44" + "@syncfusion/ej2-base": "~18.3.52" } }, "@syncfusion/ej2-react-inputs": { - "version": "18.2.45", - "resolved": "https://registry.npmjs.org/@syncfusion/ej2-react-inputs/-/ej2-react-inputs-18.2.45.tgz", - "integrity": "sha512-lH5e/YNASvqBcXt4ix8YVDv/lWBwM9F7tKiwPXckKnfNX01s2iZg+u+Dw+W3Cj7KIulpg60CHQkFoPtCm2uVkQ==", + "version": "18.3.52", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-react-inputs/-/ej2-react-inputs-18.3.52.tgz", + "integrity": "sha512-qhMFm4uMUKTashS/mX+jbxwWP3dm49V2t6b7XyZ03wAxDk2wUxchqx2AwhSNBBzTWGYXh1ZvWIujjegXIS9kqQ==", "requires": { - "@syncfusion/ej2-base": "~18.2.44", - "@syncfusion/ej2-inputs": "18.2.45", - "@syncfusion/ej2-react-base": "~18.2.44" + "@syncfusion/ej2-base": "~18.3.52", + "@syncfusion/ej2-inputs": "18.3.52", + "@syncfusion/ej2-react-base": "~18.3.52" } }, "@syncfusion/ej2-splitbuttons": { - "version": "18.2.44", - "resolved": "https://registry.npmjs.org/@syncfusion/ej2-splitbuttons/-/ej2-splitbuttons-18.2.44.tgz", - "integrity": "sha512-zR/q7OTow5CtV3ZJ2mTHdOhkYr6TeWTg3I4I47lee+6H9EFrryURmi3iyhVHaLQEG/RHW7o53kr9d7qqQwyFyQ==", + "version": "18.3.52", + "resolved": "https://registry.npmjs.org/@syncfusion/ej2-splitbuttons/-/ej2-splitbuttons-18.3.52.tgz", + "integrity": "sha512-KgZ4MGpohJzhX5HoRE+unMkeiU0d9tJbNgEhmhLKK4IsXeVx579gc9ftlTtmofjtOU9UyyHvjmYI6y+gobprww==", "requires": { - "@syncfusion/ej2-base": "~18.2.44", - "@syncfusion/ej2-popups": "~18.2.44" + "@syncfusion/ej2-base": "~18.3.52", + "@syncfusion/ej2-popups": "~18.3.52" } }, "@types/parse-json": { @@ -1629,12 +1619,19 @@ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" }, "@types/react": { - "version": "16.9.36", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.36.tgz", - "integrity": "sha512-mGgUb/Rk/vGx4NCvquRuSH0GHBQKb1OqpGS9cT9lFxlTLHZgkksgI60TuIxubmn7JuCb+sENHhQciqa0npm0AQ==", + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz", + "integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==", "requires": { "@types/prop-types": "*", - "csstype": "^2.2.0" + "csstype": "^3.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz", + "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==" + } } }, "@types/react-transition-group": { @@ -2298,6 +2295,73 @@ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" }, + "array.prototype.flatmap": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", + "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1", + "function-bind": "^1.1.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + } + } + }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", @@ -3176,9 +3240,9 @@ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" }, "binary-extensions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", - "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" }, "bluebird": { "version": "3.7.2", @@ -3478,6 +3542,16 @@ "unset-value": "^1.0.0" } }, + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + } + }, "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", @@ -4106,9 +4180,9 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "core-js": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", - "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==" + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.0.tgz", + "integrity": "sha512-W2VYNB0nwQQE7tKS7HzXd7r2y/y2SVJl4ga6oH/dnaLFzM0o2lB2P3zCkWj5Wc/zyMYjtgd5Hmhk0ObkQFZOIA==" }, "core-js-compat": { "version": "3.6.5", @@ -4126,12 +4200,6 @@ } } }, - "core-js-pure": { - "version": "3.6.5", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz", - "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -5074,12 +5142,19 @@ } }, "dom-helpers": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.4.tgz", - "integrity": "sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", + "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", "requires": { "@babel/runtime": "^7.8.7", - "csstype": "^2.6.7" + "csstype": "^3.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz", + "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==" + } } }, "dom-serializer": { @@ -5216,9 +5291,9 @@ "integrity": "sha512-smevlzzMNz3vMz6OLeeCq5HRWEj2AcgccNPYnAx4Usx0IOciq9DU36RJcICcS09hXoY7t7deRfVYKD14IrGb9A==" }, "elliptic": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", - "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -5259,14 +5334,6 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "requires": { - "iconv-lite": "~0.4.13" - } - }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -5505,9 +5572,9 @@ } }, "eslint-config-prettier": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz", - "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz", + "integrity": "sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==", "dev": true, "requires": { "get-stdin": "^6.0.0" @@ -5706,31 +5773,32 @@ } }, "eslint-plugin-react": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.20.0.tgz", - "integrity": "sha512-rqe1abd0vxMjmbPngo4NaYxTcR3Y4Hrmc/jg4T+sYz63yqlmJRknpEQfmWY+eDWPuMmix6iUIK+mv0zExjeLgA==", + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz", + "integrity": "sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g==", "dev": true, "requires": { "array-includes": "^3.1.1", + "array.prototype.flatmap": "^1.2.3", "doctrine": "^2.1.0", "has": "^1.0.3", - "jsx-ast-utils": "^2.2.3", - "object.entries": "^1.1.1", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "object.entries": "^1.1.2", "object.fromentries": "^2.0.2", "object.values": "^1.1.1", "prop-types": "^15.7.2", - "resolve": "^1.15.1", - "string.prototype.matchall": "^4.0.2", - "xregexp": "^4.3.0" + "resolve": "^1.18.1", + "string.prototype.matchall": "^4.0.2" }, "dependencies": { - "xregexp": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.3.0.tgz", - "integrity": "sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==", + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", "dev": true, "requires": { - "@babel/runtime-corejs3": "^7.8.3" + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" } } } @@ -7488,6 +7556,17 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" }, + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "get-own-enumerable-property-symbols": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", @@ -8333,9 +8412,9 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, "hyphenate-style-name": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz", - "integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ==" + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" }, "iconv-lite": { "version": "0.4.24", @@ -8382,11 +8461,11 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==" }, "image-to-base64": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/image-to-base64/-/image-to-base64-2.1.0.tgz", - "integrity": "sha512-Qlm5F5EJUkxMEY0uPVwbfEkirv4WowHGRj9LBPYU3bAuFucwhvIJiH9g3aJZ91A89jVq9GzmayiNvE2sEjQ9YQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/image-to-base64/-/image-to-base64-2.1.1.tgz", + "integrity": "sha512-G8EZaxl8dmYUXCmaC/1W4oqwj+yiY+qhF9A81TbdOtxdK9BAN3oV440Jofexp4J2oRsbHIUJtl3rlDqdjmiZOQ==", "requires": { - "node-fetch": "^1.7.3" + "node-fetch": "^2.6.0" } }, "immer": { @@ -8450,11 +8529,24 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, + "indefinite-observable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-2.0.1.tgz", + "integrity": "sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ==", + "requires": { + "symbol-observable": "1.2.0" + } + }, "indexes-of": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -8626,6 +8718,15 @@ "rgba-regex": "^1.0.0" } }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", @@ -8712,6 +8813,12 @@ "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "dev": true + }, "is-number": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", @@ -9634,81 +9741,89 @@ } }, "jss": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jss/-/jss-10.3.0.tgz", - "integrity": "sha512-B5sTRW9B6uHaUVzSo9YiMEOEp3UX8lWevU0Fsv+xtRnsShmgCfIYX44bTH8bPJe6LQKqEXku3ulKuHLbxBS97Q==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.5.0.tgz", + "integrity": "sha512-B6151NvG+thUg3murLNHRPLxTLwQ13ep4SH5brj4d8qKtogOx/jupnpfkPGSHPqvcwKJaCLctpj2lEk+5yGwMw==", "requires": { "@babel/runtime": "^7.3.1", - "csstype": "^2.6.5", + "csstype": "^3.0.2", + "indefinite-observable": "^2.0.1", "is-in-browser": "^1.1.3", "tiny-warning": "^1.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz", + "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==" + } } }, "jss-plugin-camel-case": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.3.0.tgz", - "integrity": "sha512-tadWRi/SLWqLK3EUZEdDNJL71F3ST93Zrl9JYMjV0QDqKPAl0Liue81q7m/nFUpnSTXczbKDy4wq8rI8o7WFqA==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.5.0.tgz", + "integrity": "sha512-GSjPL0adGAkuoqeYiXTgO7PlIrmjv5v8lA6TTBdfxbNYpxADOdGKJgIEkffhlyuIZHlPuuiFYTwUreLUmSn7rg==", "requires": { "@babel/runtime": "^7.3.1", "hyphenate-style-name": "^1.0.3", - "jss": "^10.3.0" + "jss": "10.5.0" } }, "jss-plugin-default-unit": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.3.0.tgz", - "integrity": "sha512-tT5KkIXAsZOSS9WDSe8m8lEHIjoEOj4Pr0WrG0WZZsMXZ1mVLFCSsD2jdWarQWDaRNyMj/I4d7czRRObhOxSuw==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.5.0.tgz", + "integrity": "sha512-rsbTtZGCMrbcb9beiDd+TwL991NGmsAgVYH0hATrYJtue9e+LH/Gn4yFD1ENwE+3JzF3A+rPnM2JuD9L/SIIWw==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "^10.3.0" + "jss": "10.5.0" } }, "jss-plugin-global": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.3.0.tgz", - "integrity": "sha512-etYTG/y3qIR/vxZnKY+J3wXwObyBDNhBiB3l/EW9/pE3WHE//BZdK8LFvQcrCO48sZW1Z6paHo6klxUPP7WbzA==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.5.0.tgz", + "integrity": "sha512-FZd9+JE/3D7HMefEG54fEC0XiQ9rhGtDHAT/ols24y8sKQ1D5KIw6OyXEmIdKFmACgxZV2ARQ5pAUypxkk2IFQ==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "^10.3.0" + "jss": "10.5.0" } }, "jss-plugin-nested": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.3.0.tgz", - "integrity": "sha512-qWiEkoXNEkkZ+FZrWmUGpf+zBsnEOmKXhkjNX85/ZfWhH9dfGxUCKuJFuOWFM+rjQfxV4csfesq4hY0jk8Qt0w==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.5.0.tgz", + "integrity": "sha512-ejPlCLNlEGgx8jmMiDk/zarsCZk+DV0YqXfddpgzbO9Toamo0HweCFuwJ3ZO40UFOfqKwfpKMVH/3HUXgxkTMg==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "^10.3.0", + "jss": "10.5.0", "tiny-warning": "^1.0.2" } }, "jss-plugin-props-sort": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.3.0.tgz", - "integrity": "sha512-boetORqL/lfd7BWeFD3K+IyPqyIC+l3CRrdZr+NPq7Noqp+xyg/0MR7QisgzpxCEulk+j2CRcEUoZsvgPC4nTg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.5.0.tgz", + "integrity": "sha512-kTLRvrOetFKz5vM88FAhLNeJIxfjhCepnvq65G7xsAQ/Wgy7HwO1BS/2wE5mx8iLaAWC6Rj5h16mhMk9sKdZxg==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "^10.3.0" + "jss": "10.5.0" } }, "jss-plugin-rule-value-function": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.3.0.tgz", - "integrity": "sha512-7WiMrKIHH3rwxTuJki9+7nY11r1UXqaUZRhHvqTD4/ZE+SVhvtD5Tx21ivNxotwUSleucA/8boX+NF21oXzr5Q==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.5.0.tgz", + "integrity": "sha512-jXINGr8BSsB13JVuK274oEtk0LoooYSJqTBCGeBu2cG/VJ3+4FPs1gwLgsq24xTgKshtZ+WEQMVL34OprLidRA==", "requires": { "@babel/runtime": "^7.3.1", - "jss": "^10.3.0", + "jss": "10.5.0", "tiny-warning": "^1.0.2" } }, "jss-plugin-vendor-prefixer": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.3.0.tgz", - "integrity": "sha512-sZQbrcZyP5V0ADjCLwUA1spVWoaZvM7XZ+2fSeieZFBj31cRsnV7X70FFDerMHeiHAXKWzYek+67nMDjhrZAVQ==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.5.0.tgz", + "integrity": "sha512-rux3gmfwDdOKCLDx0IQjTwTm03IfBa+Rm/hs747cOw5Q7O3RaTUIMPKjtVfc31Xr/XI9Abz2XEupk1/oMQ7zRA==", "requires": { "@babel/runtime": "^7.3.1", "css-vendor": "^2.0.8", - "jss": "^10.3.0" + "jss": "10.5.0" } }, "jsx-ast-utils": { @@ -9914,9 +10029,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -10382,9 +10497,9 @@ } }, "moment": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.26.0.tgz", - "integrity": "sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw==" + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" }, "moo-server": { "version": "1.3.0", @@ -10498,18 +10613,9 @@ } }, "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - }, - "node-forge": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", - "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-int64": { "version": "0.4.0", @@ -10733,14 +10839,70 @@ } }, "object.entries": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.2.tgz", - "integrity": "sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.3.tgz", + "integrity": "sha512-ym7h7OZebNS96hn5IJeyUmaWhaSM4SVtAPPfNLQEI2MYWCO2egsITb9nab2+i/Pwibx+R0mtn+ltKJXRSeTMGg==", "dev": true, "requires": { + "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.17.5", + "es-abstract": "^1.18.0-next.1", "has": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + } } }, "object.fromentries": { @@ -13830,9 +13992,9 @@ } }, "react": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", - "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -14005,9 +14167,9 @@ } }, "react-dom": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", - "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==", + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -14016,13 +14178,22 @@ } }, "react-dropdown": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/react-dropdown/-/react-dropdown-1.7.0.tgz", - "integrity": "sha512-zFZ73pgLA32hArpE4j/7DtOEhOMg240XG5QvbAb0/VinGekkHDVIakMyAFUKC5jDz8jqXEltgriqFW9R5iCtPQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/react-dropdown/-/react-dropdown-1.9.0.tgz", + "integrity": "sha512-BDApCUhs0qHqnFW3b54SuqI200FOOsmiy0dejdmtdTn/MMY11jcou3CLX1oT2Qa1PdN7viTyAGT8YCpK5qb9xg==", "requires": { "classnames": "^2.2.3" } }, + "react-dropdown-select": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/react-dropdown-select/-/react-dropdown-select-4.7.1.tgz", + "integrity": "sha512-yoF39vFN+F2TaRK1EXnhiz+8jyv40E7+MRUD/X/UsMr2dnYFWoFMMrTIVXcjVnDCFlU+yAvZYRqb+8b60bUuyw==", + "requires": { + "@emotion/core": "^10.0.27", + "@emotion/styled": "^10.0.27" + } + }, "react-easy-crop": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/react-easy-crop/-/react-easy-crop-2.1.2.tgz", @@ -14034,9 +14205,9 @@ } }, "react-easy-swipe": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/react-easy-swipe/-/react-easy-swipe-0.0.18.tgz", - "integrity": "sha512-IddCZANbT0qVbGFEihfWOkZb/rFpeA3VV87SNOOqPzmSZ93G0nDSyHD28zuGhYJilwEP33MqYv/dwo+zaZha3Q==", + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/react-easy-swipe/-/react-easy-swipe-0.0.21.tgz", + "integrity": "sha512-OeR2jAxdoqUMHIn/nS9fgreI5hSpgGoL5ezdal4+oO7YSSgJR8ga+PkYGJrSrJ9MKlPcQjMQXnketrD7WNmNsg==", "requires": { "prop-types": "^15.5.8" } @@ -14078,9 +14249,9 @@ } }, "react-google-login": { - "version": "5.1.20", - "resolved": "https://registry.npmjs.org/react-google-login/-/react-google-login-5.1.20.tgz", - "integrity": "sha512-/5vDx8Hy7Wo1fO1VC/0e5D6/ZGWgIgvcscI8mYZUQ653QOFf0c4GhTnKkebX5uE7m5rAB/2bzzZIUlIesGqWig==", + "version": "5.1.25", + "resolved": "https://registry.npmjs.org/react-google-login/-/react-google-login-5.1.25.tgz", + "integrity": "sha512-N7SZkjTEX9NsC3hywXs68SPJWAHo6M19Bs1OIFPirG0yomGF7KnbKjSqoiIfxz1V7fKAt8bkfBAzogwnGWYTeQ==", "requires": { "@types/react": "*", "prop-types": "^15.6.0" @@ -14095,20 +14266,20 @@ } }, "react-icons": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.10.0.tgz", - "integrity": "sha512-WsQ5n1JToG9VixWilSo1bHv842Cj5aZqTGiS3Ud47myF6aK7S/IUY2+dHcBdmkQcCFRuHsJ9OMUI0kTDfjyZXQ==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.11.0.tgz", + "integrity": "sha512-JRgiI/vdF6uyBgyZhVyYJUZAop95Sy4XDe/jmT3R/bKliFWpO/uZBwvSjWEdxwzec7SYbEPNPck0Kff2tUGM2Q==", "requires": { "camelcase": "^5.0.0" } }, "react-image-crop": { - "version": "8.6.4", - "resolved": "https://registry.npmjs.org/react-image-crop/-/react-image-crop-8.6.4.tgz", - "integrity": "sha512-5buyhUg9slzW+QGvN2dbpGSI1VqPxxmfEwe19TZXUB7LjW5+ljZOnrTSsteIzeBqmz6ngVucc8l+OrwgcDOSNg==", + "version": "8.6.6", + "resolved": "https://registry.npmjs.org/react-image-crop/-/react-image-crop-8.6.6.tgz", + "integrity": "sha512-2iQHKp12dYb6Fu2iN/Mg19BeLMgrbdOuKkU9k0RH7CHX6ZZylOlhfCM3/RsECbKnjGJRtGpXniGF+/i9CGis1A==", "requires": { - "clsx": "^1.0.4", - "core-js": "^3.4.2", + "clsx": "^1.1.1", + "core-js": "^3.6.5", "prop-types": "^15.7.2" } }, @@ -14137,13 +14308,13 @@ "integrity": "sha512-IyanbozsYCuHvTYDuskZTIEcRAMG/sdvAu5b29iQWoC8Kd3Zk9WGCv2oNxh6RfGHvSvgHAyaLjmC6ei/yMsJ7g==" }, "react-responsive-carousel": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/react-responsive-carousel/-/react-responsive-carousel-3.2.7.tgz", - "integrity": "sha512-uqGCnoZukU+U1relhTNe8eVX/hMT5ELh1uxHCOxR6cH+A67eG2aX68e1pJnohWqXqPj/u+Pupt1q5j8LGhDabA==", + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/react-responsive-carousel/-/react-responsive-carousel-3.2.10.tgz", + "integrity": "sha512-O8MV2LoR07BttvWaXesyWkE6s8xRW6p6HiMkelZ3TuPYQwKnlw+fYtZN+bQ3/1jg0D5JQGATY4Hnw/4WEXHnag==", "requires": { "classnames": "^2.2.5", "prop-types": "^15.5.8", - "react-easy-swipe": "^0.0.18" + "react-easy-swipe": "^0.0.21" } }, "react-router": { @@ -14252,6 +14423,26 @@ "requires": { "path-parse": "^1.0.6" } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "terser-webpack-plugin": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz", + "integrity": "sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg==", + "requires": { + "cacache": "^11.0.2", + "find-cache-dir": "^2.0.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.4.0", + "source-map": "^0.6.1", + "terser": "^3.16.1", + "webpack-sources": "^1.1.0", + "worker-farm": "^1.5.2" + } } } }, @@ -15343,11 +15534,18 @@ "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" }, "selfsigned": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", - "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", + "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", "requires": { - "node-forge": "0.9.0" + "node-forge": "^0.10.0" + }, + "dependencies": { + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" + } } }, "semver": { @@ -15564,13 +15762,68 @@ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==" }, "side-channel": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz", - "integrity": "sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.3.tgz", + "integrity": "sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g==", "dev": true, "requires": { - "es-abstract": "^1.17.0-next.1", - "object-inspect": "^1.7.0" + "es-abstract": "^1.18.0-next.0", + "object-inspect": "^1.8.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + } } }, "signal-exit": { @@ -16094,17 +16347,73 @@ } }, "string.prototype.matchall": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz", - "integrity": "sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz", + "integrity": "sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw==", "dev": true, "requires": { + "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.17.0", + "es-abstract": "^1.18.0-next.1", "has-symbols": "^1.0.1", "internal-slot": "^1.0.2", "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.2" + "side-channel": "^1.0.3" + }, + "dependencies": { + "es-abstract": { + "version": "1.18.0-next.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", + "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + } } }, "string.prototype.trimend": { @@ -16313,6 +16622,11 @@ } } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -16386,24 +16700,79 @@ } }, "terser-webpack-plugin": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.2.2.tgz", - "integrity": "sha512-1DMkTk286BzmfylAvLXwpJrI7dWa5BnFmscV/2dCr8+c56egFcbaeFAl7+sujAjdmpLam21XRdhA4oifLyiWWg==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", "requires": { - "cacache": "^11.0.2", - "find-cache-dir": "^2.0.0", + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", "schema-utils": "^1.0.0", - "serialize-javascript": "^1.4.0", + "serialize-javascript": "^4.0.0", "source-map": "^0.6.1", - "terser": "^3.16.1", - "webpack-sources": "^1.1.0", - "worker-farm": "^1.5.2" + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" }, "dependencies": { + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" } } }, @@ -16667,9 +17036,9 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "typescript": { - "version": "3.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.5.tgz", - "integrity": "sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==" + "version": "3.9.7", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", + "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==" }, "uglify-js": { "version": "1.3.5", diff --git a/package.json b/package.json index 717525b3312961c92fe54772ca13bb3d873f9a20..027b97c66ff58707036f1b3345fab429c41b2621 100644 --- a/package.json +++ b/package.json @@ -3,41 +3,42 @@ "version": "0.1.0", "private": true, "dependencies": { - "@material-ui/core": "^4.9.0", - "@material-ui/icons": "^4.5.1", - "@material-ui/lab": "^4.0.0-alpha.40", - "@material-ui/styles": "^4.9.0", - "@syncfusion/ej2-react-inputs": "^18.2.45", + "@material-ui/core": "^4.11.2", + "@material-ui/icons": "^4.11.2", + "@material-ui/lab": "^4.0.0-alpha.57", + "@material-ui/styles": "^4.11.2", + "@syncfusion/ej2-react-inputs": "^18.3.52", "axios": "^0.19.2", "base64-img": "^1.0.4", - "binary-extensions": "^2.0.0", + "binary-extensions": "^2.1.0", "build": "^0.1.4", "fine-uploader": "^5.16.2", - "image-to-base64": "^2.0.1", + "image-to-base64": "^2.1.1", "material-design-icons": "^3.0.1", - "moment": "^2.24.0", - "react": "^16.12.0", - "react-dom": "^16.12.0", - "react-dropdown": "^1.7.0", + "moment": "^2.29.1", + "react": "^16.14.0", + "react-dom": "^16.14.0", + "react-dropdown": "^1.9.0", + "react-dropdown-select": "^4.7.1", "react-easy-crop": "^2.1.0", "react-fine-uploader": "^1.1.1", - "react-google-login": "^5.0.7", + "react-google-login": "^5.1.25", "react-grid-system": "^4.4.11", - "react-icons": "^3.8.0", - "react-image-crop": "^8.6.2", + "react-icons": "^3.11.0", + "react-image-crop": "^8.6.6", "react-input-mask": "^2.0.4", "react-recaptcha": "^2.3.10", - "react-responsive-carousel": "^3.1.51", + "react-responsive-carousel": "^3.2.10", "react-router-dom": "^5.1.2", "react-scripts": "^2.1.8", "react-star-ratings": "^2.3.0", "styled-components": "^4.4.1", - "typescript": "^3.7.5" + "typescript": "^3.9.7" }, "devDependencies": { - "eslint-config-prettier": "^6.10.0", + "eslint-config-prettier": "^6.15.0", "eslint-plugin-prettier": "^3.1.2", - "eslint-plugin-react": "^7.18.0", + "eslint-plugin-react": "^7.21.5", "eslint-plugin-react-hooks": "^1.6.1", "prettier": "1.18.2" }, diff --git a/src/App.js b/src/App.js index 0ba68eb4fd680a349c32f2d38e0bcf5c2aaaa006..b6bda2253d5c84dcebce13ac439c6c407cf8f56b 100644 --- a/src/App.js +++ b/src/App.js @@ -19,6 +19,7 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React, { useContext, useEffect } from 'react'; import Home from './Pages/Home'; import Search from './Pages/Search' +import SearchOld from './Pages/SearchOld' import Header from './Components/Header' import EcFooter from './Components/EcFooter'; import GNUAGPLfooter from './Components/AGPLFooter'; @@ -45,6 +46,9 @@ import EditProfilePage from './Pages/EditProfilePage.js' import PublicUserPage from './Pages/PublicUserPage.js' import UploadPage from './Pages/UploadPage.js' import EditLearningObjectPage from './Pages/EditLearningObjectPage.js' +import SiteMap from './Pages/SiteMap' +import Accessibility from './Pages/Accessibility' +import CollectionPage from './Pages/CollectionPage.js' export default function App(){ // eslint-disable-next-line @@ -84,6 +88,7 @@ export default function App(){ <Switch> <Route path="/" exact={true} component={Home}/> <Route path="/busca" component={Search} /> + <Route path="/buscaAntiga" component={SearchOld} /> <Route path="/perfil" component={UserPage} /> <Route path="/editarperfil" component={EditProfilePage} /> <Route path="/recurso/:recursoId" component={ResourcePage}/> @@ -95,6 +100,8 @@ export default function App(){ <Route path="/termos" component={UserTerms}/> <Route path="/teste" component={Teste}/> <Route path="/sobre" component={AboutPage}/> + <Route path="/mapa-site" component={SiteMap}/> + <Route path="/acessibilidade" component={Accessibility}/> <Route path="/publicando-recurso" component={TabResoursePub}/> <Route path="/encontrando-recurso" component={TabResourseFind}/> <Route path="/participando-da-rede" component={TabNetPart}/> @@ -106,6 +113,7 @@ export default function App(){ <Route path='/professor' component={PageProfessor}/> <Route path="/upload" component={UploadPage}/> <Route path='/loja' component={ItemStore} /> + <Route path='/colecao-do-usuario/:id' component={CollectionPage} /> </Switch> <EcFooter/> <GNUAGPLfooter/> diff --git a/src/Components/ActivityListItem.js b/src/Components/ActivityListItem.js index 24a00b77a9afb3cc534a52925e70a622b06a4ff7..7af740cd4b41cc5cb29d28312a11fbdeb5d696a2 100644 --- a/src/Components/ActivityListItem.js +++ b/src/Components/ActivityListItem.js @@ -115,15 +115,15 @@ export default function ActivityListItem (props) { }, [] ) return ( - <StyledListItem> + <StyledListItem onMenuBar={props.onMenuBar}> { !props.onMenuBar && <> - + <ListItemAvatar> <Avatar alt='user avatar' src={props.avatar ? props.avatar : noAvatar}/> </ListItemAvatar> - getNotificationIcon(activity.icon) + {getNotificationIcon(activity.icon)} </> } @@ -150,7 +150,7 @@ export default function ActivityListItem (props) { } const StyledListItem = styled(ListItem)` - padding : 20px 60px !important ; + padding : ${props => props.onMenuBar ? "8px 16px !important" : "20px 60px !important"}; border-bottom : 1px solid #eee; display : flex; justify-content : flex-start; diff --git a/src/Components/AreasSubPages.js b/src/Components/AreasSubPages.js index f911ec1d0d1058885610be48f29f8b8387635106..b0ae3f7458acceb7d26e43f44948de9a9d5d965a 100644 --- a/src/Components/AreasSubPages.js +++ b/src/Components/AreasSubPages.js @@ -29,9 +29,9 @@ import { Carousel } from "react-responsive-carousel"; import recursos from "../img/ilustra_recursos_digitais.png"; import materiais from "../img/ilustra_materiais.png"; import colecoes from "../img/ilustra_colecoes.png"; -import Grid from '@material-ui/core/Grid'; -import ResourceCardFunction from './ResourceCardFunction.js' -import CollectionCardFunction from './CollectionCardFunction.js' +import Grid from "@material-ui/core/Grid"; +import ResourceCardFunction from "./ResourceCardFunction.js"; +import CollectionCardFunction from "./CollectionCardFunction.js"; const areaStyle = { paddingTop: "5px", @@ -41,20 +41,20 @@ const areaStyle = { width: "1000px", margin: "auto", padding: "20px", - minHeight: "190px" + minHeight: "190px", }; class ReqResources extends Component { constructor(props) { super(props); this.state = { - resources: [] + resources: [], }; } componentDidMount() { axios .get(`${apiUrl}/learning_objects?limit=12&sort=["published_at", "desc"]`) - .then(res => { + .then((res) => { this.setState({ resources: res.data }); console.log(res.data); }); @@ -65,64 +65,71 @@ class ReqResources extends Component { var row3 = this.state.resources.slice(8, 13); return ( <Carousel showThumbs={false} infiniteLoop={true} showStatus={false}> - <Row style={{paddingBottom: "5px"}}> - {row1.map(card => <Col md={3} sm={6} key={card.id}> - <ResourceCardFunction - avatar = {card.publisher.avatar} - id={card.id} - thumbnail = {card.thumbnail} - type = {card.object_type ? card.object_type : "Outros"} - title={card.name} - published={card.state === "published" ? true : false} - likeCount={card.likes_count} - liked={card.liked} - rating={card.review_average} - author={card.author} - tags={card.educational_stages} - href={'/recurso/' + card.id} - downloadableLink={card.default_attachment_location} - /></Col>)} - </Row> - <Row> - {row2.map(card => <Col md={3} sm={6} key={card.id}> - <ResourceCardFunction - avatar = {card.publisher.avatar} - id={card.id} - thumbnail = {card.thumbnail} - type = {card.object_type ? card.object_type : "Outros"} - title={card.name} - published={card.state === "published" ? true : false} - likeCount={card.likes_count} - liked={card.liked} - rating={card.review_average} - author={card.author} - tags={card.educational_stages} - href={'/recurso/' + card.id} - downloadableLink={card.default_attachment_location} - - /></Col>)} - </Row> - <Row> - {row3.map(card => <Col md={3} sm={6} key={card.id}> - <ResourceCardFunction - avatar = {card.publisher.avatar} - id={card.id} - thumbnail = {card.thumbnail} - type = {card.object_type ? card.object_type : "Outros"} - title={card.name} - published={card.state === "published" ? true : false} - likeCount={card.likes_count} - liked={card.liked} - rating={card.review_average} - author={card.author} - tags={card.educational_stages} - href={'/recurso/' + card.id} - downloadableLink={card.default_attachment_location} - - /></Col>)} - </Row> - </Carousel> - ) + <Row style={{ paddingBottom: "5px" }}> + {row1.map((card) => ( + <Col md={3} sm={6} key={card.id}> + <ResourceCardFunction + avatar={card.publisher.avatar} + id={card.id} + thumbnail={card.thumbnail} + type={card.object_type ? card.object_type : "Outros"} + title={card.name} + published={card.state === "published" ? true : false} + likeCount={card.likes_count} + liked={card.liked} + rating={card.review_average} + author={card.author} + tags={card.educational_stages} + href={"/recurso/" + card.id} + downloadableLink={card.default_attachment_location} + /> + </Col> + ))} + </Row> + <Row> + {row2.map((card) => ( + <Col md={3} sm={6} key={card.id}> + <ResourceCardFunction + avatar={card.publisher.avatar} + id={card.id} + thumbnail={card.thumbnail} + type={card.object_type ? card.object_type : "Outros"} + title={card.name} + published={card.state === "published" ? true : false} + likeCount={card.likes_count} + liked={card.liked} + rating={card.review_average} + author={card.author} + tags={card.educational_stages} + href={"/recurso/" + card.id} + downloadableLink={card.default_attachment_location} + /> + </Col> + ))} + </Row> + <Row> + {row3.map((card) => ( + <Col md={3} sm={6} key={card.id}> + <ResourceCardFunction + avatar={card.publisher.avatar} + id={card.id} + thumbnail={card.thumbnail} + type={card.object_type ? card.object_type : "Outros"} + title={card.name} + published={card.state === "published" ? true : false} + likeCount={card.likes_count} + liked={card.liked} + rating={card.review_average} + author={card.author} + tags={card.educational_stages} + href={"/recurso/" + card.id} + downloadableLink={card.default_attachment_location} + /> + </Col> + ))} + </Row> + </Carousel> + ); } } @@ -130,13 +137,13 @@ class ReqCollections extends Component { constructor(props) { super(props); this.state = { - collections: [] + collections: [], }; } componentDidMount() { axios .get(`${apiUrl}/collections?limit=12&sort=["updated_at", "desc"]`) - .then(res => { + .then((res) => { this.setState({ collections: res.data }); console.log(res.data); }); @@ -147,35 +154,50 @@ class ReqCollections extends Component { var row3 = this.state.collections.slice(8, 13); return ( <Carousel showThumbs={false} infiniteLoop={true} showStatus={false}> - <Row style={{paddingBottom: "5px"}}> - {row1.map(card => <Col md={3} sm={6} key={card.id}> - <CollectionCardFunction name={card.name} - rating={card.score} - author={card.owner.name} - description={card.description} - thumbnails={card.items_thumbnails} - avatar={card.owner.avatar}/></Col>)} - </Row> - <Row> - {row2.map(card => <Col md={3} sm={6} key={card.id}> - <CollectionCardFunction name={card.name} - rating={card.score} - author={card.owner.name} - description={card.description} - thumbnails={card.items_thumbnails} - avatar={card.owner.avatar}/></Col>)} - </Row> - <Row> - {row3.map(card => <Col md={3} sm={6} key={card.id}> - <CollectionCardFunction name={card.name} - rating={card.score} - author={card.owner.name} - description={card.description} - thumbnails={card.items_thumbnails} - avatar={card.owner.avatar}/></Col>)} - </Row> - </Carousel> - ) + <Row style={{ paddingBottom: "5px" }}> + {row1.map((card) => ( + <Col md={3} sm={6} key={card.id}> + <CollectionCardFunction + name={card.name} + rating={card.score} + author={card.owner.name} + description={card.description} + thumbnails={card.items_thumbnails} + avatar={card.owner.avatar} + /> + </Col> + ))} + </Row> + <Row> + {row2.map((card) => ( + <Col md={3} sm={6} key={card.id}> + <CollectionCardFunction + name={card.name} + rating={card.score} + author={card.owner.name} + description={card.description} + thumbnails={card.items_thumbnails} + avatar={card.owner.avatar} + /> + </Col> + ))} + </Row> + <Row> + {row3.map((card) => ( + <Col md={3} sm={6} key={card.id}> + <CollectionCardFunction + name={card.name} + rating={card.score} + author={card.owner.name} + description={card.description} + thumbnails={card.items_thumbnails} + avatar={card.owner.avatar} + /> + </Col> + ))} + </Row> + </Carousel> + ); } } @@ -213,7 +235,7 @@ class SubPages extends Component { style={{ paddingBottom: "5px", borderBottom: "1px solid #ff7f00", - color: "#ff7f00" + color: "#ff7f00", }} > Recursos mais recentes{" "} @@ -226,23 +248,43 @@ class SubPages extends Component { </Visible> </Container> </React.Fragment> - ); - case "Materiais": - return ( - <React.Fragment> - <div style={{backgroundColor: "#e81f4f"}}> - <Container style={areaStyle}> - - <img src={materiais} alt="aba materiais" height="165" style={{float: "right"}}/> - <p>Nesta área, você acessa livremente materiais completos de formação, - como cursos já oferecidos pelo MEC e seus parceiros. São conteúdos - elaborados por equipes multidisciplinares e de autoria de pesquisadores - e educadores renomados nas áreas.</p> - </Container> - </div> - <Container style={{padding:"20px"}}> - <p style={{paddingBottom:"5px", borderBottom: "1px solid #e81f4f", color: "#e81f4f"}}> - Materiais mais recentes </p> + ); + case "Materiais": + return ( + <React.Fragment> + <div style={{ backgroundColor: "#e81f4f" }}> + <Container style={areaStyle}> + <Grid container spacing={5}> + <Grid item xs={3}> + <img + src={materiais} + alt="aba materiais" + height="165" + style={{ float: "right" }} + /> + </Grid> + <Grid item xs={9}> + <p style={{ textAlign: "justify", color: "#fff" }}> + Nesta área, você acessa livremente materiais completos de + formação, como cursos já oferecidos pelo MEC e seus + parceiros. São conteúdos elaborados por equipes + multidisciplinares e de autoria de pesquisadores e + educadores renomados nas áreas. + </p> + </Grid> + </Grid> + </Container> + </div> + <Container style={{ padding: "20px" }}> + <p + style={{ + paddingBottom: "5px", + borderBottom: "1px solid #e81f4f", + color: "#e81f4f", + }} + > + Materiais mais recentes{" "} + </p> <Carousel style={{ padding: "20px" }} @@ -298,7 +340,7 @@ class SubPages extends Component { style={{ paddingBottom: "5px", borderBottom: "1px solid #673ab7", - color: "#673ab7" + color: "#673ab7", }} > Coleções mais recentes{" "} diff --git a/src/Components/ColCardOwnerOptions.js b/src/Components/ColCardOwnerOptions.js index 76b5b750be97631f4262bc89408dac4524116fdb..37dc26977cd9133db5b644dad03eb6860f40ea04 100644 --- a/src/Components/ColCardOwnerOptions.js +++ b/src/Components/ColCardOwnerOptions.js @@ -28,6 +28,7 @@ import {Link} from 'react-router-dom' import MoreVertIcon from '@material-ui/icons/MoreVert'; import styled from 'styled-components' import ModalExcluirColecao from './ModalExcluirColecao.js' +import ModalEditarColecao from './ModalEditarColecao.js' export default function ColCardOwnerOptions (props) { const [anchorEl, setAnchorEl] = React.useState(null); @@ -43,11 +44,17 @@ export default function ColCardOwnerOptions (props) { const [modalExcluirOpen, toggleModalExcluir] = useState(false) const openModalExcluir = () => {toggleModalExcluir(true)} + const [modalEditarOpen, toggleModalEditar] = useState(false) + + return ( <> <ModalExcluirColecao id={props.id} open={modalExcluirOpen} handleClose={() => {toggleModalExcluir(false)}} /> + <ModalEditarColecao id={props.id} + open={modalEditarOpen} handleClose={() => {toggleModalEditar(false)}} + /> <div style={{fontSize: "12px"}}> <Button aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick} style={{color : "#666"}}> @@ -66,7 +73,7 @@ export default function ColCardOwnerOptions (props) { </Link> </StyledMenuItem> - <StyledMenuItem onClick={() => {console.log('TODO: MODAL EDITAR COLECAO')}}> + <StyledMenuItem onClick={() => {toggleModalEditar(true)}}> <ListItemIcon><CreateIcon /></ListItemIcon>Editar </StyledMenuItem> diff --git a/src/Components/ColaborarModal.js b/src/Components/ColaborarModal.js index cc2e2950c326e7c898f65ea3b8f6d8a40a26a761..3c971a28dfef4319067a57617677d4494c2ab7fa 100644 --- a/src/Components/ColaborarModal.js +++ b/src/Components/ColaborarModal.js @@ -7,6 +7,7 @@ import Backdrop from '@material-ui/core/Backdrop'; import { Store } from '../Store.js'; import CloseIcon from '@material-ui/icons/Close'; import LabeledCheckbox from "../Components/Checkbox.js" +import {Link} from 'react-router-dom' const StyledDivContainer = styled.div` background-color : rgb(255,255,255); @@ -86,7 +87,6 @@ export default function ColaborarModal (props) { aria-labelledby="transition-modal-title" aria-describedby="transition-modal-description" open={props.open} - centered="true" onClose={props.handleClose} closeAfterTransition @@ -121,9 +121,16 @@ export default function ColaborarModal (props) { na plataforma com toda a comunidade escolar do paÃs. </p> <StyledButtonsDiv> - <StyledButton> - <span style={{color:"#fff"}}>SIM</span> - </StyledButton> + + <Link to={{ + pathname : "/termos-publicar-recurso", + state : true + }}> + <StyledButton> + <span style={{color:"#fff"}}>SIM</span> + </StyledButton> + </Link> + <StyledButton> <span style={{color:"#fff"}}>NÃO</span> </StyledButton> diff --git a/src/Components/CollectionAuthor.js b/src/Components/CollectionAuthor.js new file mode 100644 index 0000000000000000000000000000000000000000..54ce444032c4e4cefc778371b1e8f4144188a320 --- /dev/null +++ b/src/Components/CollectionAuthor.js @@ -0,0 +1,73 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React from 'react'; +import { Grid } from '@material-ui/core'; +import styled from 'styled-components'; +import { Link } from 'react-router-dom'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import LinearProgress from '@material-ui/core/LinearProgress'; + + +export default function CollectionAuthor(props) { + return ( + <Grid container + direction="column" + justify="center" + alignItems="center"> + {props.imgsrc ? + <UserLink + to={`/usuario-publico/${props.author_id}`} + > + <UserAvatar src={props.imgsrc}/> + </UserLink> + : + <CircularProgress color="secondary"/> + } + <InfoText>Coleção organizada por:</InfoText> + {props.name ? + <UserLink to={`/usuario-publico/${props.author_id}`} > + <UserName>{props.name}</UserName> + </UserLink> + : + <CircularProgress /> + } + </Grid> + ); +} + +const UserAvatar = styled.img` + border-radius: 100px; + width: 100px; + height: auto; +` +const InfoText = styled.p` + margin-bottom: 0; + padding-bottom: 0; + color: #666; +` +const UserName = styled.h1` + margin-top: 10px; + color: #673ab7; +` +const UserLink = styled(Link)` + text-decoration: none; + &:focus, &:hover, &:visited, &:link, &:active { + text-decoration: none; + } +` diff --git a/src/Components/CollectionCommentSection.js b/src/Components/CollectionCommentSection.js new file mode 100644 index 0000000000000000000000000000000000000000..df6ead8183a7b462c0f588d6415bccd9317b2255 --- /dev/null +++ b/src/Components/CollectionCommentSection.js @@ -0,0 +1,170 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, { useRef, useState, useEffect } from 'react'; +import { Grid } from '@material-ui/core'; +import Card from '@material-ui/core/Card'; +import Button from '@material-ui/core/Button'; +import EditIcon from '@material-ui/icons/Edit'; +import styled from 'styled-components'; +import axios from 'axios'; +import { apiUrl } from '../env'; +import CommentForm from './ResourcePageComponents/CommentForm.js'; +import Comment from './Comment.js'; +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; +import Comentario from '../img/comentarios.png'; + +export default function CollectionCommentSection(props) { + const [post_snack_open, setPostSnackOpen] = useState(false); + const [delete_snack_open, setDeleteSnackOpen] = useState(false); + const [render_state, setRenderState] = useState(false); + const [reviews, setReviews] = useState([]); + const comment_ref = useRef(null); + + const forceUpdate = () => { setRenderState(!render_state); } + + const handlePostSnackbar = () => { + setPostSnackOpen(!post_snack_open); + } + + const handleDeleteSnackbar = () => { + setDeleteSnackOpen(!delete_snack_open); + } + + const handleScrollToCommentForm = () => { + window.scrollTo(0, comment_ref.current.offsetTop); + } + + function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; + } + + const NoCommentsMessage = () => { + const NoCommentsContainer=styled.div` + text-align: center; + margin-left: 9vw; + margin-right: 9vw; + ` + const BlueTitle=styled.h2` + color: #673ab7; + ` + const Secondary=styled.h3` + font-weight: 100; + ` + const ButtonText=styled.span` + font-weight: 900; + ` + const Image=styled.img` + ` + return ( + <NoCommentsContainer> + <Image src={Comentario} /> + <BlueTitle>Compartilhe sua opinião com a rede!</BlueTitle> + <Secondary>Gostou desta coleção? Comente e compartilhe com a rede sua opinião. Interagindo com a rede, você contribui para que mais coleções como esta sejam criadas.</Secondary> + <Button + variant="contained" + color="primary" + startIcon={<EditIcon />} + onClick={handleScrollToCommentForm} + > + <ButtonText>Relatar experiência</ButtonText> + </Button> + </NoCommentsContainer> + ); + } + const CollectionComments = () => { + return ( + <div> + <Title>{reviews.length} {reviews.length == 1 ? "Relato" : "Relatos"} sobre a Coleção</Title> + {reviews.map(r => { + return ( + <Comment + rerenderCallback={forceUpdate} + objectID={props.id} + reviewID={r.id} + reviewRatings={r.review_ratings} + authorID={r.user.id} + rating={r.rating_average} + authorName={r.user.name} + authorAvatar={r.user.avatar} + description={r.description} + createdAt={r.created_at} + handleSnackbar={handleDeleteSnackbar} + recurso={false} + /> + );})} + </div> + ); + } + + useEffect(() => { + axios.get(apiUrl+'/collections/'+props.id+'/reviews') + .then(res => { + setReviews(res.data); + }); + }, [render_state]); + + return ( + <CommentAreaContainer container xs={12} direction="row" justify="center" alignItems="center"> + <Grid item xs={12} ref={comment_ref}> + <CommentAreaCard> + <Title>Conte sua experiência com a coleção</Title> + <CommentForm colecao recursoId={props.id} + handleSnackbar={handlePostSnackbar} + rerenderCallback={forceUpdate} + /> + {reviews.length ? CollectionComments() : NoCommentsMessage()} + </CommentAreaCard> + </Grid> + <Snackbar + open={post_snack_open} + autoHideDuration={6000} + onClose={handlePostSnackbar} + anchorOrigin={{vertical: 'top', horizontal: 'right'}} + > + <Alert onClose={handlePostSnackbar} severity="info"> + Seu comentário foi publicado com sucesso! + </Alert> + </Snackbar> + <Snackbar + open={delete_snack_open} + autoHideDuration={6000} + onClose={handleDeleteSnackbar} + anchorOrigin={{vertical: 'top', horizontal: 'right'}} + > + <Alert onClose={handleDeleteSnackbar} severity="info"> + Comentário deletado com sucesso. + </Alert> + </Snackbar> + </CommentAreaContainer> + ); +} + + +const CommentAreaContainer=styled(Grid)` + margin-left: 10%; + margin-right: 10%; +` +const CommentAreaCard=styled(Card)` + padding: 45px; +` +const Title=styled.h1` + font-weight: 100; + color: #666; +` diff --git a/src/Components/CollectionDescription.js b/src/Components/CollectionDescription.js new file mode 100644 index 0000000000000000000000000000000000000000..062a13bca5ba4b24c3eee0b3889131eda749b209 --- /dev/null +++ b/src/Components/CollectionDescription.js @@ -0,0 +1,103 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, { useContext, useState, useEffect } from 'react'; +import axios from 'axios'; +import { Store } from '../Store.js' +import { Grid } from '@material-ui/core'; +import Button from '@material-ui/core/Button'; +import GetAppIcon from '@material-ui/icons/GetApp'; +import AddIcon from '@material-ui/icons/Add'; +import styled from 'styled-components'; +import LinearProgress from '@material-ui/core/LinearProgress'; +import CollectionReview from './CollectionReview.js'; +import FollowCollectionButton from './FollowCollectionButton.js'; +import { apiUrl, apiDomain } from '../env'; + +export default function CollectionDescription(props) { + const { state } = useContext(Store); + const [download_url, setDownloadUrl] = useState(''); + + useEffect(() => { + const body = { + "package": { + "object": [{"type": "Collection", "id": props.collection_id}] + }}; + axios + .post(apiUrl+'/package', body) + .catch(err => { + if (err.response && err.response.status === 302) { + setDownloadUrl(apiDomain+'/'+err.response.data.url); + } + });}, [props.collection_id]); + + return ( + <Grid container direction="column" justify="center" alignItems="center"> + <Grid item> + <Title>{props.title}</Title> + </Grid> + <Grid item container + direction="row" justify="space-between" alignItems="center" + > + <Grid item sm={4}> + <CollectionReview + scrollToComment={props.scrollToComments} + id={props.collection_id}/> + </Grid> + <Grid item container sm={8} + direction="column" justify="center" alignItems="flex-end" + > + <Grid item style={{marginBottom: 10}}> + <DownloadAnchor href={download_url} > + <DownloadButton + variant="outlined" + color="primary" + startIcon={<GetAppIcon fontSize="large"/>} + size="large" + > + <ButtonText>Baixar Coleção</ButtonText> + </DownloadButton> + </DownloadAnchor> + </Grid> + <Grid item> + <FollowCollectionButton user_id={state.currentUser.id} collection_id={props.collection_id}/> + </Grid> + </Grid> + </Grid> + + </Grid> + ); +} + +const Title=styled.h1` + font-size: 3em; + color: rgb(102, 102, 102); + float: left; +` +const ButtonText=styled.span` + font-weight: bolder; + font-size: 1.2em; +` +const DownloadButton=styled(Button)` + padding-left: 10; + padding-right: 10; + width: 250px; +` +const DownloadAnchor=styled.a` + text-decoration: none !important; +` diff --git a/src/Components/CollectionReview.js b/src/Components/CollectionReview.js new file mode 100644 index 0000000000000000000000000000000000000000..be63b1d3a1a81e92d4358956a3461ea6302f3c9d --- /dev/null +++ b/src/Components/CollectionReview.js @@ -0,0 +1,120 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, { useContext, useState, useEffect } from 'react'; +import { Grid } from '@material-ui/core'; +import styled from 'styled-components'; +import Rating from '@material-ui/lab/Rating'; +import IconButton from '@material-ui/core/IconButton'; +import StarBorderIcon from '@material-ui/icons/StarBorder'; +import FavoriteIcon from '@material-ui/icons/Favorite'; +import InfoIcon from '@material-ui/icons/Info'; +import axios from 'axios'; +import { apiUrl } from '../env'; +import { Store } from '../Store.js' +import ReportModal from './ReportModal.js'; +import SignUpModal from './SignUpModal.js'; +import LoginModal from './LoginModal.js'; + +export default function CollectionReview(props) { + const [likes, setLikes] = useState(0); + const [liked, setLiked] = useState(false); + const [stars, setStars] = useState(0); + const [reportOpen, setReportOpen] = useState(false); + const [sign_up_open, setSignUpOpen] = useState(false); + const [log_in_open, setLoginOpen] = useState(false); + const { state } = useContext(Store); + + useEffect(() => { + axios.get(apiUrl+'/collections/'+props.id) + .then(res => { + setLikes(Number(res.data.likes_count)); + setLiked(res.data.liked); + }); + }, [props.id]); + + const handleClickReport = () => { + setReportOpen(true); + } + + const handleLikeClick = () => { + if (state.currentUser.id) { + const url = apiUrl+'/collections/'+props.id+'/like'; + if (!liked) + axios.put(url); + else + axios.delete(url); + setLiked(!liked); + } else + setSignUpOpen(true); + } + + const handleSetStars = (value) => { + setStars(value); + props.scrollToComment(); + } + + const handleCloseModal = () => { + setReportOpen(false); + } + + return ( + <Grid container direction="row" justify="center" alignItems="center"> + <Grid item sm={8}> + <Rating + name="customized-empty" + value={stars} + onChange={(e, value) => handleSetStars(value)} + precision={0.5} + style={{color:"#666"}} + emptyIcon={<StarBorderIcon fontSize="inherit" />} + /> + </Grid> + <Grid item sm={4}> + <IconButton aria-label="like" onClick={handleLikeClick}> + {likes + (liked ? 1 : 0)}<FavoriteIcon /> + </IconButton> + </Grid> + <Grid item sm={12}> + <IconButton + aria-label="report" + style={{fontSize: 'small'}} + onClick={handleClickReport}> + <InfoIcon />Reportar erro ou abuso + </IconButton> + <ReportModal + open={reportOpen} + handleClose={handleCloseModal} + form="colecao" + complainableId={props.id} + complainableType="Collection" + /> + </Grid> + <SignUpModal + open={sign_up_open} + handleClose={() => setSignUpOpen(false)} + openLogin={() => setLoginOpen(true)} + /> + <LoginModal + open={log_in_open} + handleClose={() => setLoginOpen(false)} + /> + + </Grid> + ); +} diff --git a/src/Components/Comment.js b/src/Components/Comment.js index 5c797282aeccccb928ede08e34d1c0e207830e3e..e1a69e4d785d2edec29baf4c4612b56eeda776b5 100644 --- a/src/Components/Comment.js +++ b/src/Components/Comment.js @@ -327,3 +327,4 @@ const AvatarDiv = styled.div` vertical-align : middle; } ` + diff --git a/src/Components/Dropdown.js b/src/Components/Dropdown.js index 60624e7f2d2c8cb5e5a55f80a00cacbcc48a67bc..f186c6938796c5ad275bd3b7881f0c929ae3459a 100644 --- a/src/Components/Dropdown.js +++ b/src/Components/Dropdown.js @@ -85,11 +85,11 @@ function Dropdown(props) { <ExpandMoreIcon/> </Button> { open && - <Popper open={open} keepMounted transition disablePortal> + <Popper open={open} keepMounted transition disablePortal placement={'bottom'}> {({ TransitionProps, placement }) => ( <Grow {...TransitionProps} - style={{ transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom' }} + style={{ transformOrigin: 'center top !important', anchorOrigin : "center bottom !important"}} > <Paper id="menu-list-grow"> <MenuList> diff --git a/src/Components/EcFooter.js b/src/Components/EcFooter.js index 413f7fcc95c1fa51ad50aa205ebe93008c2467ab..3340f3d78b77b3cca3db805d3ebe538ef72256bf 100644 --- a/src/Components/EcFooter.js +++ b/src/Components/EcFooter.js @@ -19,7 +19,7 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React, {Component} from 'react'; import {Row, Col, Container} from 'react-grid-system'; import eduConectada from '../img/educa-conectada.png'; -import { Link } from '@material-ui/core'; +import styled from 'styled-components'; const blueFooter={ backgroundColor: "#00bcd4", @@ -27,7 +27,7 @@ const blueFooter={ display: "block", paddingTop: "2em", paddingBottom: "2em", - verticalAlign: "bottom" + verticalAlign: "bottom", } const listStyle={ listStyleType: "none", @@ -35,6 +35,10 @@ const listStyle={ padding: "0", lineHeight: "1.6", } +const WhiteLink = styled.a` + text-decoration: none; + color: white; +` class EcFooter extends Component{ render(){ @@ -45,20 +49,20 @@ class EcFooter extends Component{ <Col md={4} sm={5} xs={5}> <h4>Sobre</h4> <ul style={listStyle}> - <li> <a href="/sobre">Sobre a Plataforma</a> </li> - <Link> <a href="/sobre#portaisparceiros">Portais Parceiros</a> </Link> - <li> <a href="/termos">Termos de Uso</a> </li> - <li> <a href="/contato">Contato</a> </li> + <li> <WhiteLink href="/sobre">Sobre a Plataforma</WhiteLink> </li> + <li> <WhiteLink href="/sobre#parceiros">Portais Parceiros</WhiteLink> </li> + <li> <WhiteLink href="/termos">Termos de Uso</WhiteLink> </li> + <li> <WhiteLink href="/contato">Contato</WhiteLink> </li> </ul> </Col> <Col md={4} sm={5} xs={5}> <h4>Ajuda</h4> <ul style={listStyle}> - <li> <a href="/ajuda">Central de Ajuda</a> </li> - <li> <a href="/publicando-recurso">Publicando Recursos</a> </li> - <li> <a href="/encontrando-recurso">Encontrando Recursos</a> </li> - <li> <a href="/participando-da-rede">Participando da Rede</a> </li> - <li> <a href="/gerenciando-conta">Gerenciando a Conta</a> </li> + <li> <WhiteLink href="/ajuda">Central de Ajuda</WhiteLink> </li> + <li> <WhiteLink href="/publicando-recurso">Publicando Recursos</WhiteLink> </li> + <li> <WhiteLink href="/encontrando-recurso">Encontrando Recursos</WhiteLink> </li> + <li> <WhiteLink href="/participando-da-rede">Participando da Rede</WhiteLink> </li> + <li> <WhiteLink href="/gerenciando-conta">Gerenciando a Conta</WhiteLink> </li> </ul> </Col> <Col md={4} sm={12} xs={12}> diff --git a/src/Components/EditarColecaoForm.js b/src/Components/EditarColecaoForm.js new file mode 100644 index 0000000000000000000000000000000000000000..f40f811c1c953e8770092d131c6bef6e6a9a8b5a --- /dev/null +++ b/src/Components/EditarColecaoForm.js @@ -0,0 +1,232 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, {useState, useContext, useEffect} from 'react' +import {Store} from '../Store.js' +import { Button } from '@material-ui/core'; +import styled from 'styled-components' +import Radio from '@material-ui/core/Radio'; +import RadioGroup from '@material-ui/core/RadioGroup'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import FormControl from '@material-ui/core/FormControl'; +import TextField from '@material-ui/core/TextField'; +import axios from 'axios' +import {apiUrl} from '../env'; +import {getAxiosConfig} from './HelperFunctions/getAxiosConfig' + +export default function EditarColecaoForm (props) { + const {state} = useContext(Store) + + useEffect(() => { + axios.get(`${apiUrl}/collections/${props.id}`).then( + (res) => { + setColName({key : false, value : res.data.name}) + setValue( res.data.privacy === 'public' ? 'pública' : 'privada') + handleColDescription(res.data.description) + }, + (err) => {console.log(err)} + ) + }, []) + + const [value, setValue] = React.useState(-1); + + /*values are set according to backend complaint id*/ + const [options] = React.useState([ + {value : "pública", text :'Pública (Sua coleção estará disponÃvel para todos)'}, + {value : "privada", text : 'Privada (Somente você poderá visualizar esta coleção)'} + ]) + + const handleChange = (event) => { + setValue(event.target.value); + }; + + const [colName, setColName] = React.useState({ + key : false, + value : "", + }) + + const handleColName = (e) => { + const userInput = e.target.value + + const flag = userInput.length == 0 ? true : false + + setColName({...colName, + key : flag, + value : userInput + }) + } + + const formSubmit = (e) => { + e.preventDefault() + + {/*if user didn't select either one, default to privada*/} + const finalRadioValue = value === 'pública' ? 'public' : 'private' + const finalColName = colName + + console.log(finalRadioValue, finalColName.value) + if(!(finalColName.key)) { + let payload = { + "collection" : { + "name" : finalColName.value, + "owner_id" : state.currentUser.id, + "owner_type" : "User", + "privacy" : finalRadioValue + } + } + let config = getAxiosConfig() + + axios.put( (`${apiUrl}/collections/${props.id}`), payload, config + ).then( + (response) => { + console.log(response) + if ( response.headers['access-token'] ) { + sessionStorage.setItem('@portalmec/accessToken', response.headers['access-token']) + } + props.finalize(response.data.id) + }, (error) =>{console.log(error)}) + } + } + + const [colDescription, handleColDescription] = React.useState("") + const setColDescription = (e) => {handleColDescription(e.target.value)} + + return ( + <form onSubmit={(e) => {formSubmit(e)}} style={{textAlign : "left"}}> + + <StyledTextField + id = {"col-name"} + label={"Nome"} + type = {"text"} + value = {colName.value} + onChange = {e => handleColName(e)} + error = {colName.key} + required = {true} + style={{width:"100%"}} + /> + + <StyledTextField + id = {"col-description"} + label={"Descrição"} + type = {"text"} + value = {colDescription} + multiline + rows={5} + onChange = {e => setColDescription(e)} + style={{width:"100%"}} + /> + + <span style={{fontSize : "12px", color : "#b3b3b3"}}>Esta coleção é:</span> + <StyledFormControl component="fieldset"> + <RadioGroup value={value} onChange={handleChange}> + { + options.map(option => + <FormControlLabel key={option.value} value={option.value} control={<Radio color="#673ab7"/>} label={option.text} /> + ) + } + </RadioGroup> + </StyledFormControl> + + + <ButtonsDiv> + <ButtonCancelar onClick={props.handleClose}>CANCELAR</ButtonCancelar> + <ButtonEnviar type="submit">SALVAR</ButtonEnviar> + </ButtonsDiv> + </form> + ); +} + +export const ButtonsDiv = styled.div` + display : flex; + flex-direction : row; + justify-content : center; + align-items : center; +` + +export const ButtonCancelar = styled(Button)` + &:hover { + background-color : rgba(158,158,158,0.2) !important; + } + height : 36px !important; + padding-left : 16px !important; + padding-right : 16px !important; + font-weight : 500 !important; + border-radius : 3px !important; + color :#666 !important; + background-color: transparent; + min-width : 88px !important; + height : 36px !important; +` + +export const ButtonEnviar = styled(Button)` + background-color : #673ab7 !important; + color : #fff !important; + font-size: 14px !important; + font-weight: 500 !important; + height: 36px !important; + border-radius: 3px !important; + padding-left: 16px !important; + padding-right: 16px !important; + box-shadow: 0 2px 5px 0 rgba(0,0,0,.26) !important; + outline : none !important; + min-width : 88px !important; + vertical-align : middle !important; + margin : 6px 8px !important; + text-decoration : none !important; + + .MuiButton-label { + padding-right : 16px; + padding-left : 16px; + } +` +export const StyledTextField = styled(TextField)` + margin : 18px 0 !important; + + .MuiFormHelperText-root { + text-align : right; + } + + label.Mui-focused { + color : #673ab7; + } + + label.Mui-focused.Mui-error { + color : red; + } + + .MuiInput-underline::after { + border-bottom: 2px solid #673ab7; + } +` + +export const StyledFormControl = styled(FormControl)` + display : block !important; + + .MuiFormControlLabel-root { + color : #666; + } + .MuiIconButton-label { + color : #666; + } + .PrivateRadioButtonIcon-checked { + color : orange; + } + + .MuiTypography-body1 { + font-size : 14px; + } +` diff --git a/src/Components/FloatingDownloadButton.js b/src/Components/FloatingDownloadButton.js new file mode 100644 index 0000000000000000000000000000000000000000..5d78b87d0f5eebc66b5fd63a478b13fa00147ccd --- /dev/null +++ b/src/Components/FloatingDownloadButton.js @@ -0,0 +1,72 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, { useState, useEffect } from 'react'; +import styled from 'styled-components'; +import axios from 'axios'; +import {apiUrl} from '../env'; +import GetAppIcon from '@material-ui/icons/GetApp'; +import Fab from '@material-ui/core/Fab'; +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; + +function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; +} + +export default function FloatingDownloadButton (props) { + const [snackbar, setSnackbar] = useState(false); + + const handleClickDownload = () => { + if (props.empty_selection) + setSnackbar(true); + } + + const handleClose = () => { + setSnackbar(false); + } + + return ( + <div> + <DownloadAnchor href={props.url} alt="Baixar recursos selecionados"> + <FloatingDownload + color="primary" + aria-label="download" + onClick={handleClickDownload} + > + <GetAppIcon /> + </FloatingDownload> + </DownloadAnchor> + <Snackbar open={snackbar} autoHideDuration={6000} onClose={handleClose}> + <Alert onClose={handleClose} severity="alert"> + Selecione recursos para poder baixar + </Alert> + </Snackbar> + </div> + ); +} + +const DownloadAnchor=styled.a` + text-decoration: none !important; +` + +const FloatingDownload=styled(Fab)` + position: fixed !important; + right: 15px !important; + bottom: 25px !important; +` diff --git a/src/Components/FollowCollectionButton.js b/src/Components/FollowCollectionButton.js new file mode 100644 index 0000000000000000000000000000000000000000..5e3fd33c9ce3b789de2d15373e63e6858b937752 --- /dev/null +++ b/src/Components/FollowCollectionButton.js @@ -0,0 +1,126 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, { useState, useEffect } from 'react'; +import Button from '@material-ui/core/Button'; +import CheckIcon from '@material-ui/icons/Check'; +import AddIcon from '@material-ui/icons/Add'; +import styled from 'styled-components'; +import SignUpModal from './SignUpModal.js'; +import axios from 'axios'; +import {apiUrl} from '../env'; + +export default function FollowCollectionButton(props) { + const [icon, setIcon] = useState(<AddIcon fontSize="large"/>); + const [button_text, setButtonText] = useState("Seguir Coleção"); + const [variant, setVariant] = useState("outlined"); + const [sign_up_open, setSignUpOpen] = useState(false); + const [following, setFollowing] = useState(false); //user following collection + + useEffect(() => { + axios.get(apiUrl+'/users/'+props.user_id+'/following/Collection') + .then(res => { + for (const element in res.body) + if (element.id == props.collection_id) + setFollowing(true); + }); + }, []) + + //handleMouse{Enter, Leave} only do anything when user follows given collection: + const handleMouseEnter = () => { + if (following) { + setVariant("outlined"); + setButtonText("Deixar de seguir"); + setIcon(null); + } + } + + const handleMouseLeave = () => { + if (following) { + setVariant("contained"); + setButtonText("Seguindo"); + setIcon(<CheckIcon fontSize="large" />); + } + } + + const handleClick = () => { + if (!props.user_id) + setSignUpOpen(true); + else if (!following) { + setVariant("contained"); + setButtonText("Seguindo"); + setIcon(<CheckIcon fontSize="large"/>) + setFollowing(true); + axios.post(apiUrl+'/collections/'+props.collection_id+'/follow') + .then(res => { + if (Number(res.status) != 201) + setFollowing(false); + setIcon(<AddIcon fontSize="large"/>); + setButtonText("Seguindo"); + setVariant("contained"); + }); + } else { + setVariant("outlined"); + setButtonText("Deixar de seguir"); + setIcon(<AddIcon fontSize="large"/>); + setFollowing(false); + axios.delete(apiUrl+'/collections/'+props.collection_id+'/follow') + .then(res => { + if (Number(res.status) == 200) + setFollowing(true); + setIcon(<CheckIcon fontSize="large"/>); + setButtonText("Deixar de seguir"); + setVariant("outlined"); + }); + } + }; + + if (!props.user_is_owner) + return ( + <div> + <FollowButton + variant={variant} + color="primary" + startIcon={icon} + size="large" + onMouseEnter={handleMouseEnter} + onMouseLeave={handleMouseLeave} + onClick={handleClick} + > + <ButtonText>{button_text}</ButtonText> + </FollowButton> + <SignUpModal open={sign_up_open} handleClose={() => setSignUpOpen(false)} /> + </div> + ); + else return (<div></div>); +} + +const Title=styled.h1` + font-size: 3em; + color: rgb(102, 102, 102); + float: left; +` +const ButtonText=styled.span` + font-weight: bolder; + font-size: 1.2em; +` +const FollowButton=styled(Button)` + padding-left: 10; + padding-right: 10; + width: 250px; +` diff --git a/src/Components/GuardarModal.js b/src/Components/GuardarModal.js index e43a63fc3a122cf882407e8f59d6c3676fc35955..93d38cb6c95c28ac224175c36a5cb7db4452e112 100644 --- a/src/Components/GuardarModal.js +++ b/src/Components/GuardarModal.js @@ -27,7 +27,6 @@ import {Store} from '../Store.js' import axios from 'axios' import {apiUrl, apiDomain} from '../env'; import CloseIcon from '@material-ui/icons/Close'; -import Grid from '@material-ui/core/Grid'; import PublicIcon from '@material-ui/icons/Public'; import LockIcon from '@material-ui/icons/Lock'; import LoadingSpinner from './LoadingSpinner.js' diff --git a/src/Components/Header.js b/src/Components/Header.js index 7da2d87ff8f320342adf75d9494d096874239dbc..e9aa87d2d56b11e1b0ec94553c1f7f5c3a6be88b 100644 --- a/src/Components/Header.js +++ b/src/Components/Header.js @@ -29,6 +29,8 @@ import ColaborarModal from './ColaborarModal.js' import Snackbar from '@material-ui/core/Snackbar'; import MuiAlert from '@material-ui/lab/Alert'; import {useLocation} from 'react-router-dom' +import MenuBarMobile from './MenuBarMobile.js' + //const StyledButton = styled(Button)` // background : #ffa54c !important; // boxShadow :none; @@ -45,10 +47,21 @@ export default function Header(props){ const [successfulLoginOpen, handleSuccessfulLogin] = useState(false) const [modalColaborar, setModalColaborar] = useState(false) - let loc = useLocation() + useEffect ( () => { + if (state.currentUser.askTeacherQuestion == true) { + dispatch({ + type: "TOGGLE_MODAL_COLABORAR_PLATAFORMA", + modalColaborarPlataformaOpen: true + }); + } + }, [state.currentUser.askTeacherQuestion]) + const redirect = () => { + props.history.push('/') + } + + let loc = useLocation() useEffect(() => { - console.log(loc) let query = new URLSearchParams(loc.search) //POR PARAMETRO @@ -94,7 +107,7 @@ export default function Header(props){ sessionStorage.setItem('@portalmec/id', response.data.data.id) sessionStorage.setItem('@portalmec/username', response.data.data.name) sessionStorage.setItem('@portalmec/uid', response.data.data.uid) - + redirect() }, (err) => { console.log(err) @@ -126,23 +139,40 @@ export default function Header(props){ }) } - return( - <> - <AcessibilityBar/> - <Snackbar open={successfulLoginOpen} autoHideDuration={1000} onClose={toggleSnackbar} - anchorOrigin = {{ vertical:'top', horizontal:'center' }} - > + let windowWidth = window.innerWidth + + return ( + <React.Fragment> + { + windowWidth > 990 && + <AcessibilityBar/> + } + <Snackbar open={successfulLoginOpen} autoHideDuration={1000} onClose={toggleSnackbar} + anchorOrigin = {{ vertical:'top', horizontal:'center' }} + > <Alert severity="success" style={{backgroundColor:"#00acc1"}}>Você está conectado(a)!</Alert> - </Snackbar> - <MenuBar openSearchBar={handleClickSearch} openSignUp = {handleSignUp} openLogin = {handleLogin}/> - { state.searchOpen && - <SearchBar/> - } - <SignUpModal open={signUpOpen} handleClose={handleSignUp} openLogin={handleLogin}/> - <LoginModal open={loginOpen} handleClose={() => setLogin(false)} openSignUp={handleSignUp} - openSnackbar={() => {handleSuccessfulLogin(true)}}/> - <ColaborarModal open={modalColaborar} handleClose={() => {setModalColaborar(!modalColaborar)}} /> - - </> + </Snackbar> + { + windowWidth > 990 ? + ( + <React.Fragment> + <MenuBar openSearchBar={handleClickSearch} openSignUp = {handleSignUp} openLogin = {handleLogin}/> + { + state.searchOpen && + <SearchBar/> + } + </React.Fragment> + + ) + : + ( + <MenuBarMobile openSignUp = {handleSignUp} openLogin = {handleLogin}/> + ) + } + <SignUpModal open={signUpOpen} handleClose={handleSignUp} openLogin={handleLogin}/> + <LoginModal open={loginOpen} handleClose={() => setLogin(false)} openSignUp={handleSignUp} + openSnackbar={() => {handleSuccessfulLogin(true)}}/> + <ColaborarModal open={modalColaborar} handleClose={() => {setModalColaborar(!modalColaborar)}} /> + </React.Fragment> ) } diff --git a/src/Components/LoginContainer.js b/src/Components/LoginContainer.js deleted file mode 100644 index aaf89d2182dfb74eedb1da3228ea950ae5880e76..0000000000000000000000000000000000000000 --- a/src/Components/LoginContainer.js +++ /dev/null @@ -1,320 +0,0 @@ -/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre -Departamento de Informatica - Universidade Federal do Parana - -This file is part of Plataforma Integrada MEC. - -Plataforma Integrada MEC is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Plataforma Integrada MEC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ -import React, {Component} from "react"; -import GoogleLogin from 'react-google-login' -import { Button } from '@material-ui/core'; -//import FacebookLogin from 'react-facebook-login'; -import CloseIcon from '@material-ui/icons/Close'; -import styled from 'styled-components' -import {device} from './device.js' -import LabeledCheckbox from './Checkbox.js' -import FormInput from "./FormInput.js" -import GoogleLogo from "../img/logo_google.svg" - -//arrumar isso -const responseGoogle = (response) => { - console.log(response); -} - -class LoginContainer extends Component { - constructor (props) { - super(props); - - this.state = { - email : localStorage.getItem("@portalmec/email") || "", - senha : localStorage.getItem("@portalmec/senha") ||"", - checkboxChecked : false - }; - this.handleChecked = this.handleChecked.bind(this) - } - - switchModal = (e) => { - e.preventDefault() - this.props.handleClose() - this.props.openSignUp() - } - - handleChange = e => { - this.setState({[e.target.name]: e.target.value}) - } - - onSubmit = (e) => { - e.preventDefault(); - const login = this.state - - this.props.handleLoginInfo(login); - - this.setState({ - email: "", - senha: "" - }) - } - - handleChecked = (e) => { - const value = !this.state.checkboxChecked - console.log(this.state.checkboxChecked) - console.log(value) - this.setState({ - checkboxChecked :value - }) - } - - render () { - return ( - <ContainerStyled > - <DialogHeaderStyled> - <span style={{width:"32px"}}/> - <H2Styled> Entrar - </H2Styled> - <StyledCloseModalButton onClick={this.props.handleClose}> - <CloseIcon/> - </StyledCloseModalButton> - </DialogHeaderStyled> - - <DialogContentDiv> - <SocialConnectDiv> - <StyledGoogleLoginButton - clientId="658977310896-knrl3gka66fldh83dao2rhgbblmd4un9.apps.googleusercontent.com" - - onSuccess={responseGoogle} - onFailure={responseGoogle} - cookiePolicy={'single_host_origin'} - > - <span style={{textTransform:"none", fontSize:"13px", color : "#666"}}>Usando o Google</span> - </StyledGoogleLoginButton> - </SocialConnectDiv> - - <H3Div> - <H3Styled> - <RightSideStrikedH3/> - <span style={{verticalAlign:"middle"}}>ou</span> - <LeftSideStrikedH3/> - </H3Styled> - </H3Div> - - <form onSubmit={this.onSubmit}> - <FormInput - inputType={"text"} - name={"email"} - value={this.state.email} - placeholder={"E-mail"} - handleChange={e => this.handleChange(e)} - required={true} - /> - <br/> - <FormInput - inputType={"password"} - name={"senha"} - value={this.state.senha} - placeholder={"Senha"} - handleChange={e => this.handleChange(e)} - required={true} - /> - <br/> - - <RememberRecover> - <LabeledCheckbox label={<StyledLabel><StyledSpan>Lembrar-me</StyledSpan></StyledLabel>} handleChange={this.handleChecked} /> - <UserForgotTheirPasswordSpan>Esqueceu a senha? <a href="recuperar-senha" style={{textAlign: "right", color:"#4cd0e1"}}>Clique aqui!</a></UserForgotTheirPasswordSpan> - </RememberRecover> - - <ConfirmContainerStyled> - <StyledLoginButton type="submit" variant="contained"> - <span style={{borderRadius:"3px", boxSizing:"border-box", fontFamily:"Roboto, sans serif", fontWeight:"500", color:"#fff"}}>ENTRAR</span> - </StyledLoginButton> - </ConfirmContainerStyled> - </form> - - <DialogFooterStyled> - <span style={{textAlign:"center", fontSize: "14px", color:"rgb(102, 102, 102)"}}>Ainda não tem cadastro? <StyledAnchor href="" onClick={e => this.switchModal(e)}>CADASTRE-SE</StyledAnchor></span> - </DialogFooterStyled> - </DialogContentDiv> - </ContainerStyled> - ) - } -} - -export default LoginContainer - -const ContainerStyled = styled.div` - box-sizing : border-box; - background-color : white; - max-width : none; - display : flex; - flex-direction : column; - min-width : 440px; - min-height : 550px; - align : center; - padding : 10px; - border-radius: 4px; - line-height : 20px; - font-size : 14px; - @media ${device.mobileM} { - width : 100%; - height : 100%; - } -` - -export const DialogHeaderStyled = styled.div` - text-align : center; - display : flex; - flex-direction : row; - justify-content : space-between; - padding : 10px 26px 0 26px; - height : 64px; -` -const H2Styled = styled.h2` - align-self : center; - color : #666; - font-size : 26px; - font-weight : 100; - font-family: 'Roboto', sans serif, 'Helvetica Neue', Helvetica, Arial, sans-serif !important; - justify-content: space-between; - text-align: center; - letter-spacing: .005em; -` - -export const StyledCloseModalButton = styled(Button)` - display : inline-block; - position : relative; - float : right !important; - margin-right : -8px !important; - background : transparent !important; - min-width: 0 !important; - width : 40px; -` -export const DialogContentDiv = styled.div` - padding : 20px 30px; - overflow : visible !important; -` - -export const SocialConnectDiv = styled.div` - margin-top : 0; - display : flex; - flex-direction : row; -` -export const StyledGoogleLoginButton = styled(GoogleLogin)` - background-color : #fff !important; - color : #666 !important; - border : 1px solid rgb(66, 133, 244); - box-shadow: 0 0 0 1px #4285f4 !important; - :hover { - background-color: #f4f4f4 !important; - } -` - -const DialogFooterStyled = styled.div` - box-sizing : border-box; - font-family : 'Roboto', sans serif; - margin : 20px -20px; - padding-top : 20px; - border-top : 1px #e5e5e5 solid; - justify-content : center; - text-align : center; - line-height : 1.42857143 -` - - -const RightSideStrikedH3 = styled.div` - display : inline-block; - border-bottom: 1px dotted #666; - vertical-align : middle; - font-weight : 500; - margin-right : 5px; - width : 45%; -` - -const LeftSideStrikedH3 = styled.div` - display : inline-block; - border-bottom: 1px dotted #666; - vertical-align : middle; - font-weight : 500; - margin-left : 5px; - width : 45%; -` - -export const H3Div = styled.div` - margin-top : 0; - margin-bottom : 10px; -` - -const H3Styled = styled.h3` - overflow : hidden; - text-align : center; - font-size : 14px; - color : #666; - margin : 10px 0; -` - -const StyledAnchor = styled.a` - color : #00bcd4; - text-decoration : none; -` -const ConfirmContainerStyled = styled.div` - display : flex; - margin-top : 10px; - align-items : center; - justify-content : center; -` -const StyledLoginButton = styled(Button)` - background-color : #00bcd4 !important; - box-shadow : none !important; - outline: none !important; - border : 0 !important; - overflow : hidden !important; - width : 35% !important; - display : inline-block !important; - font-family : 'Roboto', sans serif !important; - font-size: 14px !important; - height : 36px !important; - align-items : center !important; - border-radius: 3px !important; - align-self : 50% !important; - :hover { - background-color : #00acc1 !important; - } -` - - -const RememberRecover = styled.div` - display : flex; - justify-content : space-between; - font-size: 12px; - font-weight : 400; -` - -const StyledLabel = styled.div` - box-sizing : border-box; - position : relative; - vertical-align : middle !important; - color : #666; - -` - -const UserForgotTheirPasswordSpan = styled.span` - margin-top : 1em; - font-size : 12px; - font-weight : 400; - text-align : right; - color : #666; -` - -const StyledSpan = styled.span` - font-size : 12px; - font-weight : 400; - padding-top : 2px; -` diff --git a/src/Components/LoginContainerFunction.js b/src/Components/LoginContainerFunction.js index 3f8c41a24701af567f385b699ff616e44de6a1fd..331a53c917cddd8717d54b8e74083a35b196a0ef 100644 --- a/src/Components/LoginContainerFunction.js +++ b/src/Components/LoginContainerFunction.js @@ -27,7 +27,7 @@ import FormInput from "./FormInput.js" import GoogleLogo from "../img/logo_google.svg" import ValidateUserInput from '../Components/FormValidationFunction.js' import {Link} from 'react-router-dom' -import {apiUrl} from '../env'; +import {apiUrl} from '../env.js' async function handleGoogleAttempt () { console.log("handleGoogleAttempt") @@ -103,11 +103,6 @@ export default function LoginContainer (props) { } - //arrumar isso - const handleGoogleResponse = (response) => { - console.log(response); - } - return ( <div> <ContainerStyled > @@ -122,7 +117,10 @@ export default function LoginContainer (props) { <DialogContentDiv> <SocialConnectDiv> - <Button onClick={handleGoogleAttempt}>login com google</Button> + <GoogleLoginButton onClick={handleGoogleAttempt}> + <img src={GoogleLogo} alt="google-logo" className="google-logo"/> + <span>Usando o Google</span> + </GoogleLoginButton> </SocialConnectDiv> <H3Div> @@ -196,6 +194,8 @@ export default function LoginContainer (props) { width : 100%; min-width : unset; height : 100%; + min-width : unset !important; + } ` @@ -265,7 +265,7 @@ export const RightSideStrikedH3 = styled.div` vertical-align : middle; font-weight : 500; margin-right : 5px; - width : 45%; + width : 44%; ` export const LeftSideStrikedH3 = styled.div` @@ -274,7 +274,7 @@ export const RightSideStrikedH3 = styled.div` vertical-align : middle; font-weight : 500; margin-left : 5px; - width : 45%; + width : 44%; ` export const H3Div = styled.div` @@ -347,3 +347,21 @@ export const RightSideStrikedH3 = styled.div` font-weight : 400; padding-top : 2px; ` +export const GoogleLoginButton = styled(Button)` + background-color : #fff; + box-shadow : 0 0 0 1px #4285f4 !important; + color : #666 !important; + font-weight : bolder !important; + + .MuiButton-root { + min-width : 88px !important; + font-size : 14px !important; + } + + .google-logo { + max-height : 24px !important; + padding-right : 5px; + + } + +` diff --git a/src/Components/MenuBar.js b/src/Components/MenuBar.js index 2fd70a29202153f7641cf05537932fea11174625..84b7eff6e39f07c4c773329f79bd5b91c48951a7 100644 --- a/src/Components/MenuBar.js +++ b/src/Components/MenuBar.js @@ -40,7 +40,7 @@ const ContainerStyled = styled(Container)` ` -const ButtonStyled = styled(Button)` +export const ButtonStyled = styled(Button)` text-transform: capitalize !important; margin : 0 8px !important; font-weight : normal !important; @@ -86,7 +86,7 @@ const Left = styled.span ` align-items: center; ` -const ButtonPubRecursoStyled = styled(Button)` +export const ButtonPubRecursoStyled = styled(Button)` font-weight : 500 !important; border : 1.5px #666 solid !important; color: #666; @@ -117,11 +117,10 @@ export default function MenuBar(props){ const minhaArea = [ { name: "Perfil e Atividades", href: "/perfil", value : '0'}, - { name: "Status e Conquistas", href: "/perfil", value: '1'}, - { name: "Recursos Publicados", href: "/perfil", value : '2'}, - { name: "Favoritos", href: "/perfil", value : '3'}, - { name: "Coleções", href: "/perfil", value : '4'}, - { name: "Rede", href: "/perfil", value : '5'}, + { name: "Recursos Publicados", href: "/perfil", value : '1'}, + { name: "Favoritos", href: "/perfil", value : '2'}, + { name: "Coleções", href: "/perfil", value : '3'}, + { name: "Rede", href: "/perfil", value : '4'}, { name: "Configurações", href: "/editarperfil"}, ] diff --git a/src/Components/MenuBarMobile.js b/src/Components/MenuBarMobile.js new file mode 100644 index 0000000000000000000000000000000000000000..ea3196dd0c45a6658adb77cc48c2358665beb616 --- /dev/null +++ b/src/Components/MenuBarMobile.js @@ -0,0 +1,100 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React from 'react' +import MenuIcon from '@material-ui/icons/Menu'; +import styled from 'styled-components' +import {Button} from '@material-ui/core' +import logo from '../img/logo_small.svg' +import {Link} from 'react-router-dom' +import Grid from '@material-ui/core/Grid'; +import MobileDrawerMenu from './MobileDrawerMenu'; + +export default function MenuBarMobile (props) { + + const [drawerOpen, setDrawerStatus] = React.useState(false); + + const toggleDrawer = (open) => (event) => { + if (event.type === 'keydown' && (event.key === 'Tab' || event.key === 'Shift')) { + return; + } + setDrawerStatus(open); + }; + + return ( + <OuterDiv> + <Grid container> + <Grid item xs={3} style={{display : "flex"}}> + <Button style={{color : "#00bcd4"}} onClick={toggleDrawer(true)}> + <MenuIcon className="icon"/> + </Button> + </Grid> + + <Grid item xs={9} justify={'center'}> + <div className="logo"> + <Link to="/"> + <img src={logo} alt={"Plataforma Integrada"}/> + </Link> + </div> + </Grid> + </Grid> + <MobileDrawerMenu anchor={'left'} open={drawerOpen} + onClose={toggleDrawer(false)} + openSignUp = {props.openSignUp} openLogin = {props.openLogin} + /> + </OuterDiv> + ) +} + +const OuterDiv = styled.div ` + height : 48px; + margin : 5px 2px; + display : flex; + flex-direction : column; + align-content : stretch; + justify-content : center; + + .logo { + height : 50px; + width : 150px; + padding : 5px; + padding-top : 15px; + text-align : center; + + img { + height : 38px; + overflow : hidden; + } + } + + .icon { + vertical-align : middle !important; + font-weight : normal !important; + font-style : normal !important; + font-size : 24px !important; + line-height : 1 !important; + letter-spacing : normal !important; + text-transform : none !important; + display : inline-block !important; + white-space : nowrap !important; + word-wrap : normal !important; + direction : ltr !important; + padding-right : 2px; + color : inherit !important; + } +` diff --git a/src/Components/MenuList.js b/src/Components/MenuList.js index 796b57b386e93056825e0ced50a2b1d8b4a4cae0..402fa2e747ff3f45f7357d675d64db260472f556 100644 --- a/src/Components/MenuList.js +++ b/src/Components/MenuList.js @@ -28,7 +28,9 @@ import { Store } from '../Store'; import { Redirect } from "react-router-dom"; import Profile from '../img/default_profile0.png' import styled from 'styled-components' -import {apiDomain} from '../env.js' +import {apiDomain, apiUrl} from '../env.js' +import {getAxiosConfig} from './HelperFunctions/getAxiosConfig' +import axios from 'axios' const iconStyles = { fontSize : "xxx-large", @@ -56,20 +58,29 @@ export default function MenuList(props) { }; const handleLogout = () => { - localStorage.removeItem('@portalmec/username'); - sessionStorage.removeItem('@portalmec/uid'); - sessionStorage.removeItem('@portalmec/senha'); - dispatch( { - type: 'USER_LOGGED_OUT', - userLoggedOut: !state.userIsLoggedIn, - login: { - username : '', - email : '', - accessToken : '', - client : '' + let config = getAxiosConfig() + axios.delete(`${apiUrl}/auth/sign_out`, config).then( + (res) => { + + localStorage.removeItem('@portalmec/username'); + sessionStorage.removeItem('@portalmec/uid'); + sessionStorage.removeItem('@portalmec/senha'); + dispatch( { + type: 'USER_LOGGED_OUT', + userLoggedOut: !state.userIsLoggedIn, + login: { + username : '', + email : '', + accessToken : '', + client : '' } - } + }) + }, + (err) => { + console.log(err) + } ) + } return ( diff --git a/src/Components/MobileDrawerMenu.js b/src/Components/MobileDrawerMenu.js new file mode 100644 index 0000000000000000000000000000000000000000..19201b3d77e7722d4a4f414394a25565b9c950f9 --- /dev/null +++ b/src/Components/MobileDrawerMenu.js @@ -0,0 +1,280 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, {useContext, useState} from 'react' +import { Store } from '../Store'; +import Drawer from '@material-ui/core/Drawer'; +import styled from 'styled-components' +import {Link} from 'react-router-dom' +import HomeIcon from '@material-ui/icons/Home'; +import InfoIcon from '@material-ui/icons/Info'; +import MailOutlineIcon from '@material-ui/icons/MailOutline'; +import HelpOutlineIcon from '@material-ui/icons/HelpOutline'; +import AssignmentIcon from '@material-ui/icons/Assignment'; +import {ButtonStyled} from './MenuBar' +import ExitToAppIcon from '@material-ui/icons/ExitToApp' +import { Button } from '@material-ui/core'; +import MenuItem from '@material-ui/core/MenuItem'; +import DefaultAvatar from '../img/default_profile0.png' +import CloudUploadIcon from '@material-ui/icons/CloudUpload'; +import CloudDoneIcon from '@material-ui/icons/CloudDone'; +import HistoryIcon from '@material-ui/icons/History'; +import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder'; +import FolderOpenIcon from '@material-ui/icons/FolderOpen'; +import SettingsIcon from '@material-ui/icons/Settings'; +import {apiDomain, apiUrl} from '../env.js' +import {getAxiosConfig} from './HelperFunctions/getAxiosConfig' +import axios from 'axios' + +export default function MobileDrawerMenu (props) { + const {state, dispatch} = useContext(Store) + + const menuSobre = [ + { name : "Página Inicial", href : "/", icon : <HomeIcon/>}, + { name : "Sobre a Plataforma", href : "sobre", icon : <InfoIcon/>}, + { name : "Contato", href : "contato", icon : <MailOutlineIcon/>}, + { name : "Central de Ajuda", href : "ajuda", icon : <HelpOutlineIcon/>}, + { name : "Termos de Uso", href : "termos", icon : <AssignmentIcon/>}, + ] + + {/*used in dynamic css selection*/} + const [selectedIndex, setSelectedIndex] = React.useState(-1); + const handleMenuItemClick = (event, index) => { + setSelectedIndex(index); + }; + + const getUserAvatar = () => { + if (state.currentUser.userAvatar == '' || state.currentUser.userAvatar == null) { + return DefaultAvatar + } + else { + return apiDomain + state.currentUser.userAvatar + } + } + + {/*main user actions array */} + const minhaArea = [ + { name: "Publicar Recurso", href: "/termos-publicar-recurso", icon : <CloudUploadIcon/>}, + { name: "Recursos Publicados", href: "/perfil", icon : <CloudDoneIcon/>, value : '1'}, + { name: "Perfil e Atividades", href: "/perfil", icon : <HistoryIcon/>, value : '0'}, + { name: "Favoritos", href: "/perfil", icon : <FavoriteBorderIcon/>, value : '2'}, + { name: "Coleções", href: "/perfil", icon : <FolderOpenIcon/>, value : '3'}, + ] + + {/*dispatches log out actions to Store.js*/} + const handleLogout = () => { + let config = getAxiosConfig() + axios.delete(`${apiUrl}/auth/sign_out`, config).then( + (res) => { + + localStorage.removeItem('@portalmec/username'); + sessionStorage.removeItem('@portalmec/uid'); + sessionStorage.removeItem('@portalmec/senha'); + dispatch( { + type: 'USER_LOGGED_OUT', + userLoggedOut: !state.userIsLoggedIn, + login: { + username : '', + email : '', + accessToken : '', + client : '' + } + }) + }, + (err) => { + console.log(err) + } + ) + } + + return ( + <StyledDrawer anchor={props.anchor} open={props.open} onClose={props.onClose}> + <MenuBody> + {/*Renders menuSobre array options*/} + { + menuSobre.map( (item, index) => + <Link to={item.href} className={`menu-buttons ${selectedIndex === index ? 'selected' : ''}`} onClick={(event) => handleMenuItemClick(event, index)}> + {item.icon} + {item.name} + </Link> + ) + } + </MenuBody> + + + <div style={{borderTop : "1px solid #e5e5e5", borderBottom : "1px solid #e5e5e5", marginTop : "10px", paddingTop : "10px", marginBottom : "10px"}}> + { + /*If user is logged in, render user actions menu; else render log in/sign in buttons*/ + state.userIsLoggedIn ? + ( + <div style={{display : "flex", flexDirection : "column", color : "#666", paddingBottom : "10px"}}> + <MyArea> + <div className="user-avatar"> + <img alt="user-avatar" + src={getUserAvatar()} + /> + </div> + <span className="text">Minha área</span> + </MyArea> + + { + minhaArea.map( (item, index) => + <Link to={{ + pathname : item.href, + state: item.value + }} + className={`menu-buttons ${selectedIndex === (index + menuSobre.length) ? 'selected' : ''}`} + onClick={(event) => handleMenuItemClick(event, index + menuSobre.length)} + > + {item.icon} + {item.name} + </Link> + ) + } + + </div> + ) + : + ( + <React.Fragment> + <div style={{display : "flex", justifyContent : "center", marginTop : "10px"}}> + <ButtonPublicarRecurso onClick={props.openLogin}> + PUBLICAR RECURSO? + </ButtonPublicarRecurso> + </div> + + <div style={{display : "flex", flexDirection : "row", margin : "10px 0", justifyContent : "center"}}> + <div style={{borderRight : "1px solid #e5e5e5"}}> + <ButtonStyled onClick={props.openLogin}> + <ExitToAppIcon style={{color:"#00bcd4"}}/>Entrar + </ButtonStyled> + </div> + + <div> + <ButtonStyled onClick={props.openSignUp}> + Cadastre-se + </ButtonStyled> + </div> + </div> + </React.Fragment> + ) + } + </div> + { + /*Renders settings and log off buttons */ + state.userIsLoggedIn && + <React.Fragment> + <Link to={"/editarperfil"} className={`menu-buttons`}> + <SettingsIcon/> Configurações + </Link> + + <Link to={"/"} className={`menu-buttons`} onClick={handleLogout}> + <ExitToAppIcon/> Sair + </Link> + </React.Fragment> + } + </StyledDrawer> + ) +} + +const MyArea = styled.div` + margin : 0 16px; + display : flex; + flex-direction : row; + + .text { + font-size : 16px; + color : #666; + align-self : center; + } + + .user-avatar { + margin-right : 10px; + align-self : center; + border-radius : 50%; + border : 1px solid #fff; + max-width : 50px; + max-height : 50px; + overflow : hidden; + + img { + width : 100%; + height : 100%; + vertical-align : middle; + } + } +` + +const ButtonPublicarRecurso = styled(Button)` + font-weight : 500 !important; + border : 1.5px #666 solid !important; + color: #666; + box-shadow: none; + margin : 0 8px !important; + padding : 6px 25px !important; + +` + +const StyledDrawer = styled(Drawer)` + .MuiPaper-root { + width : 65% !important; + } + + .menu-buttons { + padding : 10px 16px; + font-size : 14px; + font-weight : 500; + cursor : pointer; + outline : 0; + color : #666 !important; + text-decoration : none !important; + background-color : transparent; + font-family : 'Roboto', sans serif; + + .MuiSvgIcon-root { + color : #a5a5a5 !important; + margin-right : 20px; + vertical-align : middle !important; + font-weight : normal !important; + font-style : normal !important; + font-size : 24px !important; + line-height : 1 !important; + letter-spacing : normal !important; + text-transform : none !important; + display : inline-block !important; + white-space : nowrap !important; + word-wrap : normal !important; + direction : ltr !important; + } + } + + .selected { + color : #fff !important; + background-color : #00bcd4; + .MuiSvgIcon-root { + color : #fff !important; + } + } +` + +const MenuBody = styled.div` + margin-top : 20px; + display : flex; + flex-direction : column; + color : #666; +` diff --git a/src/Components/ModalEditarColecao.js b/src/Components/ModalEditarColecao.js new file mode 100644 index 0000000000000000000000000000000000000000..4353e8dd233dacfc78629ff003248f5a732d207c --- /dev/null +++ b/src/Components/ModalEditarColecao.js @@ -0,0 +1,125 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, {useState} from 'react' +import { Button } from '@material-ui/core'; +import Modal from '@material-ui/core/Modal'; +import Backdrop from '@material-ui/core/Backdrop'; +import Fade from '@material-ui/core/Fade'; +import styled from 'styled-components' +import CloseIcon from '@material-ui/icons/Close'; +import CloseModalButton from './CloseModalButton' +import EditarColecaoForm from './EditarColecaoForm.js' +export default function ModalEditarColecao (props) { + + return ( + <StyledModal + aria-labelledby="transition-modal-title" + aria-describedby="transition-modal-description" + open={props.open} + + centered="true" + onClose={props.handleClose} + closeAfterTransition + BackdropComponent={Backdrop} + BackdropProps={{ + timeout: 500, + }} + > + <Fade in={props.open}> + <Container> + <Header> + <span style={{width:"32px"}}/> + <h2>Editar Coleção</h2> + <CloseModalButton handleClose={props.handleClose} id={props.id}/> + </Header> + <Content style={{paddingTop : "0"}}> + <EditarColecaoForm id={props.id} handleClose={props.handleClose} finalize={props.handleClose}/> + </Content> + </Container> + </Fade> + </StyledModal> + ) +} + +const Content = styled.div` + padding : 20px 30px; + overflow-y: visible; + +` + +const Header = styled.div` + display : flex; + flex-direction : row; + padding : 10px 26px 0 26px; + align-items : center; + justify-content : space-between; + height : 64px; + + h2 { + font-size : 26px; + font-weight : lighter; + color : #666 + } +` + +const StyledCloseModalButton = styled(Button)` + display : inline-block; + position : relative; + float : right !important; + margin-right : -8px !important; + background : transparent !important; + min-width: 0 !important; + width : 40px; +` + +const StyledModal = styled(Modal)` + .djXaxP{ + margin : 0 !important; + } + display : flex; + align-items: center; + justify-content : center; + text-align : center; + padding : 10px !important; + max-width : none; + max-height : none; +` + +const Container = styled.div` + box-sizing : border-box; + box-shadow : 0 7px 8px -4px rgba(0,0,0,.2),0 13px 19px 2px rgba(0,0,0,.14),0 5px 24px 4px rgba(0,0,0,.12); + background-color : white; + align : center; + display : flex; + flex-direction : column; + min-width : 240px; + max-height : none; + position : relative; + padding : 10px; + border-radius : 4px; + + @media screen and (min-width : 96px) { + width : 500px; + } + + @media screen and (max-width : 699px) { + width : 100%; + height : 100%; + } +` diff --git a/src/Components/ModalExcluirComentario.js b/src/Components/ModalExcluirComentario.js index 88ceeceff8c5c798b2e1fe85872451a43178172e..4ce108a20896e848b2e01177694ad2a139efa843 100644 --- a/src/Components/ModalExcluirComentario.js +++ b/src/Components/ModalExcluirComentario.js @@ -69,7 +69,7 @@ export default function ModalExcluir (props) { aria-labelledby="transition-modal-title" aria-describedby="transition-modal-description" open={props.open} - + centered="true" onClose={props.handleClose} closeAfterTransition @@ -101,3 +101,4 @@ export default function ModalExcluir (props) { ) } + diff --git a/src/Components/Notifications.js b/src/Components/Notifications.js index 03f16486b99a2b9efdd96b6def38d08c97f507b4..87d20942268212fae9e5a745d4abd363567d3464 100644 --- a/src/Components/Notifications.js +++ b/src/Components/Notifications.js @@ -31,6 +31,9 @@ import {apiDomain, apiUrl} from '../env.js' import axios from 'axios' import ActivityListItem from './ActivityListItem.js' import {getAxiosConfig} from './HelperFunctions/getAxiosConfig.js' +import { withStyles } from '@material-ui/core/styles'; +import {Link} from 'react-router-dom' + const StyledBadge = styled(Badge) ` .MuiBadge-dot-45{ height : 9px ; @@ -55,14 +58,36 @@ const StyledNotificationButton = styled(Button)` } ` +const StyledMenu = withStyles({ + paper: { + border: '1px solid #d3d4d5', + }, +})((props) => ( + <Menu + elevation={0} + getContentAnchorEl={null} + anchorOrigin={{ + horizontal: 'center', + vertical: "bottom", + }} + transformOrigin={{ + vertical: 'top', + horizontal: 'center', + }} + {...props} + /> +)); + export default function Notification (props) { const [anchorEl, setAnchorEl] = React.useState(null); const [notifications, setNotifications] = useState([]); const [notificatonsLength, setLength] = useState(0); useEffect(() => { - let config = getAxiosConfig() - axios.get(`${apiUrl}/feed?offset=0&limit=30`, config) - .then( (response) => { + + setTimeout(() => { + let config = getAxiosConfig() + axios.get(`${apiUrl}/feed?offset=0&limit=30`, config) + .then( (response) => { if ( response.headers['access-token'] ) { sessionStorage.setItem('@portalmec/accessToken', response.headers['access-token']) } @@ -71,13 +96,15 @@ export default function Notification (props) { setNotifications(response.data) setLength(response.data.length) - }, - (error) => { - console.log('error while running getNotifications') - } - ) - }, []) + }, + (error) => { + console.log('error while running getNotifications') + } + ) + }, 1000); + }, [sessionStorage.getItem('@portalmec/uid')]) function handleClick(event) { + console.log('event.currentTarget: ', event.currentTarget) setAnchorEl(event.currentTarget); } @@ -118,6 +145,13 @@ export default function Notification (props) { /> ) } + <div style={{padding : "0 15px", borderTop : "1px solid #dadada"}}> + <Link to="/perfil"> + <NoPadButton> + MOSTRAR TODAS + </NoPadButton> + </Link> + </div> </ContainerDiv> </StyledMenu> </React.Fragment> @@ -125,8 +159,8 @@ export default function Notification (props) { } -const StyledMenu = styled(Menu)` - +const NoPadButton = styled(Button)` + padding : 6px 0 !important; ` const ContainerDiv = styled.div` @@ -134,15 +168,16 @@ const ContainerDiv = styled.div` right : 5%; width : 360px; max-height : 400px; - position : absolute; box-shadow : 8px 8px 8px 8px rgba(0,0,0,.1); overflow-y : scroll; padding : 5px 5px 5px 5px; min-width : 160px; + background-color : #f1f1f1; .cabecalho { - border-bottom : 1px solid #666; + border-bottom : 1px solid #dadada; + padding : 10px 15px; .cabecalho-marcar { font-family: Lato,bold; diff --git a/src/Components/PublicationPermissionsContent.js b/src/Components/PublicationPermissionsContent.js index fe3536dc8c3afb0eb810835cb5f5c56430660d21..bf115152247bea197475a22ddcc2da38681123c9 100644 --- a/src/Components/PublicationPermissionsContent.js +++ b/src/Components/PublicationPermissionsContent.js @@ -32,7 +32,6 @@ const BlueRadio = withStyles({ })((props) => <Radio color="default" {...props} />); export default function PublicationPermissionsContent (props) { - {/*To DO change to get https://api.portalmec.c3sl.ufpr.br/v1/questions*/} const [questionsArr, setQuestionsArr] = useState([]) const handleSetQuestionsArr = (newArr) => {setQuestionsArr(newArr)} @@ -86,7 +85,7 @@ export default function PublicationPermissionsContent (props) { </RadioGroup> </Grid> </React.Fragment> - + ) } </Grid> diff --git a/src/Components/ReportCollectionForm.js b/src/Components/ReportCollectionForm.js new file mode 100644 index 0000000000000000000000000000000000000000..0832b014c1a6bd9314eccbce7fd712918f33ed26 --- /dev/null +++ b/src/Components/ReportCollectionForm.js @@ -0,0 +1,104 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, {useContext} from 'react'; +import { Button } from '@material-ui/core'; +import styled from 'styled-components' +import Radio from '@material-ui/core/Radio'; +import RadioGroup from '@material-ui/core/RadioGroup'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import FormControl from '@material-ui/core/FormControl'; +import TextField from '@material-ui/core/TextField'; +import {StyledFormControl, StyledTextField, ButtonsDiv, ButtonCancelar, ButtonEnviar} from './ReportUserForm.js' + +export default function ReportRecursoForm (props) { + const [value, setValue] = React.useState(-1); + + const handleChange = (event) => { + setValue(event.target.value); + }; + + /*values are set according to backend complaint id*/ + const [options] = React.useState([ + {value : "1", text : 'A Coleção viola os direitos autorais.'}, + {value : "2", text : 'A Coleção contém conteúdo ofensivo/abusivo.'}, + {value : "5", text : 'A descrição da Coleção não corresponde ao seu conteúdo.'} + ]) + + const [moreInfo, setMoreInfo] = React.useState({ + key : false, + value : "", + }) + + const handleChangeMoreInfo = (e) => { + const userInput = e.target.value + + const flag = userInput.length > 150 ? true : false + + setMoreInfo({...moreInfo, + key : flag, + value : userInput + }) + } + + const handleSubmit = (e) => { + e.preventDefault() + const finalRadioValue = value + const finalMoreInfo = moreInfo + + if( finalRadioValue != -1 && !(finalMoreInfo.key)) { + props.handleSubmit(finalRadioValue, finalMoreInfo.value) + } + else { + console.log('oops') + } + } + + return ( + <form onSubmit={(e) => handleSubmit(e)} style={{textAlign : "left"}}> + <StyledFormControl component="fieldset"> + <RadioGroup value={value} onChange={handleChange}> + { + options.map(option => + <FormControlLabel value={option.value} control={<Radio color="orange"/>} label={option.text} /> + ) + } + </RadioGroup> + </StyledFormControl> + + <StyledTextField + id = {"report-text-field"} + label={"Escreva mais sobre o problema"} + value = {moreInfo.value} + onChange = {e => handleChangeMoreInfo(e)} + helperText = {moreInfo.value.length + '/150'} + multiline={true} + rowsMax = {"5"} + error = {moreInfo.key} + required = {false} + helperText ={moreInfo.value.length + '/150'} + style={{width : "100%"}} + /> + + <ButtonsDiv> + <ButtonCancelar onClick={props.handleClose}>CANCELAR</ButtonCancelar> + <ButtonEnviar type="submit">ENVIAR</ButtonEnviar> + </ButtonsDiv> + </form> + ) +} + diff --git a/src/Components/ReportModal.js b/src/Components/ReportModal.js index ed472b3890cda0cbc7bd02e7aa6b1f44714e0131..540e1de9ae151b92d520e7b8d9105054c069d00b 100644 --- a/src/Components/ReportModal.js +++ b/src/Components/ReportModal.js @@ -30,6 +30,7 @@ import CloseIcon from '@material-ui/icons/Close'; import ReportUserForm from './ReportUserForm.js' import ReportRecursoForm from './ReportRecursoForm.js' import ReportColecaoForm from './ReportColecaoForm.js' +import ReportCollectionForm from './ReportCollectionForm.js'; function CloseModalButton (props) { return ( @@ -87,6 +88,19 @@ export default function ReportModal (props) { } } + const renderForm = (formType) => { + switch (formType) { + case 'colecao': + return ( + <ReportCollectionForm + handleClose={props.handleClose} + handleSubmit={handleSubmit} + /> + ); + break; + } + } + return ( <StyledModal aria-labelledby="transition-modal-title" @@ -183,3 +197,4 @@ const ReportContainer = styled.div` height : 100%; } ` + diff --git a/src/Components/ReportUserForm.js~fead909286087ce07b01b25f6d8f46f74dc494c8 b/src/Components/ReportUserForm.js~fead909286087ce07b01b25f6d8f46f74dc494c8 new file mode 100644 index 0000000000000000000000000000000000000000..1a906691d3b9ea6caca05448c9b5a2365178d352 --- /dev/null +++ b/src/Components/ReportUserForm.js~fead909286087ce07b01b25f6d8f46f74dc494c8 @@ -0,0 +1,179 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, {useState, useContext} from 'react'; +import { Button } from '@material-ui/core'; +import styled from 'styled-components' +import Radio from '@material-ui/core/Radio'; +import RadioGroup from '@material-ui/core/RadioGroup'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; +import FormControl from '@material-ui/core/FormControl'; +import TextField from '@material-ui/core/TextField'; + +export default function ReportForm (props) { + const [value, setValue] = React.useState(-1); + + const handleChange = (event) => { + setValue(event.target.value); + }; + + /*values are set according to backend complaint id*/ + const [options] = React.useState([ + {value : "6", text :'Esta pessoa está fingindo ser eu ou alguém que eu conheço.'}, + {value : "4", text : 'Essa pessoa envia spam.'}, + {value : "3", text : 'Essa é uma conta falsa.'}, + {value : "1", text : ' A publicação dessa pessoa viola os diretos autorais.'}, + {value : "2", text : 'As publicações dessa pessoa contém conteúdo ofensivo/abusivo.'} + ]) + + const [moreInfo, setMoreInfo] = React.useState({ + key : false, + value : "", + }) + + const handleChangeMoreInfo = (e) => { + const userInput = e.target.value + + const flag = userInput.length > 150 ? true : false + + setMoreInfo({...moreInfo, + key : flag, + value : userInput + }) + } + + const formSubmit = (e) => { + e.preventDefault() + const finalRadioValue = value + const finalMoreInfo = moreInfo + + if( finalRadioValue != -1 && !(finalMoreInfo.key)) { + props.handleSubmit(finalRadioValue, finalMoreInfo.value) + } + } + + return ( + <form onSubmit={(e) => {formSubmit(e)}}> + <StyledFormControl component="fieldset"> + <RadioGroup value={value} onChange={handleChange}> + { + options.map(option => + <FormControlLabel value={option.value} control={<Radio color="orange"/>} label={option.text} /> + ) + } + </RadioGroup> + </StyledFormControl> + + <StyledTextField + id = {"Escreva mais sobre o problema"} + label={"Escreva mais sobre o problema"} + type = {"text"} + value = {moreInfo.value} + onChange = {e => handleChangeMoreInfo(e)} + helperText = {moreInfo.value.length + '/150'} + multiline={true} + rowsMax = {"5"} + error = {moreInfo.key} + required = {false} + style={{width:"100%"}} + /> + + <ButtonsDiv> + <ButtonCancelar onClick={props.handleClose}>CANCELAR</ButtonCancelar> + <ButtonEnviar type="submit">ENVIAR</ButtonEnviar> + </ButtonsDiv> + </form> + ); +} + +export const ButtonsDiv = styled.div` + display : flex; + flex-direction : row; + justify-content : flex-end; + align-items : center; +` + +export const ButtonCancelar = styled(Button)` + &:hover { + background-color : rgba(158,158,158,0.2) !important; + } + height : 36px !important; + padding-left : 16px !important; + padding-right : 16px !important; + font-weight : 500 !important; + border-radius : 3px !important; + color :#666 !important; + background-color: transparent; + min-width : 88px !important; + height : 36px !important; +` + +export const ButtonEnviar = styled(Button)` + background-color : #ff7f00 !important; + color : #fff !important; + font-size: 14px !important; + font-weight: 500 !important; + height: 36px !important; + border-radius: 3px !important; + padding-left: 16px !important; + padding-right: 16px !important; + box-shadow: 0 2px 5px 0 rgba(0,0,0,.26) !important; + outline : none !important; + min-width : 88px !important; + vertical-align : middle !important; + margin : 6px 8px !important; + text-decoration : none !important; + + .MuiButton-label { + padding-right : 16px; + padding-left : 16px; + } +` +export const StyledTextField = styled(TextField)` + .MuiFormHelperText-root { + text-align : right; + } + + label.Mui-focused { + color : orange; + } + + label.Mui-focused.Mui-error { + color : red; + } + + .MuiInput-underline::after { + border-bottom: 2px solid orange; + } +` + +export const StyledFormControl = styled(FormControl)` + .MuiFormControlLabel-root { + color : #666; + } + .MuiIconButton-label { + color : #666; + } + .PrivateRadioButtonIcon-checked { + color : orange; + } + + .MuiTypography-body1 { + font-size : 14px; + } +` + diff --git a/src/Components/ResourceList.js b/src/Components/ResourceList.js new file mode 100644 index 0000000000000000000000000000000000000000..08a13d469c617179ce26f739450741ccc9358eb4 --- /dev/null +++ b/src/Components/ResourceList.js @@ -0,0 +1,184 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, { useState, useEffect } from 'react'; +import { Grid } from '@material-ui/core'; +import styled from 'styled-components'; +import axios from 'axios'; +import Button from '@material-ui/core/Button'; +import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank'; +import CheckBoxIcon from '@material-ui/icons/CheckBox'; +import GetAppIcon from '@material-ui/icons/GetApp'; +import ResourceCardFunction from './ResourceCardFunction.js'; +import FloatingDownloadButton from './FloatingDownloadButton.js'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; +import { apiUrl } from '../env.js'; + +function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; +} + + +export default function ResourceList(props) { + const [selected, setSelected] = useState(Array.apply( + null, {length: props.resources.length}).map(i => false)); + const [selectable, setSelectable] = useState(false); + const [download_url, setDownloadUrl] = useState(''); + const [snackbar_open, setSnackbarOpen] = useState(false); + + const updateSelected = (index) => { + let new_selected = selected.slice(); + new_selected[index] = !new_selected[index]; + setSelected(new_selected); + } + + const checkBoxIcon = (s) => { + if (s) + return <CheckBoxIcon />; + else + return <CheckBoxOutlineBlankIcon />; + } + + const handleDownloadSelection = () => { + const selected_resources = props.resources.filter(resource => selected[props.resources.indexOf(resource)]); + setSnackbarOpen(true); + } + + useEffect(() => { + if (selectable) { + var resources = [] + let i = 0; + while (i < props.resources.length) { + if (selected[i]) + resources.push({"type": "LearningObject", "id": props.resources[i].id}); + i++; + } + const body = { + "package": { + "object": resources + }}; + if (resources.length) + axios + .post(apiUrl+'/package', body) + .catch(err => { + if (err.response && err.response.status === 302) { + setDownloadUrl(apiUrl.slice().replace('/v1', '')+'/'+err.response.data.url); + } + }); + } + }, [selected, selectable]); + + return ( + <ResourceListContainer> + <Grid container direction="row" justify="space-around" alignItems="center"> + <Grid item> + <Title> + {props.resources.length ? + props.resources.length+" recurso"+(props.resources.length == 1 ? "" : "s") + : "Carregando coleção"} + </Title> + </Grid> + <Grid item> + <Button color="primary" onClick={() => setSelectable(!selectable)}> + <PanelButtonText> + {selectable ? "Desativar" : "Ativar"} seleção + </PanelButtonText> + </Button> + </Grid> + <Grid item> + <UnstyledAnchor href={download_url}> + <Button + color="primary" + variant="outlined" + startIcon={<GetAppIcon fontSize="large"/>} + onClick={handleDownloadSelection} + > + <PanelButtonText>baixar seleção</PanelButtonText> + </Button> + </UnstyledAnchor> + </Grid> + </Grid> + <Grid container direction="row" justify="flex-start" alignItems="center"> + {props.resources.map((r) => { + return ( + <ResourceGrid item key={r.title}> + <ResourceCardFunction + type={r.type} + author={r.author} + tags={r.tags} + published={r.published} + title={r.title} + rating={r.rating} + likeCount={r.likeCount} + liked={r.liked} + thumbnail={r.thumbnail} + /> + {selectable ? + (<SelectButton + variant="outline" + color="primary" + startIcon={checkBoxIcon(selected[props.resources.indexOf(r)])} + onClick={() => updateSelected(props.resources.indexOf(r))} + > + Selecionar + </SelectButton>) + : + <span></span>} + + </ResourceGrid> + ); + })} + </Grid> + <Snackbar + open={snackbar_open} + autoHideDuration={6000} + onClose={() => setSnackbarOpen(false)} + anchorOrigin={{vertical: 'top', horizontal: 'right'}} + > + <Alert onClose={() => setSnackbarOpen(false)} severity="info"> + Os recursos serão baixados + </Alert> + </Snackbar> + <FloatingDownloadButton url={download_url} empty={selected.indexOf(true) == -1}/> + </ResourceListContainer> + ); +} + +const ResourceListContainer=styled.div` + margin-left: 20; + margin-right: 20; +` +const Title=styled.p` + color: rgb(102, 102, 102); + font-size: 2em; + font-weigth: 300; +` +const SelectButton=styled(Button)` + width: 100%; +` +const PanelButtonText=styled.span` + font-weight: 900; +` +const ResourceGrid=styled(Grid)` + padding-right: 7px; +` +const UnstyledAnchor=styled.a` + text-decoration: none !important; +` diff --git a/src/Components/ResourcePageComponents/CommentForm.js b/src/Components/ResourcePageComponents/CommentForm.js index efbf0a0349ad1184ac616bd738faffa5abfba7a0..0b13b1479b9329bf1f31228575d829fb60f27f2a 100644 --- a/src/Components/ResourcePageComponents/CommentForm.js +++ b/src/Components/ResourcePageComponents/CommentForm.js @@ -72,8 +72,6 @@ export default function CommentForm (props) { } } - let windowWidth = window.innerWidth - return ( <StyledForm onSubmit={handleSubmit}> <label htmlFor="avaliacao-estrelas" className="start-label"> @@ -93,77 +91,35 @@ export default function CommentForm (props) { <div className="star-alert" style={attemptedSubmit ? {visibility : "visible"} : {visibility : "hidden" }}>{props.recurso ? "Avalie se o recurso foi útil." : "Avalie se esta coleção foi útil."}</div> <Grid container> - { - windowWidth > 990 ? - ( - <> - <Grid item xs={10}> - <StyledTextField - colecao={!props.recurso} - value={comment.value} - multiline - rows="5" - error={comment.error} - label={props.recurso ? "Escreva aqui a sua experiência com este Recurso" : "Escreva aqui a sua experiência com esta Coleção"} - onChange={e => handleChange(e)} - required={true} - help = {comment.error ? (props.recurso ? "Escreva aqui a sua experiência com este Recurso" : "Escreva aqui a sua experiência com esta Coleção") : ''} - /> - </Grid> - <Grid item xs={2}> - <div style={{height : "100%", display : "flex", flexDirection : "column", justifyContent : "flex-end"}}> - { - props.recurso ? - ( - <OrangeButton type="submit">Publicar</OrangeButton> - ) - : - ( - <PurpleButton type="submit"><EditIcon/>Enviar</PurpleButton> - ) - } - </div> - </Grid> + <Grid item xs={10}> + <StyledTextField + colecao={!props.recurso} + value={comment.value} + multiline + rows="5" + error={comment.error} + label={props.recurso ? "Escreva aqui a sua experiência com este Recurso" : "Escreva aqui a sua experiência com esta Coleção"} + onChange={e => handleChange(e)} + required={true} + help = {comment.error ? (props.recurso ? "Escreva aqui a sua experiência com este Recurso" : "Escreva aqui a sua experiência com esta Coleção") : ''} + /> + </Grid> + <Grid item xs={2}> + <div style={{height : "100%", display : "flex", flexDirection : "column", justifyContent : "flex-end"}}> + { + props.recurso ? + ( + <OrangeButton type="submit">Publicar</OrangeButton> + ) + : + ( + <PurpleButton type="submit"><EditIcon/>Enviar</PurpleButton> + ) + } + </div> + </Grid> - <div className="campos-obrigatorios">* Campos obrigatórios.</div> - </> - ) - : - ( - <> - <Grid item xs={12}> - <StyledTextField - colecao={!props.recurso} - value={comment.value} - multiline - rows="5" - error={comment.error} - label={props.recurso ? "Escreva aqui a sua experiência com este Recurso" : "Escreva aqui a sua experiência com esta Coleção"} - onChange={e => handleChange(e)} - required={true} - help = {comment.error ? (props.recurso ? "Escreva aqui a sua experiência com este Recurso" : "Escreva aqui a sua experiência com esta Coleção") : ''} - /> - </Grid> - <Grid item xs={12}> - <div style={{paddingTop : "18px", display : "flex", justifyContent : "space-between"}}> - <div className="campos-obrigatorios">* Campos obrigatórios.</div> - <div style={{width : "40%"}}> - { - props.recurso ? - ( - <OrangeButton type="submit">Publicar</OrangeButton> - ) - : - ( - <PurpleButton type="submit"><EditIcon/>Enviar</PurpleButton> - ) - } - </div> - </div> - </Grid> - </> - ) - } + <div className="campos-obrigatorios">* Campos obrigatórios.</div> </Grid > </StyledForm> ) @@ -221,9 +177,6 @@ const StyledForm = styled.form` display : flex; flex-direction : column; text-align : start; - @media screen and (max-width : 990px) { - padding-left : 15px; - } .start-label { font-size : 14px; diff --git a/src/Components/ResourcePageComponents/CommentsArea.js b/src/Components/ResourcePageComponents/CommentsArea.js index 924a690434497aa0f7e133ff4ddec765310d5566..3bdf29714925ba86ff04ad681315243505c846ed 100644 --- a/src/Components/ResourcePageComponents/CommentsArea.js +++ b/src/Components/ResourcePageComponents/CommentsArea.js @@ -183,12 +183,18 @@ const GrayContainer = styled.div` display : flex; flex-direction : column; justify-content : space-between; +<<<<<<< HEAD font-size : 14px; padding-bottom : 20px; @media screen and (min-width : 990px) { padding-right : 15px; padding-left : 15px; } +======= + padding-right : 15px; + padding-left : 15px; + padding-bottom : 20px; +>>>>>>> fead909286087ce07b01b25f6d8f46f74dc494c8 h3 { font-family : 'Roboto Light','Roboto Regular',Roboto; diff --git a/src/Components/ShareModal.js b/src/Components/ShareModal.js index 1f3b771286cd3f95c331295e9691277914e11842..fd9e6441c4bf4b0ecc52d8d9f3eb3e38b72b92c0 100644 --- a/src/Components/ShareModal.js +++ b/src/Components/ShareModal.js @@ -33,11 +33,14 @@ import LinkIcon from '../img/link_icon.svg' import CloseModalButton from './CloseModalButton.js' export default function ReportModal (props) { - const refContainer = useRef(props.link); - - function copyToClipboard(e) { - let copyText = document.getElementById('p-text') - console.log(copyText) + const textAreaRef = useRef(props.link); + + const copyToClipboard = (e) => { + textAreaRef.current.select(); + document.execCommand('copy'); + // This is just personal preference. + // I prefer to not show the whole text area selected. + e.target.focus(); }; return ( @@ -97,10 +100,14 @@ export default function ReportModal (props) { {/*Get shareable link*/} <Grid item xs={4}> + { + document.queryCommandSupported('copy') && <ShareButton onClick={copyToClipboard}> <img src={LinkIcon} alt="link-icon"/> - <p id="p-text" value={props.link}>COPIAR LINK</p> + <p>COPIAR LINK</p> + <textarea ref={textAreaRef} value={props.link} readOnly style={{height: "0", position: "absolute",zIndex: "-1"}}/> </ShareButton> + } </Grid> </Grid> </ShareInfo> diff --git a/src/Components/SignUpContainer.js b/src/Components/SignUpContainer.js deleted file mode 100644 index 9d01f58daf46303a7b3967d3eb8adc5d2e7e9ec0..0000000000000000000000000000000000000000 --- a/src/Components/SignUpContainer.js +++ /dev/null @@ -1,326 +0,0 @@ -/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre -Departamento de Informatica - Universidade Federal do Parana - -This file is part of Plataforma Integrada MEC. - -Plataforma Integrada MEC is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Plataforma Integrada MEC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ - -import React, {Component} from "react"; -import GoogleLogin from 'react-google-login' -import { Button } from '@material-ui/core'; -//import FacebookLogin from 'react-facebook-login'; -import CloseIcon from '@material-ui/icons/Close'; -import styled from 'styled-components' -import {device} from './device.js' -import FormInput from "./FormInput.js" -import {StyledCloseModalButton, DialogContentDiv, DialogHeaderStyled, SocialConnectDiv, StyledGoogleLoginButton, H3Div} from './LoginContainer.js' -const responseGoogle = (response) => { - console.log(response); -} - -const responseFacebook = (response) => { - console.log(response); -} - -var Recaptcha = require('react-recaptcha') - -//alterar funcao do callback -var callback = function () { - console.log('Done!!!!'); -}; - -function validateUserInfo (name, email, password) { - const errors = [] - - if(name.lenght === 0 ) { - errors.push({name : "name", msg : "Faltou preencher seu nome completo."}) - } - if(email.length === 0) { - errors.push({name : "email", msg : "Faltou preencher seu e-mail."}) - } - else if ( (email.split("").filter(x => x === "@").length !== 1) || (email.indexOf(".") === -1) ){ - errors.push({name : "email", msg : "Insira um endereço de email válido."}) - errors.push({name : "email", msg : "Por exemplo: seunome@gmail.com, seunome@hotmail.com"}) - } - if(password.length === 0) { - errors.push({ name : "password", msg : "Faltou definir uma senha."}) - } - - return errors -} - -class SignUpContainer extends Component { - constructor (props) { - super(props); - - this.state = { - name: "", - email: "", - password: "", - - errors : [] - }; - }; - - switchModal = (e) => { - e.preventDefault() - this.props.handleClose() - this.props.openLogin() - }; - - handleChange = e => { - this.setState({[e.target.name]: e.target.value}) - - }; - - onSubmit = (e) => { - //on submit we should prevent the page from refreshing - e.preventDefault(); //though this is arguable - const { name, email, password } = this.state; - const errors = validateUserInfo(name, email, password) - console.log(this.state) - if ( errors.length < 1) { - //pass user info to Store.js and clear all text fields - this.props.handleLoginInfo(this.state) - this.setState({ - name: "", - email: "", - password: "" - }) - } - else { - this.setState({errors}) - } - - } - - render () { - const { errors } = this.state; - return ( - <ContainerStyled > - <DialogHeaderStyled> - <span style={{width:"32px"}}/> - <H2Styled> Cadastrar-se - </H2Styled> - <StyledCloseModalButton onClick={this.props.handleClose} > - <CloseIcon /> - </StyledCloseModalButton> - </DialogHeaderStyled> - - <DialogContentDiv> - <SocialConnectDiv> - <StyledGoogleLoginButton - clientId="658977310896-knrl3gka66fldh83dao2rhgbblmd4un9.apps.googleusercontent.com" - onSuccess={responseGoogle} - onFailure={responseGoogle} - cookiePolicy={'single_host_origin'} - > - <span style={{textTransform:"none", fontSize:"13px"}}>Usando o Google</span> - </StyledGoogleLoginButton> - </SocialConnectDiv> - - <H3Div> - <H3Styled> - <RightSideStrikedH3/> - <span style={{verticalAlign:"middle"}}>ou</span> - <LeftSideStrikedH3/> - </H3Styled> - </H3Div> - - <form ref="form" onSubmit={this.onSubmit}> - {errors.map(error => ( - <p key={error.name}>Error: {error.msg}</p> - ))} - <FormInput - inputType={"text"} - name={"name"} - value={this.state.name} - placeholder={"Nome Completo"} - handleChange={e => this.handleChange(e)} - required={true} - /> - <br/> - <FormInput - inputType={"text"} - name={"email"} - value={this.state.email} - placeholder={"E-mail"} - handleChange={e => this.handleChange(e)} - required={true} - /> - <br/> - <FormInput - inputType={"password"} - name={"password"} - value={this.state.password} - placeholder={"Senha"} - handleChange={e => this.handleChange(e)} - required={true} - /> - <br/> - <Recaptcha - sitekey="6LcyFr8UAAAAAOd0Po6rmZC1D_nYik8nLCAkNKsc" - size="normal" - render="explicit" - onloadCallback={callback} - /> - <ConfirmContainerStyled> - <StyledSignUpButton type="submit" variant="contained"> - <span - style={{paddingLeft:"16px", paddingRight:"16px", borderRadius:"3px", boxSizing:"border-box", - fontFamily:"Roboto, sans serif", fontWeight:"500", color:"#fff"}} - > - CADASTRAR - </span> - </StyledSignUpButton> - </ConfirmContainerStyled> - </form> - - <TermosDeUsoStyled> - <p>Ao se cadastrar, você está aceitando os Termos de Uso e de PolÃtica - de Privacidade. <a href="./">Ler Termos</a>.</p> - </TermosDeUsoStyled> - - <DialogFooterStyled> - <span style={{textAlign:"center", fontSize: "14px"}}>Já possui cadastro? <StyledAnchor href="" onClick={e => this.switchModal(e)}>ENTRAR</StyledAnchor></span> - </DialogFooterStyled> - </DialogContentDiv> - </ContainerStyled> - ) - } -} - -export default SignUpContainer - -const ContainerStyled = styled.div` - box-sizing : border-box; - background-color : white; - max-width : none; - align : center; - display : flex; - flex-direction : column; - min-width : 450px; - - max-height : none; - position : relative; - padding : 10px; - @media ${device.mobileM} { - width : 100%; - height : 100%; - } -` - -const DialogFooterStyled = styled.div` - box-sizing : border-box; - font-family : 'Roboto', sans serif; - margin : 20px -20px; - padding-top : 20px; - border-top : 1px #e5e5e5 solid; - justify-content : center; - text-align : center; - line-height : 1.42857143 -` - -const TermosDeUsoStyled = styled.div` - font-family: 'Roboto', sans serif, 'Helvetica Neue', Helvetica, Arial, sans-serif; - color : #666; - font-size : 13px; - margin : 0 0 10px; - max-width : 350px; - margin-top : 10px; - text-align : start; -` - -const H2Styled = styled.h2` - align-self : center; - color : #666; - font-size : 26px; - font-weight : lighter; - justify-content: space-between; - font-family: 'Roboto', sans serif, 'Helvetica Neue', Helvetica, Arial, sans-serif !important; - text-align: center; - letter-spacing: .005em; -` - -const H3Styled = styled.h3` - overflow : hidden; - text-align : center; - font-size : 14px; - color : #666; - margin : 10px 0; -` -const RightSideStrikedH3 = styled.div` - display : inline-block; - border-bottom: 1px dotted #666; - vertical-align : middle; - font-weight : 500; - margin-right : 5px; - width : 45%; -` - -const LeftSideStrikedH3 = styled.div` - display : inline-block; - border-bottom: 1px dotted #666; - vertical-align : middle; - font-weight : 500; - margin-left : 5px; - width : 45%; -` - -const StyledAnchor = styled.a` - color : #00bcd4; - text-decoration : none; -` -//const StyledCloseModalButton = styled(Button)` -// display : inline-block; -// position : relative; -// float : right !important; -// margin-right : -8px; -// background : transparent; -// min-width: 0 !important; -// width : 40px; -//` - -const ConfirmContainerStyled = styled.div` - display : flex; - margin-top : 10px; - align-items : center; - justify-content : center; - box-sizing : border-box; - font-size : 13px; -` - -const StyledSignUpButton = styled(Button)` - background-color: #00bcd4 !important; - box-shadow : none !important; - outline: none !important; - border : 0 !important; - overflow : hidden !important; - width : 50% !important; - display : inline-block !important; - font-family : 'Roboto', sans serif !important; - font-size: 14px !important; - height : 36px !important; - align-items : center !important; - border-radius: 3px !important; - align-self : 50% !important; - :hover { - background-color : #00acc1 !important; - } -` - -const StyledRecaptcha = styled(Recaptcha)` - display : flex !important; - justify-content : center !important; -` diff --git a/src/Components/SignUpContainerFunction.js b/src/Components/SignUpContainerFunction.js index 965e21f62ec1338acda820e3d29a9c82289db267..7f49992a254ab10e2e4d38d295a8e390925525e5 100644 --- a/src/Components/SignUpContainerFunction.js +++ b/src/Components/SignUpContainerFunction.js @@ -24,15 +24,21 @@ import CloseIcon from '@material-ui/icons/Close'; import styled from 'styled-components' import {device} from './device.js' import FormInput from "./FormInput.js" -import {StyledCloseModalButton, DialogContentDiv, DialogHeaderStyled, SocialConnectDiv, H3Div} from './LoginContainer.js' +import {StyledCloseModalButton, DialogContentDiv, DialogHeaderStyled, SocialConnectDiv, StyledGoogleLoginButton, H3Div} from './LoginContainerFunction.js' +import {apiUrl} from '../env.js' +import {GoogleLoginButton} from './LoginContainerFunction' import ValidateUserInput from '../Components/FormValidationFunction.js' +import GoogleLogo from "../img/logo_google.svg" var Recaptcha = require('react-recaptcha') -var callback = function () { - console.log('Done!!!!'); -}; - +async function handleGoogleAttempt () { + console.log("handleGoogleAttempt") + let request_url = ( + `${apiUrl}/omniauth/google_oauth2?auth_origin_url=` + window.location.href + '&omniauth_window_type=sameWindow&resource_class=User' + ) + window.location.replace(request_url) +} export default function SignUpContainer (props) { const [formNome, setNome] = useState( { @@ -132,8 +138,10 @@ export default function SignUpContainer (props) { <DialogContentDiv> <SocialConnectDiv> - <Button onClick={() => {console.log('handleGoogleAttempt')}}>cadastro com google</Button> - + <GoogleLoginButton onClick={handleGoogleAttempt}> + <img src={GoogleLogo} alt="google-logo" className="google-logo"/> + <span>Usando o Google</span> + </GoogleLoginButton> </SocialConnectDiv> <H3Div> @@ -177,12 +185,6 @@ export default function SignUpContainer (props) { help = {formSenha.key ? (formSenha.value.length == 0 ? "Faltou digitar sua senha." : "A senha precisa ter no mÃnimo 8 caracteres.") : ""} /> <br/> - <Recaptcha - sitekey="6LcyFr8UAAAAAOd0Po6rmZC1D_nYik8nLCAkNKsc" - size="normal" - render="explicit" - onloadCallback={callback} - /> <ConfirmContainerStyled> <StyledSignUpButton type="submit" variant="contained"> <span @@ -224,6 +226,8 @@ const ContainerStyled = styled.div` width : 100%; min-width : unset; height : 100%; + min-width : unset !important; + } ` @@ -272,7 +276,7 @@ const RightSideStrikedH3 = styled.div` vertical-align : middle; font-weight : 500; margin-right : 5px; - width : 45%; + width : 44%; ` const LeftSideStrikedH3 = styled.div` @@ -281,7 +285,7 @@ const LeftSideStrikedH3 = styled.div` vertical-align : middle; font-weight : 500; margin-left : 5px; - width : 45%; + width : 44%; ` const StyledAnchor = styled.a` diff --git a/src/Components/TabPanels/UserPageTabs/ModalExcluirConta.js b/src/Components/TabPanels/UserPageTabs/ModalExcluirConta.js new file mode 100644 index 0000000000000000000000000000000000000000..43ff66284eca688e2582703fa8c988bcb6798027 --- /dev/null +++ b/src/Components/TabPanels/UserPageTabs/ModalExcluirConta.js @@ -0,0 +1,219 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React, {useContext, useState} from 'react'; +import {Store} from '../../../Store.js' +import { Button } from '@material-ui/core'; +import Modal from '@material-ui/core/Modal'; +import Backdrop from '@material-ui/core/Backdrop'; +import Fade from '@material-ui/core/Fade'; +import styled from 'styled-components' +import axios from 'axios' +import {apiUrl} from '../../../env.js' +import CloseIcon from '@material-ui/icons/Close'; +import ExcluirAvatar from '../../../img/Excluir.png' +import GreyButton from '../../GreyButton' +import FormInput from '../../FormInput' +import {Link} from 'react-router-dom' +import SnackbarComponent from '../../SnackbarComponent.js' +import {getAxiosConfig} from '../../HelperFunctions/getAxiosConfig' + +function CloseModalButton (props) { + return ( + <StyledCloseModalButton onClick={props.handleClose}> + <CloseIcon/> + </StyledCloseModalButton> + ) +} + +export default function ModalExcluirConta (props) { + const {state, dispatch} = useContext(Store) + + const [formEmail, setEmail] = useState( + { + key : false, + value : "", + } + ) + const handleChange = (e) => { + const userInput = e.target.value + let flag = !(userInput === state.currentUser.email) + + setEmail({...formEmail, + key : flag, + value : userInput + }) + } + + const [snackbarOpen, toggleSnackbar] = useState(false) + + const deletedAccountText = `A conta ${state.currentUser.email} foi deletada com sucesso` + + const deleteAccount = () => { + let config = getAxiosConfig() + + axios.delete( (`${apiUrl}/auth/`), config + ).then( (response) => { + console.log(response) + toggleSnackbar(true) + + dispatch({ + type: "USER_DELETED_ACCOUNT", + }); + + props.handleClose() + }, (error) => {console.log(error);}) + } + + return ( + <React.Fragment> + <SnackbarComponent snackbarOpen={snackbarOpen} severity={"info"} handleClose={() => {toggleSnackbar(false)}} text={deletedAccountText}/> + <StyledModal + aria-labelledby="transition-modal-title" + aria-describedby="transition-modal-description" + open={props.open} + centered="true" + onClose={props.handleClose} + closeAfterTransition + BackdropComponent={Backdrop} + BackdropProps={{ + timeout: 500, + }} + > + <Fade in={props.open}> + <Container> + <Header> + <span style={{width:"32px"}}/> + <h2>Excluir a Conta Definitivamente</h2> + <CloseModalButton handleClose={props.handleClose}/> + </Header> + <Content> + <div style={{display : "flex", flexDirection : "column", color : "#666", textAlign : "left"}}> + <div style={{display : "flex", flexDirection : "row", margin : "0 30px", justifyContent : "center", alignContent : "center"}}> + <div style={{height : "90px", position : "relative"}}> + <img src={ExcluirAvatar} alt="excluir-avatar" style={{height : "inherit", objectFit : "contain", verticalAlign : "middle"}}/> + </div> + <p style={{paddingLeft : "10px"}}>Você é muito importante para a rede, ficarÃamos felizes se você ficasse. Quer contar o que aconteceu? Talvez possamos ajudar. <StyledLink to="/contato">Entre em contato.</StyledLink></p> + </div> + <p style={{marginTop : "20px"}}> + Saiba que a exclusão da conta removerá o seu perfil permanentemente. Se você publicou algum recurso, ele ainda ficará disponÃvel para os usuários da plataforma. + </p> + <p style={{marginTop : "20px"}}> + É necessário que você digite seu e-mail para confirmar a exclusão: + </p> + <FormInput + inputType={"text"} + name={"email"} + value={formEmail.value} + placeholder={"Digite seu e-mail de cadastro"} + handleChange={e => handleChange(e)} + required={true} + error = {formEmail.key} + help = {formEmail.key ? ( formEmail.value.length == 0 ? "Faltou preencher seu e-mail." : "O e-mail deve ser o mesmo no qual você cadastrou esta conta") : ""} + /> + <div style={{display : "flex", flexDirection : "row", justifyContent : "space-evenly", paddingTop : "15px"}}> + <GreyButton callback={props.handleClose} text={"Cancelar"}/> + <RedButton disabled={formEmail.key} onClick = {() => {deleteAccount()}}>EXCLUIR PERMANENTEMENTE</RedButton> + </div> + </div> + </Content> + </Container> + </Fade> + </StyledModal> + </React.Fragment> + ) +} + +const RedButton = styled(Button)` + background-color : rgb(230,60,60) !important; + color : #fff !important; + font-weight : bolder; + box-shadow : 0 2px 5px 0 rgba(0,0,0,.26) !important; +` + +const Content = styled.div` + padding : 20px 30px; + +` + +const Header = styled.div` + display : flex; + flex-direction : row; + padding : 10px 26px 0 26px; + align-items : center; + justify-content : space-between; + height : 64px; + + h2 { + font-size : 26px; + font-weight : lighter; + color : #666 + } +` + +const StyledCloseModalButton = styled(Button)` + display : inline-block; + position : relative; + float : right !important; + margin-right : -8px !important; + background : transparent !important; + min-width: 0 !important; + width : 40px; +` + +const StyledModal = styled(Modal)` + .djXaxP{ + margin : 0 !important; + } + display : flex; + align-items: center; + justify-content : center; + text-align : center; + padding : 10px !important; + max-width : none; + max-height : none; +` + +const Container = styled.div` + box-sizing : border-box; + box-shadow : 0 7px 8px -4px rgba(0,0,0,.2),0 13px 19px 2px rgba(0,0,0,.14),0 5px 24px 4px rgba(0,0,0,.12); + background-color : white; + align : center; + display : flex; + flex-direction : column; + min-width : 240px; + max-height : none; + position : relative; + padding : 10px; + border-radius : 4px; + + @media screen and (min-width : 700px) { + max-width : 600px; + max-height : 600px; + } + + @media screen and (max-width : 699px) { + overflow-y : scroll; + width : 100%; + height : 100%; + } +` +const StyledLink = styled(Link)` + text-decoration : none !important; + color : #00bcd4 !important; +` diff --git a/src/Components/TabPanels/UserPageTabs/PanelAtividades.js b/src/Components/TabPanels/UserPageTabs/PanelAtividades.js index 38080f38f5e14aec7ff2768d86d3b945b4186843..7e7b7b00cbebbe058420cdbb184d808920c2c7cf 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelAtividades.js +++ b/src/Components/TabPanels/UserPageTabs/PanelAtividades.js @@ -108,6 +108,7 @@ export default function TabPanelAtividades (props) { { notificationsSlice.map( (notification) => <ActivityListItem + onMenuBar={false} avatar = {notification.owner.avatar ? apiDomain + notification.owner.avatar : null} activity = {notification.activity} actionType = {notification.trackable_type} diff --git a/src/Components/TabPanels/UserPageTabs/PanelGerenciarConta.js b/src/Components/TabPanels/UserPageTabs/PanelGerenciarConta.js index ee09ebe4b676c6ef8cff4013bbe67d82cbd38ef7..e111f1a941dada230b02d11f440a3bd424dd3da6 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelGerenciarConta.js +++ b/src/Components/TabPanels/UserPageTabs/PanelGerenciarConta.js @@ -23,6 +23,7 @@ import FormInput from "../../FormInput.js" import {CompletarCadastroButton} from './PanelSolicitarContaProfessor.js' import {ButtonCancelar} from './PanelEditarPerfil.js' import ValidateUserInput from '../../FormValidationFunction.js' +import ModalExcluirConta from './ModalExcluirConta.js' export default function TabPanelGerenciarConta (props) { const [senhaAtual, setSenhaAtual] = useState( @@ -128,6 +129,8 @@ export default function TabPanelGerenciarConta (props) { } + const [modalExcluir, setModalExcluir] = useState(false) + return ( <> <Paper elevation={3} style= {{width:"100%"}}> @@ -210,7 +213,8 @@ export default function TabPanelGerenciarConta (props) { <span style={{margin:"0", display:"flex", justifyContent:"flex-start"}}>Antes de excluir a sua conta, saiba que ela será removida permanentemente.</span> </div> <div style={{margin:"0", display:"flex", justifyContent:"flex-start"}}> - <ButtonCancelar style={{color:'#eb4034'}}>EXCLUIR CONTA</ButtonCancelar> + <ModalExcluirConta open={modalExcluir} handleClose={() => {setModalExcluir(false)}}/> + <ButtonCancelar style={{color:'#eb4034'}} onClick={() => {setModalExcluir(true)}}>EXCLUIR CONTA</ButtonCancelar> </div> </div> </div> @@ -218,3 +222,4 @@ export default function TabPanelGerenciarConta (props) { </> ) } + diff --git a/src/Components/VerticalRuler.js b/src/Components/VerticalRuler.js new file mode 100644 index 0000000000000000000000000000000000000000..eb178b1336e30b671c5627b9ec4a76c487a52602 --- /dev/null +++ b/src/Components/VerticalRuler.js @@ -0,0 +1,30 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ + +import React from 'react'; + + +export default function VerticalRuler(props) { + return ( + <div + style={{ + borderLeft: ''+props.width+'px solid '+props.color, + height:props.height + }}/> + ); +} diff --git a/src/Pages/Accessibility.js b/src/Pages/Accessibility.js new file mode 100644 index 0000000000000000000000000000000000000000..ff57fd98b3f5d3f546dfa3018f28b6f0478b32d2 --- /dev/null +++ b/src/Pages/Accessibility.js @@ -0,0 +1,151 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, {useState, useContext} from 'react'; +import styled from 'styled-components' +import { Link } from "react-router-dom"; +import Breadcrumbs from "@material-ui/core/Breadcrumbs"; + + +const titulo ={ + fontFamily: "Roboto, sans-serif", + marginTop: "0", + fontSize: "26px", + fontWeight: "300", + marginBottom: "10px", + color: "#666" +} +const subtitulo ={ + fontFamily: "Roboto, sans-serif", + marginBottom: "20px", + marginTop: "0", + fontWeight: "500", + fontSize: "16px", + color: "#00bcd4" + +} + +const paper ={ + padding: "30px 30px 100px 30px", + backgroundColor: "#fff", + boxShadow: "0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24)", + width:"1170px", + margin: "30px auto", + marginBottom:"0", + display: "flex", + flexDirection:"column", + boxSizing: "border-box" +} + +const paragrafo={ + textAlign: "left", + padding: "30px 0", + margin: "0", + fontFamily: "'Roboto Light','Roboto Regular',Roboto", + fontWeight: "300", + fontSize: "18px", + color: "#666", + display:"block" +} + +const azulzinho={ + textAlign: "right", + display:"block", + color: "#00bcd4", + fontSize: "16px" +} + +const atalhos = { + fontWeight: "400", + color: "#00bcd4" + +} + +const breadCrumbs={ + padding: "10px", + display: "flex", + margin: "0 auto", + width:"1170px" +} +const StyledBreadCrumbs = styled(Breadcrumbs)` + display: flex; + justify-content: flex-start; + max-width: 1170px; + span { + color: #a5a5a5; + font-size: 14px; + } + a { + color: #00bcd4; + text-decoration: none; + font-size: 14px; + } +`; + +export default function Acessibility (props) { + return ( + <div style={{padding:"0 0 30px 0",backgroundColor :"#f4f4f4"}}> + + <div style={breadCrumbs}> + <StyledBreadCrumbs> + <Link to="/">Página Inicial</Link> + <span>Acessibilidade</span> + + </StyledBreadCrumbs> + </div> + <link href="https://fonts.googleapis.com/css?family=Roboto:300;400;500&display=swap" rel="stylesheet"/> + <div style={paper}> + <h3 style={titulo}>Acessibilidade</h3> + <div style={{maxWidth:"660px",margin:"0 auto"}}> + <p style={paragrafo}> + Acessibilidade na web é possibilitar qualquer indivÃduo de usufruir de quaisquer + atividades ou conteúdos em sÃtios e serviços disponÃveis na web, com igualdade e + autonomia, independentemente de sua capacidade motora, visual, auditiva, + intelectual, cultural ou social + </p> + <span style={azulzinho}> + Cartilha Acessibilidade na Web - W3C Brasil, 2013 + </span> + <p style={paragrafo}> + Na Plataforma a acessibilidade foi baseada principalmente no Modelo de + Acessibilidade em Governo Eletrônico (e-MAG), o modelo pode ser acessado + <a + style={{textDecoration:"none", color:"#222"}} + target="_blank" + href="https://www.governoeletronico.gov.br/documentos-e-arquivos/e-MAG%20V3.pdf"> aqui</a>. + </p> + </div> + <div style={{color:"#666", fontSize:"14px"}}> + <h3 style={subtitulo}>Atalhos padrões da Plataforma</h3> + Teclando-se <strong style={atalhos}>Alt + 1</strong> em qualquer página da Plataforma, chega-se diretamente ao começo do conteúdo principal da página. + <br/><br/> + Teclando-se <strong style={atalhos}>Alt + 2</strong> em qualquer página da Plataforma, chega-se diretamente ao inÃcio do menu principal. + <br/><br/> + Teclando-se <strong style={atalhos}>Alt + 3</strong> em qualquer página da Plataforma, chega-se diretamente no campo de busca. + <br/><br/> + Teclando-se <strong style={atalhos}>Alt + 4</strong> em qualquer página da Plataforma, chega-se diretamente ao rodapé. + <br/><br/> + No caso do <strong style={atalhos}>Firefox</strong>, em vez de Alt + número, tecle simultaneamente <strong style={atalhos}>Alt + Shift + número</strong>. + <br/><br/> + Sendo <strong style={atalhos}>Firefox</strong> no <strong style={atalhos}>Mac OS</strong>, em vez de Alt + Shift + número, tecle simultaneamente <strong style={atalhos}>Ctrl + Alt + número</strong>. + <br/><br/> + No <strong style={atalhos}>Opera</strong>, as teclas são <strong style={atalhos}>Shift + Escape + número</strong>. Ao teclar apenas <strong style={atalhos}>Shift + Escape</strong>, o usuário encontrará uma janela com todas as alternativas de ACCESSKEY da página. + </div> + </div> + </div> + ); +} diff --git a/src/Pages/CollectionPage.js b/src/Pages/CollectionPage.js index 53f2351c0eade585a0709d459f9f940299b60bb5..f7b3a32e0016fde9b1370e7f5d5024549a7b4ed5 100644 --- a/src/Pages/CollectionPage.js +++ b/src/Pages/CollectionPage.js @@ -2,7 +2,6 @@ Departamento de Informatica - Universidade Federal do Parana This file is part of Plataforma Integrada MEC. - Plataforma Integrada MEC is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or @@ -16,15 +15,90 @@ GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ -import React, {Component} from 'react'; +import React, { useRef, useState, useEffect } from 'react'; +import axios from 'axios'; +import { Grid } from '@material-ui/core'; +import CollectionAuthor from '../Components/CollectionAuthor.js'; +import VerticalRuler from '../Components/VerticalRuler.js'; +import CollectionDescription from '../Components/CollectionDescription.js'; +import ResourceList from '../Components/ResourceList.js'; +import CollectionCommentSection from '../Components/CollectionCommentSection.js'; +import { apiUrl, apiDomain } from '../env'; +import CircularProgress from '@material-ui/core/CircularProgress'; + +export default function CollectionPage(props) { + const [collection, setCollection] = useState({ + name: '', + id: 0, + }); + const collection_id = props.match.params.id; + const comment_ref = useRef(null); + + useEffect(()=>{ + axios.get(apiUrl+'/collections/'+collection_id) + .then(res => { + setCollection(Object.assign({}, res.data)); + }); + }, []); + + const handleScrollToComments = () => { + window.scrollTo(0, comment_ref.current.offsetTop); + } + + return ( + <Grid container + direction="row" + justify="space-around" + alignItems="center" + style={mainContainerStyle}> + + <Grid item xs={10} md={3}> + <CollectionAuthor + author_id={collection.owner ? collection.owner.id : 0} + name={collection.owner ? collection.owner.name : ""} + imgsrc={collection.owner ? apiDomain+collection.owner.avatar : ''}/> + </Grid> + + <VerticalRuler width={1} height={300} color="rgb(238, 238, 238)"/> + <Grid item xs={10} md={6}> + <CollectionDescription + scrollToComments={handleScrollToComments} + title={collection.name ? collection.name : ""} + collection_id={collection.id ? collection.id : 0}/> + </Grid> -class CollectionPage extends Component { - render() { - return ( - <h1> Página visulizar coleção</h1> - ); - } - } + <Grid container item xs={12} direction="row" justify="center" alignItems="center" style={{backgroundColor: '#f4f4f4'}}> + <Grid item xs={10}> + <ResourceList resources={ + collection.collection_items ? + collection.collection_items.map(i => { + return { + type: i.collectionable.object_type, + author: i.collectionable.author, + published: i.collectionable.published_at, + title: i.collectionable.name, + rating: i.collectionable.review_average, + likeCount: i.collectionable.likes_count, + liked: i.collectionable.liked, + avatar: i.collectionable.publisher.avatar, + thumbnail: i.collectionable.thumbnail, + tags: i.collectionable.tags.map(t => t.name), + id: i.collectionable.id, + } + }) + : [] + }/> + + </Grid> + <Grid container item xs={12} style={{marginTop: 40}} ref={comment_ref}> + <CollectionCommentSection id={collection_id}/> + </Grid> + </Grid> + </Grid> + ); +} -export default CollectionPage; +const mainContainerStyle = { + marginTop: '5%', +} diff --git a/src/Pages/Search.js b/src/Pages/Search.js index 50234337bc6dc86c83545d9722f6febe3982c706..8fbba1a8eeb3140f38753f965105f98f33fc67d2 100644 --- a/src/Pages/Search.js +++ b/src/Pages/Search.js @@ -18,6 +18,7 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React, { useEffect, useState, useContext } from "react"; import axios from "axios"; +import {apiDomain} from '../env'; import { Link } from "react-router-dom"; import styled from "styled-components"; import Paper from "@material-ui/core/Paper"; @@ -25,70 +26,69 @@ import Paper from "@material-ui/core/Paper"; // import ResourceCard from '../Components/ResourceCard' // import CollectionCard from '../Components/CollectionCard' // import UserCard from '../Components/UserCard' +import Select from "react-dropdown-select"; import Breadcrumbs from "@material-ui/core/Breadcrumbs"; import { apiUrl } from "../env"; import "./Styles/Home.css"; import { Store } from "../Store"; import { Grid } from "@material-ui/core"; -import Dropdown from 'react-dropdown' -import 'react-dropdown/style.css' +import Dropdown from "react-dropdown"; +import "react-dropdown/style.css"; import SearchExpansionPanel from "../Components/SearchExpansionPanel/SearchExpansionPanel"; -import ResourceCard from "../Components/ResourceCard"; +import ResourceCardFunction from "../Components/ResourceCardFunction"; +import CollectionCardFunction from "../Components/CollectionCardFunction"; +import ContactCard from "../Components/ContactCard"; export default function Search(props) { const { state, dispatch } = useContext(Store); - const [results, setResults] = useState([]); + const [resultsResource, setResultsResource] = useState([]); + const [resultsCollection, setResultsCollection] = useState([]); + const [resultsUser, setResultsUser] = useState([]); const [page] = useState(0); - const [resultsPerPage, setResultsPerPage] = useState(12); + const [resultsPerPage, setResultsPerPage] = useState(6); const [order] = useState("score"); - const options = [ - - {value:"LearningObject", label:"Recursos"}, - {value:"Collection", label:"Coleções"}, - {value:"User", label:"Usuários"} - - ]; - const ordenar = [ - {label:"Mais Estrelas"}, - {label:"Mais Relevante"}, - {label:"Mais Baixados"}, - {label:"Mais Favoritados"}, - {label:"Mais Recentes"}, - {label:"Ordem Alfabética"}, - ]; + const [options] = React.useState([ + { label: "Recursos", value: "LearningObject" }, + { label: "Coleções", value: "Collection" }, + { label: "Usuários", value: "User" }, + ]); + const [ordenar] = useState([ + { label: "Mais Estrelas" }, + { label: "Mais Relevante" }, + { label: "Mais Baixados" }, + { label: "Mais Favoritados" }, + { label: "Mais Recentes" }, + { label: "Ordem Alfabética" }, + ]); - const [defaultOption,setDefaultOption] =useState( options[0]); - const [defaultOrder,setDefaultOrder] =useState( ordenar[0]); + const [option, setOption] = useState( + new URLSearchParams(window.location.search).get("search_class") + ); + const [optionResult, setOptionResult] = useState(option); + console.log(option); + console.log(state.search.class); + + const collectStuff = (tipoBusca) => { + console.log(tipoBusca); - const collectStuff = (tipoBusca=state.search.class,option=undefined) => { - axios .get( `${apiUrl}/search?page=${page}&results_per_page=${resultsPerPage}&order=${order}&query=${state.search.query}&search_class=${tipoBusca}` ) - .then(res => { - setResults(res.data); - if (option != undefined) { - let aux = undefined; - for (let i=0; i < options.length;i=i+1){ - - console.log("Vamo dale0") - if (options[i].label==option){ - console.log("Vamo dale") - setDefaultOption(options[i]); - - } - } - - } + .then((res) => { + if (tipoBusca === "LearningObject") setResultsResource(res.data); + else if (tipoBusca === "Collection") setResultsCollection(res.data); + else if (tipoBusca === "User") setResultsUser(res.data); + setOptionResult(tipoBusca); console.log(res.data); console.log(tipoBusca); - })}; + }); + }; useEffect(() => { dispatch({ type: "HANDLE_SEARCH_BAR", - opened: false + opened: false, }); const urlParams = new URLSearchParams(window.location.search); @@ -100,55 +100,51 @@ export default function Search(props) { type: "SAVE_SEARCH", newSearch: { query: query, - class: searchClass - } + class: searchClass, + }, }); } return () => dispatch({ type: "HANDLE_SEARCH_BAR", - opened: false + opened: false, }); }, []); - useEffect(() => { - collectStuff(); - }, [state.search, resultsPerPage]); - - - + collectStuff(option); + }, [resultsPerPage]); return ( <div style={{ backgroundColor: "#f4f4f4" }}> - <React.Fragment> + {/* <React.Fragment> <h1> Search for {state.search.query !== "*" ? state.search.query : "all"}{" "} in {state.search.class} </h1> {state.search.class === "LearningObject" && ( <ul> - {results.map(res => ( + {results.map((res) => ( <li key={res.id}> {res.name} </li> ))} </ul> )} {state.search.class === "Collection" && ( <ul> - {results.map(res => ( + {results.map((res) => ( <li key={res.id}> {res.name} </li> ))} </ul> )} {state.search.class === "User" && ( <ul> - {results.map(res => ( + {results.map((res) => ( <li key={res.id}> {res.name} </li> ))} </ul> )} - </React.Fragment> + </React.Fragment> */} <Principal> <BreadCrumbsDiv> @@ -165,13 +161,29 @@ export default function Search(props) { style={{ display: "flex", flexDirection: "column", - justifyContent: "center" + justifyContent: "center", + paddingLeft: 20, }} > - <div style={{display:"flex",flexDirection:"row"}}> - <div style={{ textAlign: "left" }}>Mostrar</div> - <Dropdown options={options} onChange={()=>{collectStuff(options.value,options.label )}} value={defaultOption} placeholder="Select an option" /> - + <div style={{ display: "flex", flexDirection: "row" }}> + <span style={{ alignSelf: "center", marginRight: 10 }}> + MOSTRAR: + </span> + <select + style={{ backgroundColor: "transparent", border: "none" }} + value={option} + onChange={(e) => { + console.log(e.currentTarget.value); + setOption(e.currentTarget.value); + collectStuff(e.currentTarget.value); + }} + > + {options.map((item) => ( + <option key={item.value} value={item.value}> + {item.label} + </option> + ))} + </select> </div> </Grid> <Grid @@ -180,10 +192,10 @@ export default function Search(props) { style={{ display: "flex", flexDirection: "column", - justifyContent: "center" + justifyContent: "center", }} > - <div>Numero</div> + <div>Número</div> </Grid> <Grid item @@ -191,48 +203,206 @@ export default function Search(props) { style={{ display: "flex", flexDirection: "column", - justifyContent: "center" + justifyContent: "center", + paddingRight: 20, }} > - <div style={{ textAlign: "right" }}>Ordenar por:</div> - <Dropdown options={ordenar} onChange={()=>{collectStuff(ordenar.label )}} value={defaultOrder} placeholder="Select an order "/> + <div + style={{ + display: "flex", + flexDirection: "row", + justifyContent: "end", + }} + > + <span + style={{ + textAlign: "right", + alignSelf: "center", + marginRight: 10, + }} + > + ORDENAR POR: + </span> + <Dropdown + options={ordenar} + onChange={() => { + collectStuff(ordenar.label); + }} + placeholder="Select an order " + /> + </div> </Grid> </Grid> </HeaderFilters> - <GridBusca container spacing={2}> - <Grid item md={3} xs={12}> - <Paper elevation={4} square> - <SearchExpansionPanel /> - </Paper> - </Grid> - <Grid item md={9} xs={12}> - <Grid container spacing={2}> - {results.map(card => ( - <Grid item md={4} xs={6} key={card.id}> - <ResourceCard - name={card.name} - rating={card.score} - type={card.object_type} - description={card.description} - thumbnail={card.thumbnail} - author={card.author} - avatar={card.publisher.avatar} - /> - </Grid> - ))} + + {optionResult === "Collection" && ( + <GridBuscaCollection container spacing={2}> + <Grid item md={12} xs={12}> + <Grid container spacing={2}> + {resultsCollection.map((card) => ( + <Grid item md={4} xs={6} key={card.id}> + <CollectionCardFunction + name={card.name} + rating={card.score} + author={card.owner.name} + description={card.description} + thumbnails={card.items_thumbnails} + avatar={card.owner.avatar} + /> + </Grid> + ))} + </Grid> + <div + style={{ + display: "flex", + flexDirection: "row", + justifyContent: "center", + }} + > + <button + style={{ + height: 36, + backgroundColor: "#ff7f00", + marginBottom: 50, + marginTop: 50, + fontSize: 14, + color: "white", + borderRadius: 4, + border: "none", + }} + onClick={() => setResultsPerPage(resultsPerPage + 12)} + > + Carregar mais 12 + </button> + </div> </Grid> - <button onClick={() => setResultsPerPage(resultsPerPage + 12)}> - Número de recursos mostrados {resultsPerPage} - </button> - </Grid> - </GridBusca> + </GridBuscaCollection> + )} + {optionResult === "LearningObject" && ( + <GridBuscaResource container spacing={2}> + <Grid item md={3} xs={12}> + <Paper elevation={4} square> + <SearchExpansionPanel /> + </Paper> + </Grid> + <Grid item md={9} xs={12}> + <Grid container spacing={2}> + {resultsResource.map((card) => ( + <Grid item md={4} xs={6} key={card.id}> + <ResourceCardFunction + name={card.name} + rating={card.score} + type={card.object_type} + description={card.description} + thumbnail={card.thumbnail} + author={card.author} + avatar={card.publisher.avatar} + /> + </Grid> + ))} + </Grid> + <div + style={{ + display: "flex", + flexDirection: "row", + justifyContent: "center", + }} + > + <button + style={{ + height: 36, + backgroundColor: "#ff7f00", + marginBottom: 50, + marginTop: 50, + fontSize: 14, + color: "white", + borderRadius: 4, + border: "none", + }} + onClick={() => setResultsPerPage(resultsPerPage + 12)} + > + Carregar mais 12 + </button> + </div> + </Grid> + </GridBuscaResource> + )} + {optionResult === "User" && ( + <GridBuscaUser container spacing={2}> + <Grid item md={12} xs={12}> + <Grid container spacing={2}> + {resultsUser.map((card) => ( + <Grid item md={4} xs={6} key={card.id}> + <ContactCard + name = {card.name} + avatar = {card.avatar ? apiDomain + card.avatar : null} + cover={card.cover ? apiDomain + card.cover : null} + numCollections = {card.collections_count} + numLearningObjects = {card.learning_objects_count} + follow_count={card.follows_count} + followed = {card.followed || null} + followerID = {card.id} + href={'/usuario-publico/' + card.id} + /> + </Grid> + ))} + </Grid> + <div + style={{ + display: "flex", + flexDirection: "row", + justifyContent: "center", + }} + > + <button + style={{ + height: 36, + backgroundColor: "#ff7f00", + marginBottom: 50, + marginTop: 50, + fontSize: 14, + color: "white", + borderRadius: 4, + border: "none", + }} + onClick={() => setResultsPerPage(resultsPerPage + 6)} + > + Carregar mais 6 + </button> + </div> + </Grid> + </GridBuscaUser> + )} </Principal> </div> ); } -const GridBusca = styled(Grid)` +const GridBuscaCollection = styled(Grid)` + color: #666; + background-color: green; + + h4 { + padding: 0 15px; + font-size: 18px; + margin-block: 10px; + text-transform: uppercase; + } +`; +const GridBuscaResource = styled(Grid)` + color: #666; + background-color: red; + + h4 { + padding: 0 15px; + font-size: 18px; + margin-block: 10px; + text-transform: uppercase; + } +`; +const GridBuscaUser = styled(Grid)` color: #666; + background-color: blue; h4 { padding: 0 15px; diff --git a/src/Pages/SiteMap.js b/src/Pages/SiteMap.js new file mode 100644 index 0000000000000000000000000000000000000000..13d6eb97e97a57234e4a7f452c264ba5995b3392 --- /dev/null +++ b/src/Pages/SiteMap.js @@ -0,0 +1,188 @@ +/*Copyright (C) 2019 Centro de Computacao Cientifica e Software Livre +Departamento de Informatica - Universidade Federal do Parana + +This file is part of Plataforma Integrada MEC. + +Plataforma Integrada MEC is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Plataforma Integrada MEC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Affero General Public License for more details. + +You should have received a copy of the GNU Affero General Public License +along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/>.*/ +import React, {useState, useContext} from 'react'; +import styled from 'styled-components' +import { Link } from "react-router-dom"; +import Breadcrumbs from "@material-ui/core/Breadcrumbs"; + + +const titulo ={ + fontFamily: "Roboto, sans-serif", + marginTop: "0", + fontSize: "26px", + fontWeight: "300", + marginBottom: "10px", + color: "#666" +} +const subtitulo ={ + fontFamily: "Roboto, sans-serif", + marginTop: "40px", + fontWeight:"500", + fontSize:"16px", + color: "#00bcd4" + +} +const item={ + fontFamily: "Roboto, sans-serif", + textDecoration: "none", + display:"block", + fontSize:"15px", + color: "#333", + fontWeight:"300", + paddingBottom: "5px" +} +const linha={ + margin: "15px 0", + borderTop: "2px solid #00bcd4", + borderBottom:"none" +} + +const paper ={ + padding: "30px 30px 100px 30px", + backgroundColor: "#fff", + boxShadow: "0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24)", + maxWidth:"1170px", + margin: "30px auto", + marginBottom:"0", + display: "flex", + flexDirection:"column", + boxSizing: "border-box" +} + +const cards={ + display:"flex", + flexDirection:"row" +} + +const card = { + padding:"0 15px", + width:"25%" +} + +const breadCrumbs={ + padding: "10px", + display: "flex", + margin: "0 auto", + width:"1170px" +} +const StyledBreadCrumbs = styled(Breadcrumbs)` + display: flex; + justify-content: flex-start; + max-width: 1170px; + span { + color: #a5a5a5; + font-size: 14px; + } + a { + color: #00bcd4; + text-decoration: none; + font-size: 14px; + } +`; + +export default function SiteMap (props) { + return ( + <div style={{ padding:"0 0 30px 0",backgroundColor :"#f4f4f4"}}> + + <div style={breadCrumbs}> + <StyledBreadCrumbs> + <Link to="/">Página Inicial</Link> + <span>Mapa do site</span> + + </StyledBreadCrumbs> + </div> + <link href="https://fonts.googleapis.com/css?family=Roboto:300;500&display=swap" rel="stylesheet"/> + <div style={paper}> + <h3 style={titulo}>Mapa do site</h3> + <div style={cards}> + <div style={card}> + <h3 style={subtitulo}>Sobre</h3> + <hr style={linha} /> + <a style={item} href="sobre">Sobre a Plataforma</a> + <a style={item} href="sobre#portaisparceiros">Portais Parceiros</a> + <a style={item} href="termos">Termos de Uso</a> + <a style={item} href="contato">Contato</a> + </div> + <div style={card}> + <h3 style={subtitulo}>Ajuda</h3> + <hr style={linha} /> + <a style={item} href="ajuda">Central de Ajuda</a> + <Link + style={item} + to={{ + pathname: "plataforma-mec", + + state: { value: "0" } + }} + > O que é a Plataforma MEC</Link> + <Link + style={item} + to={{ + pathname: "publicando-recurso", + state: { value: "0" } + }} + > Publicando Recurso + </Link> + + <Link + style={item} + to={{ + pathname: "encontrando-recurso", + state: { value: "0" } + }} + > Encontrando Recurso + </Link> + <Link + style={item} + to={{ + pathname: "/participando-da-rede", + + state: { value: "0" } + }} + > Participando da Rede + </Link> + <Link + style={item} + to={{ + pathname: "gerenciando-conta", + + state: { value: "0" } + }} + > Gerenciando a conta + </Link> + </div> + + <div style={card}> + <h3 style={subtitulo}>Acessibilidade</h3> + <hr style={linha} /> + <a style={item} href="acessibilidade">Acessibilidade</a> + </div> + <div style={card}> + <h3 style={subtitulo}>Ãrea do Usuário</h3> + <hr style={linha} /> + <a style={item} href="/perfil">Perfil e Atividades</a> + <a style={item} href="perfil">Recursos Publicados</a> + <a style={item} href="/perfil">Favoritos</a> + <a style={item} href="perfil">Coleções</a> + <a style={item} href="/perfil">Rede</a> + </div> + </div> + </div> + </div> + ); +} diff --git a/src/Pages/TermsPage.js b/src/Pages/TermsPage.js index 7a168814b56a521e46b8a86e5dd2155b25e168f4..b8296f954e3a0a15201504828ddcd2c13bf68e11 100644 --- a/src/Pages/TermsPage.js +++ b/src/Pages/TermsPage.js @@ -97,7 +97,7 @@ export default function TermsContainer (props) { userAgreement: true }) - if (props.cameFromPublishButton) { + if (props.location.state) { props.history.push('/professor') }else { props.history.push('/permission') diff --git a/src/Pages/UserPage.js b/src/Pages/UserPage.js index 83acf71d2e65b3e60dc654cfb92a9ba0f54b6661..6c1359d6b64ae45c734d83c0108e66f964f29a07 100644 --- a/src/Pages/UserPage.js +++ b/src/Pages/UserPage.js @@ -65,7 +65,7 @@ export default function UserPage (props){ Number(props.location.state) || 0 ); const [tabs, setTabs] = useState([ - 'Atividades', 'Status e Conquistas', 'Meus Recursos', 'Favoritos', 'Coleções', 'Rede' + 'Atividades', 'Meus Recursos', 'Favoritos', 'Coleções', 'Rede' ]) const handleChangeTab = (event, newValue) => { setTabValue(newValue) @@ -84,7 +84,7 @@ export default function UserPage (props){ if((response.data.role_ids.includes(4))) { setTabs([ - 'Atividades', 'Status e Conquistas', 'Meus Recursos', 'Favoritos', 'Coleções', 'Rede', 'Curadoria' + 'Atividades', 'Meus Recursos', 'Favoritos', 'Coleções', 'Rede', 'Curadoria' ]) } }, @@ -162,16 +162,14 @@ export default function UserPage (props){ {tabValue === 0 && <TabPanelAtividades id={id} config={GetHeaderConfig()}/>} {tabValue === 1 && - <TabPanelStatusEConquistas id={id} config={GetHeaderConfig()}/>} - {tabValue === 2 && <TabPanelMeusRecursos id={id} config={GetHeaderConfig()}/>} - {tabValue === 3 && + {tabValue === 2 && <TabPanelFavoritos id={id} config={GetHeaderConfig()}/>} - {tabValue === 4 && + {tabValue === 3 && <TabPanelColecoes id={id} config={GetHeaderConfig()}/>} - {tabValue === 5 && + {tabValue === 4 && <TabPanelRede id={id} config={GetHeaderConfig()}/>} - {tabValue === 6 && + {tabValue === 5 && <TabPanelCuradoria id={id} config={GetHeaderConfig()}/>} </Grid> </Grid> diff --git a/src/Store.js b/src/Store.js index 2d5aaa81d7419740f6f4a34618975773ea836cac..3838a6b5245ef2be9598ec739fdde53c14f217ea 100644 --- a/src/Store.js +++ b/src/Store.js @@ -35,7 +35,7 @@ const initialState = { height: 0 }, currentUser: { - askTeacherQuestion : true, + askTeacherQuestion : false, id : '', username : '', email : '', @@ -81,10 +81,13 @@ function reducer(state, action) { currentUser:action.login } case 'USER_LOGGED_OUT': + sessionStorage.clear() return { ...state, userIsLoggedIn:action.userLoggedOut, - currentUser:action.login + currentUser:action.login, + userAgreedToPublicationTerms: false, + userAgreedToPublicationPermissions: false } case 'USER_AGREED_TO_PUBLICATION_TERMS': return { @@ -106,6 +109,32 @@ function reducer(state, action) { ...state, currentUser : action.currUser } + case 'USER_DELETED_ACCOUNT': + localStorage.clear() + return { + ...state, + userIsLoggedIn:false, + currentUser: { + askTeacherQuestion : true, + id : '', + username : '', + email : '', + accessToken : '', + clientToken : '', + userAvatar : '', + userCover : '', + uid : '', + followCount : 0, + collectionsCount : 0, + submitter_request : 'default', + roles : [] + }, + } + case 'TOGGLE_MODAL_COLABORAR_PLATAFORMA': + return { + ...state, + modalColaborarPlataformaOpen : action.modalColaborarPlataformaOpen + } default: return state } diff --git a/src/img/Excluir.png b/src/img/Excluir.png new file mode 100644 index 0000000000000000000000000000000000000000..fd6fb1bd51208e07d3565f89b5e517f8e1386145 Binary files /dev/null and b/src/img/Excluir.png differ