diff --git a/package-lock.json b/package-lock.json index dff899627684dc4a894a7415e6cd2e0e65709081..43a1c84dc653fe49e201e1273ea0054d40e3f1d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2038,6 +2038,14 @@ } } }, + "@types/react-recaptcha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/react-recaptcha/-/react-recaptcha-2.3.3.tgz", + "integrity": "sha512-1IdhJxBbPN+QL/eARSl/qwV2+03kwewJmZ43CWJJoGVZd4S4wGiascCl1HVe8PRtNPzXDqAi+nXIufvEDIsAPg==", + "requires": { + "@types/react": "*" + } + }, "@types/react-transition-group": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", @@ -2957,9 +2965,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -3908,14 +3916,32 @@ } }, "browserslist": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.0.tgz", - "integrity": "sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==", + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", "requires": { - "caniuse-lite": "^1.0.30001043", - "electron-to-chromium": "^1.3.413", - "node-releases": "^1.1.53", - "pkg-up": "^2.0.0" + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + }, + "dependencies": { + "caniuse-lite": { + "version": "1.0.30001239", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001239.tgz", + "integrity": "sha512-cyBkXJDMeI4wthy8xJ2FvDU6+0dtcZSJW3voUF8+e9f1bBeuvyZfc3PNbkOETyhbR+dGCPzn9E7MA3iwzusOhQ==" + }, + "electron-to-chromium": { + "version": "1.3.755", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.755.tgz", + "integrity": "sha512-BJ1s/kuUuOeo1bF/EM2E4yqW9te0Hpof3wgwBx40AWJE18zsD1Tqo0kr7ijnOc+lRsrlrqKPauJAHqaxOItoUA==" + }, + "node-releases": { + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==" + } } }, "bser": { @@ -4000,9 +4026,9 @@ }, "dependencies": { "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==" + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" } } }, @@ -4461,6 +4487,11 @@ "simple-swizzle": "^0.2.2" } }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + }, "colornames": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", @@ -4809,9 +4840,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4853,9 +4884,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4892,9 +4923,9 @@ "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" }, "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -4954,9 +4985,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -5109,9 +5140,9 @@ } }, "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -5176,9 +5207,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -5219,9 +5250,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -5626,9 +5657,9 @@ "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" }, "dns-packet": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz", - "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", + "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", "requires": { "ip": "^1.1.0", "safe-buffer": "^5.0.1" @@ -5714,11 +5745,18 @@ } }, "domhandler": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", - "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", "requires": { - "domelementtype": "1" + "domelementtype": "^2.2.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + } } }, "domutils": { @@ -5973,6 +6011,11 @@ "is-symbol": "^1.0.2" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -8249,9 +8292,9 @@ "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" }, "handlebars": { - "version": "4.7.6", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", - "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "version": "4.7.7", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", + "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "requires": { "minimist": "^1.2.5", "neo-async": "^2.6.0", @@ -8266,13 +8309,10 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "uglify-js": { - "version": "3.9.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.4.tgz", - "integrity": "sha512-8RZBJq5smLOa7KslsNsVcSH+KOXf1uDU8yqLeNuVKwmT0T3FA0ZoXlinQfRad7SDcbZZRZE4ov+2v71EnxNyCA==", - "optional": true, - "requires": { - "commander": "~2.20.3" - } + "version": "3.13.9", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.9.tgz", + "integrity": "sha512-wZbyTQ1w6Y7fHdt8sJnHfSIuWeDgk6B5rCb4E/AM6QNNPbOMIZph21PW5dRB3h7Df0GszN+t7RuUH6sWK5bF0g==", + "optional": true } } }, @@ -8448,9 +8488,9 @@ "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==" }, "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==" }, "hpack.js": { "version": "2.1.6", @@ -8588,22 +8628,40 @@ } }, "htmlparser2": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", - "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", - "requires": { - "domelementtype": "^1.3.1", - "domhandler": "^2.3.0", - "domutils": "^1.5.1", - "entities": "^1.1.1", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" }, "dependencies": { - "entities": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", - "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + }, + "domutils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } } } }, @@ -10579,9 +10637,9 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash-es": { "version": "4.17.21", @@ -10858,9 +10916,9 @@ } }, "merge-deep": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.2.tgz", - "integrity": "sha512-T7qC8kg4Zoti1cFd8Cr0M+qaZfOwjlPDEdZIIPPB2JZctjaPM4fX+i7HOId69tAti2fvO6X5ldfYUONDODsrkA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", + "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", "requires": { "arr-union": "^3.1.0", "clone-deep": "^0.2.4", @@ -13819,9 +13877,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -13854,9 +13912,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -13893,9 +13951,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -13928,9 +13986,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -13962,9 +14020,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -13997,9 +14055,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14031,9 +14089,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14068,9 +14126,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14102,9 +14160,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14135,9 +14193,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14169,9 +14227,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14208,9 +14266,9 @@ "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" }, "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14257,9 +14315,9 @@ "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" }, "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14300,9 +14358,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14333,9 +14391,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14366,9 +14424,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14399,9 +14457,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14433,9 +14491,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14467,9 +14525,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14500,9 +14558,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14533,9 +14591,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14566,9 +14624,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14599,9 +14657,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14632,9 +14690,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14666,9 +14724,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14700,9 +14758,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14735,9 +14793,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14825,9 +14883,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14858,9 +14916,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14891,9 +14949,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14927,9 +14985,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -14965,9 +15023,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15009,9 +15067,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15045,9 +15103,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15083,9 +15141,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15119,9 +15177,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15197,9 +15255,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15230,9 +15288,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15265,9 +15323,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15301,9 +15359,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15337,9 +15395,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15372,9 +15430,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15407,9 +15465,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15442,9 +15500,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15478,9 +15536,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15512,9 +15570,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15547,9 +15605,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15580,9 +15638,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15613,9 +15671,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15647,9 +15705,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15716,9 +15774,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15755,9 +15813,9 @@ "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" }, "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15801,9 +15859,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15837,9 +15895,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15870,9 +15928,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15903,9 +15961,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15937,9 +15995,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -15971,9 +16029,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -16017,9 +16075,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -16052,9 +16110,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -16298,9 +16356,9 @@ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" }, "querystringify": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz", - "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" }, "raf": { "version": "3.4.1", @@ -17026,9 +17084,9 @@ } }, "react-dropdown": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/react-dropdown/-/react-dropdown-1.9.0.tgz", - "integrity": "sha512-BDApCUhs0qHqnFW3b54SuqI200FOOsmiy0dejdmtdTn/MMY11jcou3CLX1oT2Qa1PdN7viTyAGT8YCpK5qb9xg==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/react-dropdown/-/react-dropdown-1.9.2.tgz", + "integrity": "sha512-g4eufErTi5P5T5bGK+VmLl//qvAHy79jm6KKx8G2Tl3mG90bpigb+Aw85P+C2JUdAnIIQdv8kP/oHN314GvAfw==", "requires": { "classnames": "^2.2.3" } @@ -17894,40 +17952,65 @@ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" }, "renderkid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz", - "integrity": "sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", + "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", "requires": { - "css-select": "^1.1.0", - "dom-converter": "^0.2", - "htmlparser2": "^3.3.0", - "strip-ansi": "^3.0.0", - "utila": "^0.4.0" + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^3.0.1" }, "dependencies": { "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", "requires": { - "boolbase": "~1.0.0", - "css-what": "2.1", - "domutils": "1.5.1", - "nth-check": "~1.0.1" + "boolbase": "^1.0.0", + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" } }, "css-what": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", - "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", + "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==" + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" }, "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "nth-check": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.0.tgz", + "integrity": "sha512-i4sc/Kj8htBrAiH1viZ0TgU8Y5XqCaV/FziYK6TBczxmeKm3AEFWqqF3195yKudrarqy7Zu80Ra5dobFjn9X/Q==", "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "boolbase": "^1.0.0" } } } @@ -19148,9 +19231,9 @@ } }, "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", "requires": { "figgy-pudding": "^3.5.1" } @@ -19533,9 +19616,9 @@ }, "dependencies": { "postcss": { - "version": "7.0.32", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", - "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -19769,9 +19852,9 @@ } }, "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==" + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" } } }, @@ -20225,9 +20308,9 @@ } }, "url-parse": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz", - "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.1.tgz", + "integrity": "sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==", "requires": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -20428,9 +20511,9 @@ "optional": true }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "optional": true, "requires": { "is-glob": "^4.0.1" @@ -21338,9 +21421,9 @@ } }, "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz", + "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", "requires": { "async-limiter": "~1.0.0" } @@ -21362,8 +21445,7 @@ }, "y18n": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + "resolved": "" }, "yallist": { "version": "3.1.1", @@ -21392,6 +21474,13 @@ "which-module": "^2.0.0", "y18n": "^3.2.1", "yargs-parser": "^9.0.2" + }, + "dependencies": { + "y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==" + } } }, "yargs-parser": { diff --git a/package.json b/package.json index 6c44b79445f56fdbb0e65b8f636b81ecd597c08e..e0d4bec3b7d19d0b1719c4cc9da338be771cd854 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@material-ui/lab": "^4.0.0-alpha.57", "@material-ui/styles": "^4.11.2", "@syncfusion/ej2-react-inputs": "^18.3.52", + "@types/react-recaptcha": "^2.3.3", "antd": "^4.13.1", "axios": "^0.21.1", "base64-img": "^1.0.4", @@ -30,7 +31,7 @@ "react": "^16.14.0", "react-cookie": "^4.0.3", "react-dom": "^16.14.0", - "react-dropdown": "^1.9.0", + "react-dropdown": "^1.9.2", "react-dropdown-select": "^4.7.1", "react-easy-crop": "^2.1.0", "react-fine-uploader": "^1.1.1", diff --git a/public/index.html b/public/index.html index 0cf2c82d7dcdfd0db4cc4afe6f97ccc2492f573c..5a55d5b2604173be763d84d95092a495275df599 100755 --- a/public/index.html +++ b/public/index.html @@ -1,3 +1,3 @@ -<!-- 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/. --> <!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="utf-8" /> <meta http-equiv='cache-control' content='no-cache'/> <meta http-equiv='expires' content='0'/> <meta http-equiv='pragma' content='no-cache'/> <!-- google sign-in --> <meta name="google-signin-client_id" content="288460085642-k4veg4fo8kddvjer8b055n9da5qtgha7.apps.googleusercontent.com"> <script src="https://apis.google.com/js/platform.js" async defer></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Plataforma integrada MEC RED</title> </head> <body > <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"/> </body> </html> \ No newline at end of file +<!-- 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/. --> <!DOCTYPE html> <html lang="pt-br"> <head> <meta charset="utf-8" /> <meta http-equiv='cache-control' content='no-cache'/> <meta http-equiv='expires' content='0'/> <meta http-equiv='pragma' content='no-cache'/> <!-- google sign-in --> <meta name="google-signin-client_id" content="288460085642-k4veg4fo8kddvjer8b055n9da5qtgha7.apps.googleusercontent.com"> <script src="https://apis.google.com/js/platform.js" async defer></script> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Plataforma integrada MEC RED</title> </head> <body > <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"/> <script src="https://www.google.com/recaptcha/api.js" async defer></script> </body> </html> \ No newline at end of file diff --git a/src/Admin/Components/Components/DataCards/InstitutionsCard.js b/src/Admin/Components/Components/DataCards/InstitutionsCard.js index b4981b7bb93715a8bbfa0bc94f8d85e628df3416..1791b22d4867fcb2338057acccc185d559c98db4 100644 --- a/src/Admin/Components/Components/DataCards/InstitutionsCard.js +++ b/src/Admin/Components/Components/DataCards/InstitutionsCard.js @@ -168,7 +168,7 @@ const InstitutionCard = () => { </Typography> </Grid> <Grid item> - <Link style={{ textDecoration: 'none' }} to={`/admin/intitutions`}> + <Link style={{ textDecoration: 'none' }} to={`/admin/institutions`}> <Button startIcon={<ListRoundedIcon />} color="primary" diff --git a/src/Admin/Components/Components/Inputs/CreateInstitution.js b/src/Admin/Components/Components/Inputs/CreateInstitution.js index b4f001f083f15aa192319a899cbad7dcac96421a..378c0960b36556a71709978fed512c03db48a9ba 100644 --- a/src/Admin/Components/Components/Inputs/CreateInstitution.js +++ b/src/Admin/Components/Components/Inputs/CreateInstitution.js @@ -227,7 +227,7 @@ const CreateInstitution = (props) => { </Typography> </Grid> <Grid item> - <Link style={{ textDecoration: 'none' }} to={'/admin/intitutions'}> + <Link style={{ textDecoration: 'none' }} to={'/admin/institutions'}> <Button onClick={props.BackToList} startIcon={<ListRoundedIcon />} diff --git a/src/Admin/Components/Components/Inputs/IntitutionsInputs.js b/src/Admin/Components/Components/Inputs/IntitutionsInputs.js index 148f006fd401c3e485beb476954f6a324f7d25d3..ca1ea9dfb454b6cf7275e47b33f9b6da8cd2b212 100644 --- a/src/Admin/Components/Components/Inputs/IntitutionsInputs.js +++ b/src/Admin/Components/Components/Inputs/IntitutionsInputs.js @@ -262,7 +262,7 @@ const EditInstitution = () => { </Grid> <Grid item> - <Link style={{ textDecoration: 'none' }} to={`/admin/intitutions`}> + <Link style={{ textDecoration: 'none' }} to={`/admin/institutions`}> <Button startIcon={<ListRoundedIcon />} color="primary" diff --git a/src/Admin/Components/Components/Unauthorized.js b/src/Admin/Components/Components/Unauthorized.js index decfa6b5aa2504d3aedb0199faa97c66b84025d0..245a219b46f516a8d6fe7ce5d4ec2a89852f2590 100644 --- a/src/Admin/Components/Components/Unauthorized.js +++ b/src/Admin/Components/Components/Unauthorized.js @@ -19,6 +19,8 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React, {useState} from 'react'; import SnackBar from '../../../Components/SnackbarComponent'; import { Link } from 'react-router-dom'; +import styled from "styled-components"; + const Unauthorized = () => { const [openSnack, setOpenSnack] = useState(true); @@ -31,11 +33,33 @@ const Unauthorized = () => { snackbarOpen={openSnack} handleClose={() => setOpenSnack(false)} /> - <Link to='/'> - Redirecionar para home - </Link> + <> + <StyledDiv><span style={{ fontSize: '50px' }}>Desculpe</span></StyledDiv> + <StyledDiv> + <span style={{ fontSize: '30px' }}> + Você não tem as permissões necessárias para acessar essa página. + </span> + </StyledDiv> + <StyledDiv> + <Link to='/'> + <span style={{ fontSize: '20px' }}> + Voltar para a página inicial + </span> + </Link> + </StyledDiv> + </> </div> ); } +const StyledDiv = styled('div')` + width: 100%; + margin-top: 70px; + margin-bottom: 70px; + justify-content : space-evenly; + display: flex; + color: #757575; + text-align:center; +` + export default Unauthorized; \ No newline at end of file diff --git a/src/Admin/Pages/AdminLabelTabs/LabelTabs.js b/src/Admin/Pages/AdminLabelTabs/LabelTabs.js index 54b2a0fdf2dfd40bbef4f5d36ee15c9d6b95f486..ca1f7b5a2dadad873ebb3b23b5d2856c4849fe83 100644 --- a/src/Admin/Pages/AdminLabelTabs/LabelTabs.js +++ b/src/Admin/Pages/AdminLabelTabs/LabelTabs.js @@ -64,7 +64,7 @@ const TabsItens = [ }, { label: "Instituições", - href: '/admin/intitutions', + href: '/admin/institutions', icon: <AccountBalanceRoundedIcon style={{ fill: orange }} />, }, { diff --git a/src/Admin/Services.js b/src/Admin/Services.js deleted file mode 100644 index bce02eb72a414c7f04cbbdb8e0acbec383ca2fd6..0000000000000000000000000000000000000000 --- a/src/Admin/Services.js +++ /dev/null @@ -1,241 +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 axios from 'axios'; - -export function Delete(api) { - return new Promise(resolve => { - axios({ - method: 'delete', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - }).then(response => { - if (response.status === 200) { - resolve(true); - } else { - resolve(false); - } - SaveNewHeaders(response) - }).catch(err =>{ - resolve(false) - }) - }) -} - -export function SendEmail(api, body) { - return new Promise(resolve => { - axios({ - method: 'post', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - data: JSON.stringify(body) - }).then(response => { - console.log(response) - if (response.status === 200) { - resolve(true); - } else { - resolve(false); - } - SaveNewHeaders(response) - }).catch(err =>{ - resolve(false) - }) - }) -} - -export function Edit(api, body) { - return new Promise(resolve => { - axios({ - method: 'put', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - data: JSON.stringify(body) - }).then(response => { - console.log(response) - if (response.status === 200) { - resolve(true) - } else { - resolve(false) - } - SaveNewHeaders(response) - }).catch(err =>{ - resolve(false) - }) - }) -} - -export function Create(api, body) { - return new Promise(resolve => { - axios({ - method: 'post', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - data: JSON.stringify(body) - }).then(response => { - if (response.status === 201) { - resolve(true) - } else { - resolve(false) - } - SaveNewHeaders(response) - }).catch(err =>{ - resolve(false) - }) - }) -} - -export function HandleComplain(api) { - return new Promise(resolve => { - axios({ - method: 'post', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - }).then(response => { - if (response.status === 200) { - resolve(true) - } else { - resolve(false) - } - SaveNewHeaders(response) - }).catch(err =>{ - resolve(false) - }) - }) -} - -export function GetFullList(api, headers) { - - return new Promise(resolve => { - axios({ - method: 'get', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - }).then((res) => { - console.log(res) - if (res.status === 200) { - resolve({ - state: true, - data: res.data - }) - } else { - resolve({ - state: false, - data: {} - }) - } - SaveNewHeaders(res) - }).catch((err) => { - resolve({ - state: false, - data: {} - }) - }) - }, []); -} - -export function GetSpecificData(api, headers) { - return new Promise(resolve => { - axios({ - method: 'get', - url: api, - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json; charset=utf-8', - 'access-token': sessionStorage.getItem('@portalmec/accessToken'), - 'client': sessionStorage.getItem('@portalmec/clientToken'), - 'uid': sessionStorage.getItem('@portalmec/uid'), - 'If-None-Match': null - }, - }).then((res) => { - console.log(res) - if (res.status === 200) { - resolve({ - state: true, - data: res.data - }) - } else { - resolve({ - state: false, - data: {} - }) - } - SaveNewHeaders(res) - }).catch((err) => { - resolve({ - state: false, - data: {} - }) - }) - }, []); -} - -const SaveNewHeaders = (response) => { - if ( - (response.headers['access-token'] === undefined || response.headers['access-token'] === null) && - (response.headers.client === undefined || response.headers.client === null) - ) { - - } else { - sessionStorage.setItem('@portalmec/accessToken', response.headers['access-token']) - sessionStorage.setItem('@portalmec/clientToken', response.headers.client) - console.log('saved') - } -} - diff --git a/src/App.js b/src/App.js index 69f120fca178d1bd363b70a9348f0b0101dc8086..b5a80b2f2b1902af6232cdb5c49b1ca956a4d0c0 100644 --- a/src/App.js +++ b/src/App.js @@ -52,6 +52,7 @@ import CollectionPage from "./Pages/CollectionPage.js"; import FormationMaterialPage from "./Pages/FormationMaterialPage.js"; import FormationMaterialIframe from "./Pages/FormationMaterialIframe.js"; import MaterialPage from "./Pages/MaterialPage"; +import PageNotFound from "./Pages/PageNotFound.js"; import NoteVariables from "./Admin/Pages/Pages/SubPages/NoteVariables"; import Institution from "./Admin/Pages/Pages/SubPages/Institutions"; @@ -151,8 +152,30 @@ export default function App() { return () => window.removeEventListener("resize", setWindowSize); }, [window.innerWidth, window.innerHeight]); + const AdminTemplate = (props) => { + if (CheckUserPermission()) + return ( + <div style={{ backgroundColor: " #D3D3D3" }}> + <AppBarAdmin /> + <div style={{ padding: "2em" }}> + {props.inner} + </div> + </div> + ) + else + return ( + <div style={{ backgroundColor: " #D3D3D3" }}> + <div style={{ padding: "2em" }}> + <Unauthorized /> + </div> + </div> + ) + } + return ( - <BrowserRouter history={piwik.connectToHistory(customHistory)}> + // add piwik later + // history={piwik.connectToHistory(customHistory)} + <BrowserRouter> <Header /> <div style={{ @@ -201,262 +224,237 @@ export default function App() { <Route path="/topico" component={FormationMaterialPage} /> <Route path="/iframe-colecao" component={FormationMaterialIframe} /> <Route path="/material-formacao" component={MaterialPage} /> - <div style={{ backgroundColor: " #D3D3D3" }}> - <AppBarAdmin /> - <div style={{ padding: "2em" }}> - <Route path="/admin/home" exact={true} render={() => { - if (CheckUserPermission()) - return <Inframe /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/intitutions" render={() => { - if (CheckUserPermission()) - return <Institution /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/institution" render={() => { - if (CheckUserPermission()) - return <InstitutionCard /> - else - return <Unauthorized /> - }} /> - <Route - path="/admin/institutionEdit" - render={() => { - if (CheckUserPermission()) - return <InstitutionsInput /> - else - return <Unauthorized /> - }} - /> - <Route - path="/admin/InstitutionCreate" - render={() => { - if (CheckUserPermission()) - return <CreateInstitution /> - else - return <Unauthorized /> - }} - /> - <Route path="/admin/noteVars" render={() => { - if (CheckUserPermission()) - return <NoteVariables /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/noteVar" render={() => { - if (CheckUserPermission()) - return <NoteVarCard /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/noteVarEdit" render={() => { - if (CheckUserPermission()) - return <NoteVarInputs /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/languages" render={() => { - if (CheckUserPermission()) - return <Languages /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/languageEdit" render={() => { - if (CheckUserPermission()) - return <EditLanguage /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/languageCreate" render={() => { - if (CheckUserPermission()) - return <CreateLanguage /> - else - return <Unauthorized /> - }} /> - <Route - path="/admin/CommunityQuestions" - render={() => { - if (CheckUserPermission()) - return <CommunityQuestions /> - else - return <Unauthorized /> - }} - /> - <Route - path="/admin/CommunityQuestion" - render={() => { - if (CheckUserPermission()) - return <CommunityCard /> - else - return <Unauthorized /> - }} - /> - <Route path="/admin/Collections" render={() => { - if (CheckUserPermission()) - return <Collections /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/Collection" render={() => { - if (CheckUserPermission()) - return <CollectionCard /> - else - return <Unauthorized /> - }} /> - <Route - path="/admin/EditCollection" - render={() => { - if (CheckUserPermission()) - return <EditCollection /> - else - return <Unauthorized /> - }} - /> - <Route path="/admin/Ratings" render={() => { - if (CheckUserPermission()) - return <Ratings /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/Rating" render={() => { - if (CheckUserPermission()) - return <RatingCard /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/EditRating" render={() => { - if (CheckUserPermission()) - return <EditRating /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/CreateRating" render={() => { - if (CheckUserPermission()) - return <CreateRating /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/Questions" render={() => { - if (CheckUserPermission()) - return <Questions /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/CreateQuestion" render={() => { - if (CheckUserPermission()) - return <CreateQuestions /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/activities" render={() => { - if (CheckUserPermission()) - return <Activity /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/activity" render={() => { - if (CheckUserPermission()) - return <ActivityCard /> - else - return <Unauthorized /> - }} /> - <Route - path="/admin/learningObjects" - render={() => { - if (CheckUserPermission()) - return <EducationalObject /> - else - return <Unauthorized /> - }} /> - <Route - path="/admin/learningObject" - render={() => { - if (CheckUserPermission()) - return <EducationalObjectCard /> - else - return <Unauthorized /> - }} /> - <Route - path="/admin/learningObjectEdit" - render={() => { - if (CheckUserPermission()) - return <EducationalObjectEdit /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/complaints" render={() => { - if (CheckUserPermission()) - return <Complaints /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/complaint" render={() => { - if (CheckUserPermission()) - return <ComplaintCard /> - else - return <Unauthorized /> - }} /> - <Route - path="/admin/users/teacher_requests" - render={() => { - if (CheckUserPermission()) - return <AproveTeacher /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/usersList" render={() => { - if (CheckUserPermission()) - return <UserList /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/user" render={() => { - if (CheckUserPermission()) - return <UserCard /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/EditUser" render={() => { - if (CheckUserPermission()) - return <EditUser /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/permissions" render={() => { - if (CheckUserPermission()) - return <UserPermissions /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/EditPermissions" render={() => { - if (CheckUserPermission()) - return <EditRole /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/CreateRole" render={() => { - if (CheckUserPermission()) - return <CreateRole /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/BlockedUsers" render={() => { - if (CheckUserPermission()) - return <BlockedUser /> - else - return <Unauthorized /> - }} /> - <Route path="/admin/sendEmail" render={() => { - if (CheckUserPermission()) - return <SendEmail /> - else - return <Unauthorized /> - }} /> - </div> - </div> + + <Route + path="/admin/home" + exact={true} + render={() => { + return <AdminTemplate inner={<Inframe/>}/> + }} + /> + <Route + path="/admin/institutions" + render={() => { + return <AdminTemplate inner={<Institution />}/> + }} + /> + <Route + path="/admin/institution" + render={() => { + return <AdminTemplate inner={<InstitutionCard />}/> + }} + /> + <Route + path="/admin/institutionEdit" + render={() => { + return <AdminTemplate inner={<InstitutionsInput />}/> + }} + /> + <Route + path="/admin/InstitutionCreate" + render={() => { + return <AdminTemplate inner={<CreateInstitution />}/> + }} + /> + <Route + path="/admin/noteVars" + render={() => { + return <AdminTemplate inner={<NoteVariables />}/> + }} + /> + <Route + path="/admin/noteVar" + render={() => { + return <AdminTemplate inner={<NoteVarCard />}/> + }} + /> + <Route + path="/admin/noteVarEdit" + render={() => { + return <AdminTemplate inner={<NoteVarInputs />}/> + }} + /> + <Route + path="/admin/languages" + render={() => { + return <AdminTemplate inner={<Languages />}/> + }} + /> + <Route + path="/admin/languageEdit" + render={() => { + return <AdminTemplate inner={<EditLanguage />}/> + }} + /> + <Route + path="/admin/languageCreate" + render={() => { + return <AdminTemplate inner={<CreateLanguage />}/> + }} + /> + <Route + path="/admin/CommunityQuestions" + render={() => { + return <AdminTemplate inner={<CommunityQuestions />}/> + }} + /> + <Route + path="/admin/CommunityQuestion" + render={() => { + return <AdminTemplate inner={<CommunityCard />}/> + }} + /> + <Route + path="/admin/Collections" + render={() => { + return <AdminTemplate inner={<Collections />}/> + }} + /> + <Route + path="/admin/Collection" + render={() => { + return <AdminTemplate inner={<CollectionCard />}/> + }} + /> + <Route + path="/admin/EditCollection" + render={() => { + return <AdminTemplate inner={<EditCollection />}/> + }} + /> + <Route + path="/admin/Ratings" + render={() => { + return <AdminTemplate inner={<Ratings />}/> + }} + /> + <Route + path="/admin/Rating" + render={() => { + return <AdminTemplate inner={<RatingCard />}/> + }} + /> + <Route + path="/admin/EditRating" + render={() => { + return <AdminTemplate inner={<EditRating />}/> + }} + /> + <Route + path="/admin/CreateRating" + render={() => { + return <AdminTemplate inner={<CreateRating />}/> + }} + /> + <Route + path="/admin/Questions" + render={() => { + return <AdminTemplate inner={<Questions />}/> + }} + /> + <Route + path="/admin/CreateQuestion" + render={() => { + return <AdminTemplate inner={<CreateQuestions />}/> + }} + /> + <Route + path="/admin/activities" + render={() => { + return <AdminTemplate inner={<Activity />}/> + }} + /> + <Route + path="/admin/activity" + render={() => { + return <AdminTemplate inner={<ActivityCard />}/> + }} + /> + <Route + path="/admin/learningObjects" + render={() => { + return <AdminTemplate inner={<EducationalObject />}/> + }} + /> + <Route + path="/admin/learningObject" + render={() => { + return <AdminTemplate inner={<EducationalObjectCard />}/> + }} + /> + <Route + path="/admin/learningObjectEdit" + render={() => { + return <AdminTemplate inner={<EducationalObjectEdit />}/> + }} + /> + <Route + path="/admin/complaints" + render={() => { + return <AdminTemplate inner={<Complaints />}/> + }} + /> + <Route + path="/admin/complaint" + render={() => { + return <AdminTemplate inner={<ComplaintCard />}/> + }} + /> + <Route + path="/admin/users/teacher_requests" + render={() => { + return <AdminTemplate inner={<AproveTeacher />}/> + }} /> + <Route + path="/admin/usersList" + render={() => { + return <AdminTemplate inner={<UserList />}/> + }} + /> + <Route + path="/admin/user" + render={() => { + return <AdminTemplate inner={<UserCard />}/> + }} + /> + <Route + path="/admin/EditUser" + render={() => { + return <AdminTemplate inner={<EditUser />}/> + }} + /> + <Route + path="/admin/permissions" + render={() => { + return <AdminTemplate inner={<UserPermissions />}/> + }} + /> + <Route + path="/admin/EditPermissions" + render={() => { + return <AdminTemplate inner={<EditRole />}/> + }} + /> + <Route + path="/admin/CreateRole" + render={() => { + return <AdminTemplate inner={<CreateRole />}/> + }} + /> + <Route + path="/admin/BlockedUsers" + render={() => { + return <AdminTemplate inner={<BlockedUser />}/> + }} + /> + <Route + path="/admin/sendEmail" + render={() => { + return <AdminTemplate inner={<SendEmail />}/> + }} + /> + + <Route path='*' component={PageNotFound} /> </Switch> {!hideFooter && ( <div> @@ -466,4 +464,4 @@ export default function App() { )} </BrowserRouter> ); -} +} \ No newline at end of file diff --git a/src/Components/AreasSubPagesFunction.js b/src/Components/AreasSubPagesFunction.js index f08832691ff2fc7d21160c18b362a4d7cfd6344d..72046e4d265381f4029a7135eb4c7b8748c6e394 100644 --- a/src/Components/AreasSubPagesFunction.js +++ b/src/Components/AreasSubPagesFunction.js @@ -30,7 +30,8 @@ import ResourceCardFunction from "./ResourceCardFunction.js"; import CollectionCardFunction from "./CollectionCardFunction.js"; import colecoes_obj from './FormationMaterialsResources/formationMaterials'; import ExpandedMaterial from './ExpandedMaterials'; -import Dropdown from "react-dropdown"; +import TextField from '@material-ui/core/TextField'; +import MenuItem from '@material-ui/core/MenuItem'; import { getRequest } from './HelperFunctions/getAxiosConfig.js' import Grid from '@material-ui/core/Grid'; import { Link } from 'react-router-dom' @@ -223,7 +224,7 @@ function TabRecurso() { { window.innerWidth <= 501 && <div style={{ display: "flex", justifyContent: "center" }}> - <Link to={`/busca?query=*&search_class=LearningObject`} className="button-ver">VER RECURSOS</Link> + <Link to={`/busca?page=0&results_per_page=12&order=review_average&query=*&search_class=LearningObject`} className="button-ver">VER RECURSOS</Link> </div> } </StyledTab> @@ -257,15 +258,31 @@ function TabRecurso() { <Grid item> <p style={{ margin: 0, padding: 0 }}> Ordenar por: - </p> + </p> </Grid> <Grid item> - <Dropdown options={ordenar} value={currOrder} onChange={(e) => { - setCurrOrder(e.label) - setCurrValue(e.value) - }} - placeholder="Selecione uma opção" - /> + <TextField + select + fullWidth + value={currValue} + variant="outlined" + > + {ordenar.map((option) => ( + <MenuItem + key={option.value} + value={option.value} + name={option.value} + onClick={() => { + setCurrOrder(option.label) + setCurrValue(option.value) + }} + > + <span style={currValue === option.value ? { color: "#ff7f00" } : null} > + {option.label} + </span> + </MenuItem> + ))} + </TextField> </Grid> </Grid> </Grid> @@ -320,7 +337,7 @@ function TabColecoes() { { window.innerWidth <= 501 && <div style={{ display: "flex", justifyContent: "center" }}> - <Link to={`/busca?query=*&search_class=Collection`} className="button-ver">VER COLEÇÕES</Link> + <Link to={`/busca?page=0&results_per_page=12&order=review_average&query=*&search_class=Collection`} className="button-ver">VER COLEÇÕES</Link> </div> } </StyledTab> @@ -357,12 +374,28 @@ function TabColecoes() { </p> </Grid> <Grid item> - <Dropdown options={ordenar} value={currOrder} onChange={(e) => { - setCurrOrder(e.label) - setCurrValue(e.value) - }} - placeholder="Selecione uma opção" - /> + <TextField + select + fullWidth + value={currValue} + variant="outlined" + > + {ordenar.map((option) => ( + <MenuItem + key={option.value} + value={option.value} + name={option.value} + onClick={() => { + setCurrOrder(option.label) + setCurrValue(option.value) + }} + > + <span style={currValue === option.value ? { color: "#673ab7" } : null} > + {option.label} + </span> + </MenuItem> + ))} + </TextField> </Grid> </Grid> </Grid> diff --git a/src/Components/ColCardPublicOptions.js b/src/Components/ColCardPublicOptions.js index 6e374d7a159e18c51bc06a44038c0aa859c796d6..2b58c70f58000d4014fb53330c8901a65cbfc1b3 100644 --- a/src/Components/ColCardPublicOptions.js +++ b/src/Components/ColCardPublicOptions.js @@ -25,13 +25,14 @@ import OpenIcon from '@material-ui/icons/OpenInNew'; import { Link } from 'react-router-dom' import MoreVertIcon from '@material-ui/icons/MoreVert'; import styled from 'styled-components' -import ErrorIcon from '@material-ui/icons/Error'; +import FavoriteIcon from '@material-ui/icons/Favorite'; import ReportModal from './ReportModal.js' import ReportProblemIcon from '@material-ui/icons/ReportProblem'; import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; -import { deleteRequest } from '../Components/HelperFunctions/getAxiosConfig' +import AddIcon from '@material-ui/icons/Add'; +import ExitToAppIcon from '@material-ui/icons/ExitToApp'; -export default function ColCardPublicOptions(props) { +export default function ColCardPublicOptions({ id, userFollowingCol, handleLike, handleFollow, currentUserId, handleLogin, liked }) { const [anchorEl, setAnchorEl] = React.useState(null); function handleClick(event) { @@ -45,20 +46,13 @@ export default function ColCardPublicOptions(props) { const [reportModalOpen, toggleReportModal] = useState(false) const handleReportModal = (value) => { toggleReportModal(value) } - const handleUnfollow = () => { - if (props.currentUserId) - deleteRequest(`/collections/${props.id}/follow`, (data) => { console.log(data) }, (error) => { console.log(error) }) - else - props.handleLogin() - } - return ( <> <ReportModal open={reportModalOpen} handleClose={() => handleReportModal(false)} form="colecao" - complainableId={props.id} + complainableId={id} complainableType={"Collection"} /> <div style={{ fontSize: "12px" }}> @@ -78,7 +72,7 @@ export default function ColCardPublicOptions(props) { onClose={handleClose} > <StyledMenuItem> - <Link to={"/colecao-do-usuario/" + props.id}> + <Link to={"/colecao-do-usuario/" + id}> <ListItemIcon> <OpenIcon /> </ListItemIcon> @@ -88,7 +82,7 @@ export default function ColCardPublicOptions(props) { <StyledMenuItem onClick={() => - window.open("/colecao-do-usuario/" + props.id, "_blank") + window.open("/colecao-do-usuario/" + id, "_blank") } > <ListItemIcon> @@ -97,19 +91,38 @@ export default function ColCardPublicOptions(props) { Abrir em nova guia </StyledMenuItem> - <StyledMenuItem onClick={handleUnfollow}> + <StyledMenuItem onClick={handleLike}> + <ListItemIcon> + { + liked ? + <FavoriteIcon style={{ fill: 'red' }} /> : <FavoriteIcon style={{ fill: '#666' }} /> + } + </ListItemIcon> + { + liked ? + "Desfavoritar" : "Favoritar" + } + </StyledMenuItem> + + <StyledMenuItem onClick={handleFollow}> <ListItemIcon> - <ErrorIcon /> + { + userFollowingCol ? + <ExitToAppIcon /> : <AddIcon /> + } </ListItemIcon> - Deixar de Seguir + { + userFollowingCol ? + "Deixar de seguir" : "Seguir" + } </StyledMenuItem> <StyledMenuItem onClick={() => { - if (props.currentUserId) + if (currentUserId) handleReportModal(true); else - props.handleLogin() + handleLogin() }} > <ListItemIcon> diff --git a/src/Components/CollectionAuthor.js b/src/Components/CollectionAuthor.js index c81f227aadb22527f80b95f72cd226920a63379f..c6c299cf08bba817e4a14e684609084840c44f4b 100644 --- a/src/Components/CollectionAuthor.js +++ b/src/Components/CollectionAuthor.js @@ -29,17 +29,17 @@ export default function CollectionAuthor(props) { direction="column" justify="center" alignItems="center"> - {props.imgsrc ? + {props.imgsrc ? <UserLink to={`/usuario-publico/${props.author_id}`} - > - <UserAvatar src={props.imgsrc}/> + > + <UserAvatar src={props.imgsrc} /> </UserLink> : - <CircularProgress color="secondary"/> + <CircularProgress color="secondary" /> } <InfoText>Coleção organizada por:</InfoText> - {props.name ? + {props.name ? <UserLink to={`/usuario-publico/${props.author_id}`} > <UserName>{props.name}</UserName> </UserLink> diff --git a/src/Components/CollectionCardFunction.js b/src/Components/CollectionCardFunction.js index 6f7322e7261536655d78098ad28b3639e87af2a5..dd4e3d079b837960dd76e8621f494404c71ecb47 100644 --- a/src/Components/CollectionCardFunction.js +++ b/src/Components/CollectionCardFunction.js @@ -22,7 +22,6 @@ import { apiDomain } from '../env'; import noAvatar from "../img/default_profile.png"; import Button from '@material-ui/core/Button'; import styled from 'styled-components' -import Slide from '@material-ui/core/Slide'; import Grid from '@material-ui/core/Grid'; import { StyledCard, CardDiv, CardReaDiv, Footer, LikeCounter, ButtonNoWidth, EnviadoPor, TagContainer, HeaderContainer, AvatarDiv } from './ResourceCardFunction.js' import Rating from '@material-ui/lab/Rating'; @@ -46,7 +45,7 @@ export default function CollectionCardFunction(props) { // eslint-disable-next-line const [userAvatar] = useState(props.avatar ? (`${apiDomain}` + props.avatar) : noAvatar) - const [userFollowingCol, toggleUserFollowingCol] = useState(props.followed ? props.followed : false) + const [userFollowingCol, toggleUserFollowingCol] = useState(props.followed) const handleToggleUserFollowingCol = () => { toggleUserFollowingCol(!userFollowingCol) } const [name, setName] = useState(props.name) @@ -193,39 +192,40 @@ export default function CollectionCardFunction(props) { <StyledCard> <CardDiv> <CardReaDiv> - <Header onMouseEnter={controlSlide} onMouseLeave={controlSlide}> - <Slide direction="left" in={slideIn} timeout={1000}> - <div className={`slideContentLinkAfterActive${slideIn}`} style={{ width: '100%', height: "100%" }}> - <Link to={"/colecao-do-usuario/" + props.id} className="text" style={{ textDecoration: "none" }} > - {SlideAnimationContent()} - </Link> + <Link to={"/colecao-do-usuario/" + props.id}> + <Header onMouseEnter={controlSlide} onMouseLeave={controlSlide}> + <div className={`slideContentLinkBeforeActive${slideIn}`} style={{ width: '272.5px', height: '230px' }}> + <UserInfo style={{ width: '272.5px'}}> + {/* I(Luis) dont know why, but if i use styled components, sometimes the avatar will be deconfigured */} + <img src={userAvatar} alt="user avatar" style={{ + height: "70px", width: "70px", borderRadius: "50%", + zIndex: 1, border: "2px solid white", + boxShadow: "0 1px 3px rgba(0,0,0,.45)" + }} /> + <UserAndTitle> + <span>{props.author}</span> + <span className={"col-name"}>{name}</span> + </UserAndTitle> + </UserInfo> + <StyledGrid container direction="row" style={{ width: '272.5px' }}> + { + props.thumbnails.map((thumb) => + <Grid item xs={props.thumbnails.length <= 3 && props.thumbnails.length > 0 ? 12 / props.thumbnails.length : 6}> + <div style={{ backgroundImage: `url(${`${apiDomain}` + thumb})`, height: `${props.thumbnails.length <= 3 ? '230px' : '100%'}`, width: "100%", backgroundSize: "cover", backgroundPosition: "center" }} /> + </Grid> + ) + } + </StyledGrid> </div> - </Slide> - <div className={`slideContentLinkBeforeActive${slideIn}`} style={{ width: '100%', height: '100%' }}> - <UserInfo> - {/* I(Luis) dont know why, but if i use styled components, sometimes the avatar will be deconfigured */} - <img src={userAvatar} alt="user avatar" style={{ - height: "70px", width: "70px", borderRadius: "50%", - zIndex: 1, border: "2px solid white", - boxShadow: "0 1px 3px rgba(0,0,0,.45)" - - }} /> - <UserAndTitle> - <span>{props.author}</span> - <span className={"col-name"}>{name}</span> - </UserAndTitle> - </UserInfo> - <StyledGrid container direction="row"> - { - props.thumbnails.map((thumb) => - <Grid item xs={props.thumbnails <= 4 && props.thumbnails > 0 ? 12 / props.thumbnails.length : 6}> - <div style={{ backgroundImage: `url(${`${apiDomain}` + thumb})`, height: "100%", width: "100%", backgroundSize: "cover", backgroundPosition: "center" }} /> - </Grid> - ) - } - </StyledGrid> - </div> - </Header> + { + <div className={`slideContentLinkAfterActive${slideIn}`} style={{ width: '272.5px', height: '230px' }}> + <div className="text" > + {SlideAnimationContent()} + </div> + </div> + } + </Header> + </Link> <Description> {/*renders rating, number of learning objects and likes count*/} { @@ -297,6 +297,10 @@ export default function CollectionCardFunction(props) { } <ColCardPublicOptions id={props.id} + userFollowingCol={userFollowingCol} + handleLike={handleLike} + handleFollow={handleFollow} + liked={liked} handleLogin={handleLogin} currentUserId={state.currentUser.id} /> @@ -315,8 +319,8 @@ export default function CollectionCardFunction(props) { const SlideContentDiv = styled.div` background-color : #7e57c2; padding : 10px; - width : 100%; - height : 100%; + width : 272.5px; + height : 230px; ` const UserAndTitle = styled.div` diff --git a/src/Components/CollectionCommentSection.js b/src/Components/CollectionCommentSection.js index ccc7f079dae76494734addd6116bdaf6a331ae5d..49f8861e07ab19e2403bad1e0a64fcee929b9f33 100644 --- a/src/Components/CollectionCommentSection.js +++ b/src/Components/CollectionCommentSection.js @@ -16,7 +16,7 @@ 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 React, { useRef, useState, useEffect, Fragment } from 'react'; import { Grid } from '@material-ui/core'; import Card from '@material-ui/core/Card'; import Button from '@material-ui/core/Button'; @@ -27,13 +27,31 @@ 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'; -import {getRequest} from '../Components/HelperFunctions/getAxiosConfig' +import { getRequest } from '../Components/HelperFunctions/getAxiosConfig' +import ExitToAppIcon from '@material-ui/icons/ExitToApp'; +import SignUpModal from './SignUpModal.js'; +import LoginModal from './LoginModal.js'; +import SnackBarComponent from './SnackbarComponent'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import IconButton from '@material-ui/core/IconButton'; +import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown'; 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 [sign_up_open, setSignUpOpen] = useState(false); + const [log_in_open, setLoginOpen] = useState(false); + const [is_loading, setIsLoading] = useState(false); + const [snackInfo, setSnackInfo] = useState({ + open: false, + text: '', + severity: '', + color: '' + }); const [reviews, setReviews] = useState([]); + const [totalReviews, setTotalReviews] = useState(0); + const [currPageReviews, setCurrPageReviews] = useState(0); const comment_ref = useRef(null); const forceUpdate = () => { setRenderState(!render_state); } @@ -50,30 +68,74 @@ export default function CollectionCommentSection(props) { window.scrollTo(0, comment_ref.current.offsetTop); } + function handleOpenSnackSignIn() { + const info = { + open: true, + text: 'Você foi logado com sucesso!', + severity: 'success', + color: '', + } + + handleSnackInfo(info) + } + + function handleSnackInfo(info) { + setSnackInfo({ + ...info + }) + } + + function handleCloseSnack() { + setSnackInfo({ + open: false, + text: '', + severity: '', + color: '', + }) + } + + function handleOpenSignUp() { + setSignUpOpen(true) + } + function Alert(props) { return <MuiAlert elevation={6} variant="filled" {...props} />; } + function handleLoadMoreReviews() { + if (reviews.length !== parseInt(totalReviews)) + setCurrPageReviews((previous) => previous + 1) + else { + const info = { + open: true, + text: 'Não há mais comentários para carregar.', + severity: 'warning', + color: '', + } + handleSnackInfo(info) + } + } + const NoCommentsMessage = () => { - const NoCommentsContainer=styled.div` + const NoCommentsContainer = styled.div` text-align: center; margin-left: 9vw; margin-right: 9vw; ` - const BlueTitle=styled.h2` + const BlueTitle = styled.h2` color: #673ab7; ` - const Secondary=styled.h3` + const Secondary = styled.h3` font-weight: 100; ` - const ButtonText=styled.span` + const ButtonText = styled.span` font-weight: 900; ` - const Image=styled.img` + const Image = styled.img` ` return ( <NoCommentsContainer> - <Image src={Comentario} style={{width:"100%", maxWidth:234}}/> + <Image src={Comentario} style={{ width: "100%", maxWidth: 234 }} /> <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 @@ -89,78 +151,227 @@ export default function CollectionCommentSection(props) { } const CollectionComments = () => { return ( - <div> - <Title>{reviews.length} {reviews.length === 1 ? "Relato" : "Relatos"} sobre a Coleção</Title> + <ComentariosBox> + <h3>{totalReviews} {totalReviews !== 1 ? 'Relatos' : 'Relato'} sobre o uso do Recurso</h3> {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> + <div className="comentario-template" key={r.created_at}> + <Comment + isCollection={false} + 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} + handlePost={handlePostSnackbar} + recurso={false} + /> + </div> + ); + })} + <div className="load-more"> + <IconButton className="button" onClick={handleLoadMoreReviews}> + <KeyboardArrowDownIcon /> + </IconButton> + </div> + </ComentariosBox> ); } + function handleSuccessGet(data, headers) { + setReviews((previousState) => previousState.concat(data)); + if (headers.has('X-Total-Count')) + setTotalReviews(headers.get('X-Total-Count')) + setIsLoading(false); + } + + function handleFailGet(error) { + setIsLoading(false) + } + useEffect(() => { - getRequest(`/collections/${props.id}/reviews`, (data) => {setReviews(data)}, (error) => {console.log(error)}) - }, [render_state]); + setIsLoading(true) + getRequest( + `/collections/${props.id}/reviews?page=${currPageReviews}`, + handleSuccessGet, + (error) => { handleFailGet(error) } + ) + }, [render_state, currPageReviews]); return ( <CommentAreaContainer container xs={12} direction="row" justify="center" alignItems="center"> + <SnackBarComponent + snackbarOpen={snackInfo.open} + handleClose={handleCloseSnack} + severity={snackInfo.severity} + text={snackInfo.text} + color={snackInfo.color} + /> + <SignUpModal + open={sign_up_open} + handleClose={() => setSignUpOpen(false)} + openLogin={() => setLoginOpen(true)} + /> + <LoginModal + openSnackbar={handleOpenSnackSignIn} + open={log_in_open} + handleClose={() => setLoginOpen(false)} + openSignUp={handleOpenSignUp} + /> <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()} + { + props.currentUserId ? + <Fragment> + <Title>Conte sua experiência com a coleção</Title> + <Grid container style={{ paddingTop: "20px" }} spacing={1}> + <Grid item xs={12} sm={2} style={{ paddingLeft: "15px", paddingRight: "15px" }}> + <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}> + <Avatar src={props.avatar} alt="user avatar" /> + </div> + </Grid> + <Grid item xs={12} sm={10}> + <CommentForm + colecao + recursoId={props.id} + handleSnackbar={handlePostSnackbar} + rerenderCallback={forceUpdate} + /> + </Grid> + </Grid> + </Fragment> + : + <Grid item xs={12}> + <LogInToComment> + <span className="span-purple">Você precisa entrar para comentar</span> + <Button onClick={() => setSignUpOpen(true)} style={{ textTransform: "uppercase", color: "#666", fontWeight: "700" }}> + <ExitToAppIcon />ENTRAR + </Button> + </LogInToComment> + </Grid> + } + { + is_loading ? + <LoadingDiv> + <CircularProgress className="loading" /> + </LoadingDiv> + : + reviews.length ? CollectionComments() : NoCommentsMessage() + } </CommentAreaCard> </Grid> <Snackbar open={post_snack_open} autoHideDuration={6000} onClose={handlePostSnackbar} - anchorOrigin={{vertical: 'top', horizontal: 'right'}} + anchorOrigin={{ vertical: 'top', horizontal: 'right' }} > - <Alert onClose={handlePostSnackbar} severity="info"> + <Alert onClose={handlePostSnackbar} severity="info"> Seu comentário foi publicado com sucesso! </Alert> - </Snackbar> + </Snackbar> <Snackbar open={delete_snack_open} autoHideDuration={6000} onClose={handleDeleteSnackbar} - anchorOrigin={{vertical: 'top', horizontal: 'right'}} + anchorOrigin={{ vertical: 'top', horizontal: 'right' }} > - <Alert onClose={handleDeleteSnackbar} severity="info"> + <Alert onClose={handleDeleteSnackbar} severity="info"> Comentário deletado com sucesso. </Alert> - </Snackbar> + </Snackbar> </CommentAreaContainer> ); } +const ComentariosBox = styled.div` + display : flex; + flex-direction : column; + padding : 20px; + width : 100%; + + h3 { + font-family: 'Roboto Light','Roboto Regular',Roboto; + font-weight: 300; + font-style: normal; + color:#666; + font-size: 1.857em; + margin: 15px 2%; + text-align : flex-start; + } + + .comentario-template { + margin-top: 5px; + padding : 20px 0; + border-bottom : 1px solid #f4f4f4; + } + + .load-more{ + width: 100%; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + } + + .button{ + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + } +` + +const Avatar = styled.img` + height: 60px; + width: 60px; + border-radius: 50%; + margin-left: 2%; + margin-top: 5%; +` + +const LoadingDiv = styled.div` + margin: 1em; + display: flex; + justify-content: center; + align-items: center; + .loading{ + color: #673ab7; + size: 24px; + } +` + +const LogInToComment = styled.div` + display : flex; + flex-direction : column; + text-align : center; + padding : 20px; + align-items : center; + + .span-purple { + font-size : 24px; + font-weight : 700; + padding-bottom : 5px; + color : #673ab7; + } + + img { + object-fit : contain !important; + background-color : transparent !important; + } +` -const CommentAreaContainer=styled(Grid)` - margin-left: 10%; - margin-right: 10%; +const CommentAreaContainer = styled(Grid)` + padding: 10px; ` -const CommentAreaCard=styled(Card)` +const CommentAreaCard = styled(Card)` padding: 45px; ` -const Title=styled.h1` +const Title = styled.h1` + text-align: center; font-weight: 100; color: #666; ` diff --git a/src/Components/CollectionDescription.js b/src/Components/CollectionDescription.js index aa35cb0df4909fa3205678aa145bc1e02f2802ad..60de747f5bb7c17d9dff5d1a9acb2f69d8c95808 100644 --- a/src/Components/CollectionDescription.js +++ b/src/Components/CollectionDescription.js @@ -30,35 +30,40 @@ export default function CollectionDescription(props) { useEffect(() => { const body = { "package": { - "object": [{"type": "Collection", "id": props.collection_id}] - }}; + "object": [{ "type": "Collection", "id": props.collection_id }] + } + }; axios - .post(apiUrl+'/package', body) + .post(apiUrl + '/package', body) .catch(err => { if (err.response && err.response.status === 302) { - setDownloadUrl(apiDomain+'/'+err.response.data.url); + setDownloadUrl(apiDomain + '/' + err.response.data.url); } - });}, [props.collection_id]); + }); + }, [props.collection_id]); return ( <Grid container direction="column" justify="center" alignItems="center" spacing={5}> - <Grid - item + <Grid + item justify="center" alignItems="center" > <Title>{props.title}</Title> </Grid> - <Grid + <Grid item - direction="row" - justify="center" + direction="row" + justify="center" alignItems="center" > <Grid item> - <CollectionReview + <CollectionReview + stars={props.stars} + liked={props.liked} + likes={props.likes} scrollToComment={props.scrollToComments} - id={props.collection_id}/> + id={props.collection_id} /> </Grid> {/* <Grid item container sm={8} direction="column" justify="center" alignItems="flex-end" @@ -85,7 +90,7 @@ export default function CollectionDescription(props) { ); } -const Title=styled.h1` +const Title = styled.h1` font-size: 2.5em; color: rgb(102, 102, 102); text-align: center diff --git a/src/Components/CollectionDowloadButton.js b/src/Components/CollectionDowloadButton.js index d7820da26c20262c585c60eff2723a2d5bc78b52..bda45946d26e9fb373ba79d5e006d4cacb5bb495 100644 --- a/src/Components/CollectionDowloadButton.js +++ b/src/Components/CollectionDowloadButton.js @@ -5,29 +5,62 @@ import Button from '@material-ui/core/Button'; import styled from 'styled-components'; import { apiUrl, apiDomain } from '../env'; import { getRequest } from './HelperFunctions/getAxiosConfig' +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; +function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; +} const DowloadButton = (props) => { const [download_url, setDownloadUrl] = useState(''); + const [snackInfo, setSnackInfo] = useState({ + open: false, + text: "", + severity: "", + }); useEffect(() => { - const body = { - "package": { - "object": [{ "type": "Collection", "id": props.id }] - } - }; - axios - .post(apiUrl + '/package', body) - .catch(err => { - if (err.response && err.response.status === 302) { - setDownloadUrl(apiDomain + '/' + err.response.data.url); + if (props.id && props.id !== "0") { + const body = { + "package": { + "object": [{ "type": "Collection", "id": props.id }] } - }); + }; + axios + .post(apiUrl + '/package', body) + .catch(err => { + if (err.response && err.response.status === 302) { + setDownloadUrl(apiDomain + '/' + err.response.data.url); + } + }); + } + }, [props.id]); - const handleDowloadCollection = () => { + const handleDowloadCollection = (e) => { // there is no error controller here because the router ///:type/:id/download is always returning error + e.preventDefault() + + let snackInfo = {} + if (download_url) { + window.open(download_url, '_blank') + snackInfo = { + open: true, + text: "A coleção está sendo baixada...", + severity: "success", + } + handleSnackInfo(snackInfo) + } + else { + snackInfo = { + open: true, + text: "Não foi possÃvel baixar a coleção", + severity: "warning", + } + handleSnackInfo(snackInfo) + } getRequest( `/collections/${props.id}/download`, (data, header) => { @@ -37,18 +70,40 @@ const DowloadButton = (props) => { ) } + const handleSnackInfo = (info) => { + setSnackInfo({ ...info }) + } + + const handleCloseSnack = () => { + const snackInfo = { + open: false, + text: "", + severity: "", + } + handleSnackInfo(snackInfo) + } + return ( <> - <DownloadAnchor href={download_url} > - <DownloadButton - variant="outlined" - color="primary" - startIcon={<GetAppIcon fontSize="large" />} - size="small" - > - <ButtonText onClick={handleDowloadCollection}>Baixar Coleção</ButtonText> - </DownloadButton> - </DownloadAnchor> + <Snackbar + open={snackInfo.open} + autoHideDuration={6000} + onClose={handleCloseSnack} + anchorOrigin={{ vertical: 'top', horizontal: 'right' }} + > + <Alert onClose={handleCloseSnack} severity={snackInfo.severity}> + {snackInfo.text} + </Alert> + </Snackbar> + <DownloadButton + variant="outlined" + color="primary" + startIcon={<GetAppIcon fontSize="large" />} + size="small" + onClick={handleDowloadCollection} + > + <ButtonText>Baixar Coleção</ButtonText> + </DownloadButton> </> ) } @@ -62,8 +117,5 @@ const DownloadButton = styled(Button)` padding-right: 10; width: 250px; ` -const DownloadAnchor = styled.a` - text-decoration: none !important; -` export default DowloadButton; diff --git a/src/Components/CollectionReview.js b/src/Components/CollectionReview.js index c9dc801016a770dd65acd4378c9db395b6c4d945..0d94757b2dbd235e2b3b9ef2b8077707b8a9a357 100644 --- a/src/Components/CollectionReview.js +++ b/src/Components/CollectionReview.js @@ -27,31 +27,30 @@ import { Store } from '../Store.js' import ReportModal from './ReportModal.js'; import SignUpModal from './SignUpModal.js'; import LoginModal from './LoginModal.js'; -import { putRequest, getRequest } from './HelperFunctions/getAxiosConfig.js' +import { putRequest } from './HelperFunctions/getAxiosConfig.js' +import SnackBarComponent from './SnackbarComponent'; export default function CollectionReview(props) { - const [likes, setLikes] = useState(0); - const [liked, setLiked] = useState(false); - const [stars, setStars] = useState(0); + const { state } = useContext(Store); + + const [likes, setLikes] = useState(); + const [liked, setLiked] = useState(); + const [stars, setStars] = useState(); const [reportOpen, setReportOpen] = useState(false); const [sign_up_open, setSignUpOpen] = useState(false); const [log_in_open, setLoginOpen] = useState(false); - const { state } = useContext(Store); - - function handleSuccessfulGet(data) { - setLikes(Number(data.likes_count)); - setLiked(data.liked); - } - - useEffect(() => { - const url = `/collections/${props.id}` - - getRequest(url, handleSuccessfulGet, (error) => { console.log(error) }) - - }, [props.id, state.currentUser.id]); + const [snackInfo, setSnackInfo] = useState({ + open: false, + text: '', + severity: '', + color: '' + }); const handleClickReport = () => { - setReportOpen(true); + if (state.currentUser.id) + setReportOpen(true); + else + setSignUpOpen(true) } function handleSuccess(data) { @@ -67,24 +66,62 @@ export default function CollectionReview(props) { setSignUpOpen(true); } - const handleSetStars = (value) => { - setStars(value); - props.scrollToComment(); - } - const handleCloseModal = () => { setReportOpen(false); } + function handleOpenSnackSignIn() { + const info = { + open: true, + text: 'Você foi logado com sucesso!', + severity: 'success', + color: '', + } + + handleSnackInfo(info) + } + + function handleSnackInfo(info) { + setSnackInfo({ + ...info + }) + } + + function handleCloseSnack() { + setSnackInfo({ + open: false, + text: '', + severity: '', + color: '', + }) + } + + function handleOpenSignUp() { + setSignUpOpen(true) + } + + useEffect(() => { + setLiked(props.liked) + setLikes(props.likes) + setStars(props.stars) + }, [props]) + return ( <Grid container direction="column"> + <SnackBarComponent + snackbarOpen={snackInfo.open} + handleClose={handleCloseSnack} + severity={snackInfo.severity} + text={snackInfo.text} + color={snackInfo.color} + /> <Grid sm={12} container direction="row" alignItems="center"> <Grid item> <Rating name="customized-empty" - value={stars} - onChange={(e, value) => handleSetStars(value)} - precision={0.5} + value={Number(stars)} + readOnly + onClick={props.scrollToComment} style={{ color: "#666" }} emptyIcon={<StarBorderIcon fontSize="inherit" />} /> @@ -116,8 +153,10 @@ export default function CollectionReview(props) { openLogin={() => setLoginOpen(true)} /> <LoginModal + openSnackbar={handleOpenSnackSignIn} open={log_in_open} handleClose={() => setLoginOpen(false)} + openSignUp={handleOpenSignUp} /> </Grid> ); diff --git a/src/Components/Comment.js b/src/Components/Comment.js index 09b66d5ad2f83e4ad3f10994de899960ca4f1b49..4388ec758a2cdc81a97f8b61f7fb3765b3ef5805 100644 --- a/src/Components/Comment.js +++ b/src/Components/Comment.js @@ -16,13 +16,13 @@ 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 {Store} from '../Store.js' +import React, { useState, useContext } from 'react' +import { Store } from '../Store.js' import styled from 'styled-components' import Grid from '@material-ui/core/Grid'; import { Button } from '@material-ui/core'; -import {Link} from 'react-router-dom' -import {apiDomain} from '../env'; +import { Link } from 'react-router-dom' +import { apiDomain } from '../env'; import noAvatar from "../img/default_profile.png"; import Rating from '@material-ui/lab/Rating'; import StarBorderIcon from '@material-ui/icons/StarBorder'; @@ -31,10 +31,10 @@ import TextField from "@material-ui/core/TextField"; import Menu from '@material-ui/core/Menu'; import MenuItem from '@material-ui/core/MenuItem'; import ModalExcluir from './ModalExcluirComentario.js' -import {putRequest, deleteRequest} from './HelperFunctions/getAxiosConfig' - -export default function Comment (props) { +import { putRequest, deleteRequest } from './HelperFunctions/getAxiosConfig' +export default function Comment(props) { + console.log(props) /* Required props: rerenderCallback = callback function to trigger re-render on parent component @@ -52,7 +52,7 @@ export default function Comment (props) { */ var moment = require('moment') - const {state} = useContext(Store) + const { state } = useContext(Store) const [displayedComment, setDisplayedComment] = useState(props.description) const [editando, setEditando] = useState(false) const [anchorEl, setAnchorEl] = React.useState(null); @@ -65,177 +65,204 @@ export default function Comment (props) { const [modalOpen, toggleModal] = useState(false) const [comment, setComment] = useState({ - error : false, - value : props.description + error: false, + value: props.description }) const handleChange = (e) => { const userInput = e.target.value const flag = (userInput.length === 0 ? true : false); - setComment({...comment, error : flag, value : userInput}) + setComment({ ...comment, error: flag, value: userInput }) } - function handleOnSuccessfulComment (data) { + function handleOnSuccessfulComment(data) { setDisplayedComment(comment.value) setEditando(false) - props.handleSnackbar(2) + props.handlePost() } const updateComment = () => { const finalComment = comment + let url; + + if (props.isCollection) + url = `/collections/${props.objectID}/reviews/${props.reviewID}` + else + url = `/learning_objects/${props.objectID}/reviews/${props.reviewID}` + if (!finalComment.error) { let payload = { - "review" : { - "name":null, - "description":finalComment.value, - "pros":null, - "cons":null, - "review_ratings_attributes" : props.reviewRatings + "review": { + "description": finalComment.value, + "review_ratings_attributes": props.reviewRatings } } - putRequest(`/learning_objects/${props.objectID}/reviews/`, payload, handleOnSuccessfulComment, (error) => {console.log(error)}) + putRequest(url, payload, handleOnSuccessfulComment, (error) => { console.log(error) }) } } - function handleSuccessDeleteComment (data) { + function handleSuccessDeleteComment(data) { props.rerenderCallback() props.handleSnackbar(3) } const deleteComment = () => { + let url; + + if (props.isCollection) + url = `/collections/${props.objectID}/reviews/${props.reviewID}` + else + url = `/learning_objects/${props.objectID}/reviews/${props.reviewID}` - deleteRequest(`/learning_objects/${props.objectID}/reviews/${props.reviewID}`, handleSuccessDeleteComment, (error) => {console.log(error)}) + deleteRequest(url, handleSuccessDeleteComment, (error) => { console.log(error) }) toggleModal(false) } - - return ( - <React.Fragment> - <ModalExcluir - open={modalOpen} handleClose={() => {toggleModal(false)}} - handleConfirm={deleteComment} - /> - <Grid container style={{paddingLeft : "20px"}}> - - <Grid item xs={1}> - { - props.authorID && - <AvatarDiv> - <Link to={'/usuario-publico/' + props.authorID}> - <img src={props.authorAvatar ? apiDomain + props.authorAvatar : noAvatar} alt="author avatar"/> - </Link> - </AvatarDiv> - } - </Grid> - - <Grid item xs={10}> - <Comentario> - <div className="star-rating-container"> - <Rating - name="read-only" - value={props.rating} - readOnly - size="small" - style={{color:"#666"}} - emptyIcon={<StarBorderIcon fontSize="inherit" style={{color : "#a5a5a5"}} />} - /> - </div> - - { - props.name && - <strong>{props.name}</strong> - } - - - <div> + if (props.authorID) + return ( + <React.Fragment> + <ModalExcluir + open={modalOpen} handleClose={() => { toggleModal(false) }} + handleConfirm={deleteComment} + /> + <Grid container style={{ paddingLeft: "20px" }}> + + <Grid item xs={1}> { - editando ? - ( - <React.Fragment> - <div style={{marginTop : "5%", padding : "2px"}}> - <StyledTextField - colecao={!props.recurso} - id = "input-comentario" - label = {"Editar Comentário"} - margin = "normal" - value = {comment.value} - multiline={true} - rows="5" - onChange = {(e) => {handleChange(e)}} - style={{width:"100%"}} - /> - </div> - <div style={{float : "right"}}> - <StyledButton - style={props.recurso ? {backgroundColor : "#ff7f00"} : {backgroundColor : "#673ab7"}} - onClick={() => {setEditando(false)}} - > - Fechar + props.authorID && + <AvatarDiv> + <Link to={'/usuario-publico/' + props.authorID}> + <img src={props.authorAvatar ? apiDomain + props.authorAvatar : noAvatar} alt="author avatar" /> + </Link> + </AvatarDiv> + } + </Grid> + + <Grid item xs={10}> + <Comentario> + <div className="star-rating-container"> + <Rating + name="read-only" + value={props.rating} + readOnly + size="small" + style={{ color: "#666" }} + emptyIcon={<StarBorderIcon fontSize="inherit" style={{ color: "#a5a5a5" }} />} + /> + </div> + + { + props.name && + <strong>{props.name}</strong> + } + + <div> + { + editando ? + ( + <React.Fragment> + <div style={{ marginTop: "5%", padding: "2px" }}> + <StyledTextField + colecao={!props.recurso} + id="input-comentario" + label={"Editar Comentário"} + margin="normal" + value={comment.value} + multiline={true} + rows="5" + onChange={(e) => { handleChange(e) }} + style={{ width: "100%" }} + /> + </div> + <div style={{ float: "right" }}> + <StyledButton + style={props.recurso ? { backgroundColor: "#ff7f00" } : { backgroundColor: "#673ab7" }} + onClick={() => { setEditando(false) }} + > + Fechar </StyledButton> - <StyledButton - style={props.recurso ? {backgroundColor : "#ff7f00"} : {backgroundColor : "#673ab7"}} - onClick={() => updateComment()} - > - Salvar + <StyledButton + style={props.recurso ? { backgroundColor: "#ff7f00" } : { backgroundColor: "#673ab7" }} + onClick={() => updateComment()} + > + Salvar </StyledButton> - </div> - </React.Fragment> - ) - : - ( - <React.Fragment> - <p> - { - props.authorID && - <Link - to={'/usuario-publico/' + props.authorID} - style={{ - fontWeight : "bolder", - color : props.recurso ? "#ff7f00" : "#673ab7" - }} - > - {props.authorName} - </Link> - } + </div> + </React.Fragment> + ) + : + ( + <React.Fragment> + <p> + { + props.authorID && + <Link + to={'/usuario-publico/' + props.authorID} + style={{ + fontWeight: "bolder", + color: props.recurso ? "#ff7f00" : "#673ab7" + }} + > + {props.authorName} + </Link> + } : {displayedComment} - </p> - { - props.authorID !== state.currentUser.id && - <span className="date"> - {moment(props.createdAt).format("DD/MM/YYYY")} - </span> - } - </React.Fragment> - ) - } - </div> + </p> + <span className="date"> + {moment(props.createdAt).format("DD/MM/YYYY")} + </span> + </React.Fragment> + ) + } + </div> + + </Comentario> + </Grid> - </Comentario> - </Grid> + { + props.authorID === state.currentUser.id && + <Grid item xs={1}> + <StyledDiv> + <Button onClick={handleClick}><EditIcon /></Button> + <Menu + id="simple-menu" + anchorEl={anchorEl} + keepMounted + open={Boolean(anchorEl)} + onClose={handleClose} + > + <MenuItem onClick={() => { setEditando(true); handleClose() }}>Editar</MenuItem> + <MenuItem onClick={() => { toggleModal(true); handleClose() }}>Excluir</MenuItem> + </Menu> + </StyledDiv> + </Grid> + } + </Grid> + </React.Fragment> + ) + else + return ( + <Grid container style={{ paddingLeft: "20px" }} justify='center' alignItems='center '> - { - props.authorID === state.currentUser.id && <Grid item xs={1}> - <StyledDiv> - <Button onClick={handleClick}><EditIcon/></Button> - <Menu - id="simple-menu" - anchorEl={anchorEl} - keepMounted - open={Boolean(anchorEl)} - onClose={handleClose} - > - <MenuItem onClick={() => {setEditando(true); handleClose()}}>Editar</MenuItem> - <MenuItem onClick={() => {toggleModal(true);handleClose()}}>Excluir</MenuItem> - </Menu> - </StyledDiv> + { + <AvatarDiv> + <img src={noAvatar} alt="author avatar" /> + </AvatarDiv> + } </Grid> - } - </Grid> - </React.Fragment> - ) + + <Grid item xs={10}> + <Comentario> + <p> + O usuário que fez esse comentário deletou a conta. + </p> + </Comentario> + </Grid> + </Grid> + ) } const StyledTextField = styled(TextField)` @@ -265,9 +292,7 @@ const StyledButton = styled(Button)` ` const Comentario = styled.div` - @media screen and (max-width: 990px) { - padding-left : 55px !important; - } + padding-left : 55px !important; font-size : 14px; .star-rating-container { diff --git a/src/Components/FloatingDownloadButton.js b/src/Components/FloatingDownloadButton.js index 96537210b046c1d0fc841ec4016e16c52e12c3c1..dcd9db430c7d96705bd4dc91e5295710a5642c21 100644 --- a/src/Components/FloatingDownloadButton.js +++ b/src/Components/FloatingDownloadButton.js @@ -16,54 +16,24 @@ 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 React from 'react'; import styled from 'styled-components'; 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); - } +export default function FloatingDownloadButton(props) { 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> + <FloatingDownload + color="primary" + aria-label="download" + onClick={props.handleDownloadSelection} + > + <GetAppIcon /> + </FloatingDownload> ); } -const DownloadAnchor=styled.a` - text-decoration: none !important; -` - -const FloatingDownload=styled(Fab)` +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 index 974a56fd3492cf7440b46679794fb061ea237e7a..e89f8901c0e586124c99df453dc70ac627027f63 100644 --- a/src/Components/FollowCollectionButton.js +++ b/src/Components/FollowCollectionButton.js @@ -16,7 +16,7 @@ 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, useContext } from 'react'; +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'; @@ -24,13 +24,12 @@ import styled from 'styled-components'; import SignUpModal from './SignUpModal.js'; import LoginModal from './LoginModal'; import SnackBarComponent from './SnackbarComponent'; -import { getRequest, putRequest } from './HelperFunctions/getAxiosConfig' -import { Store } from '../Store' +import { putRequest } from './HelperFunctions/getAxiosConfig' export default function FollowCollectionButton(props) { - const { state } = useContext(Store) + const [icon, setIcon] = useState(<AddIcon fontSize="large" />); - const [button_text, setButtonText] = useState("Seguir Coleção"); + const [button_text, setButtonText] = useState("Seguir coleção"); const [variant, setVariant] = useState("outlined"); const [sign_up_open, setSignUpOpen] = useState(false); const [open_login, setOpenLogin] = useState(false); @@ -42,51 +41,20 @@ export default function FollowCollectionButton(props) { }); const [following, setFollowing] = useState(false); //user following collection - function handleSuccessGet(data) { - if (!data.errors) - data.map((e) => { - if (e["followable"]["id"] === Number(props.collection_id)) { - setVariant("contained"); - setButtonText("Seguindo"); - setIcon(<CheckIcon fontSize="large" />) - setFollowing(true); - } - return undefined - }) - else { - const info = { - open: true, - text: 'Falha ao verificar se o usuário segue a coleção!', - severity: 'error', - color: 'red' - } - - handleSnackInfo(info) - } - } useEffect(() => { - if (state.currentUser.id) { - const url = `/users/${props.user_id}/following/Collection` - getRequest( - url, - handleSuccessGet, - (error) => { - const info = { - open: true, - text: 'Falha ao verificar se o usuário segue a coleção!', - severity: 'error', - color: 'red' - } - handleSnackInfo(info) - }) + if (props.followed) { + setFollowing(true) + setButtonText("Seguindo") + setVariant("contained") + setIcon(<CheckIcon fontSize="large" />); } else { - setIcon(<AddIcon fontSize="large" />) - setButtonText("Seguir Coleção") - setVariant("outlined") setFollowing(false) + setButtonText("Seguir coleção") + setVariant("outlined") + setIcon(<AddIcon fontSize="large" />); } - }, [state.currentUser.id]); + }, [props]) //handleMouse{Enter, Leave} only do anything when user follows given collection: const handleMouseEnter = () => { diff --git a/src/Components/Header.js b/src/Components/Header.js index 57cc42f248418e141996fa0023bb6793938441a2..54e02feaa381434678d74c13bb418de8fa126924 100644 --- a/src/Components/Header.js +++ b/src/Components/Header.js @@ -54,7 +54,7 @@ export default function Header(props) { } useEffect(() => { - if (sessionStorage.getItem('@portalmec/auth_headers')) { + if (localStorage.getItem('@portalmec/auth_headers')) { const url = `/auth/validate_token/` getRequest(url, handleSuccessValidateToken, (error) => { console.log(error) }) } diff --git a/src/Components/HelperFunctions/getAxiosConfig.js b/src/Components/HelperFunctions/getAxiosConfig.js index 6d1608bc91648d8b83374f9c4949a9ada3401cdd..8ced7d5be70b3d08d7b2cb3f7864f801b8c2d484 100644 --- a/src/Components/HelperFunctions/getAxiosConfig.js +++ b/src/Components/HelperFunctions/getAxiosConfig.js @@ -2,16 +2,18 @@ import {apiUrl} from '../../env.js' export function getAxiosConfigFromJSON () { let config = { - headers : JSON.parse(sessionStorage.getItem('@portalmec/auth_headers')) + headers : JSON.parse(localStorage.getItem('@portalmec/auth_headers')) } return config } export function updateHeaders (newHeaders) { - sessionStorage.setItem('@portalmec/accessToken', newHeaders['access-token']) + let newToken = getNewAccessToken(newHeaders['access-token']) - let auth_headers = JSON.parse(sessionStorage.getItem('@portalmec/auth_headers')) + localStorage.setItem('@portalmec/accessToken', newToken) + + let auth_headers = JSON.parse(localStorage.getItem('@portalmec/auth_headers')) /*const auth_headers = { client: newHeaders.get('client'), "access-token": newHeaders.get('access-token'), @@ -20,7 +22,7 @@ export function updateHeaders (newHeaders) { "token-type": "Bearer" } - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers))*/ + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers))*/ if (auth_headers) { auth_headers['access-token'] = newHeaders['access-token'] } @@ -33,11 +35,11 @@ export function updateHeaders (newHeaders) { "token-type": "Bearer" } } - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) } function fetchHeaders () { - let auth_headers = JSON.parse(sessionStorage.getItem('@portalmec/auth_headers')) + let auth_headers = JSON.parse(localStorage.getItem('@portalmec/auth_headers')) var myHeaders = undefined if (auth_headers) { @@ -58,12 +60,12 @@ function fetchHeaders () { function checkPreviousTokens (new_token) { - let prev_tokens = JSON.parse(sessionStorage.getItem('@portalmec/tokens')) + let prev_tokens = JSON.parse(localStorage.getItem('@portalmec/tokens')) if (prev_tokens) { if (!prev_tokens.hasOwnProperty(new_token)) { prev_tokens[new_token] = 1 - sessionStorage.setItem('@portalmec/tokens', JSON.stringify(prev_tokens)) + localStorage.setItem('@portalmec/tokens', JSON.stringify(prev_tokens)) return true } else { @@ -73,25 +75,36 @@ function checkPreviousTokens (new_token) { else { let tokens = {} tokens[new_token] = 1 - sessionStorage.setItem('@portalmec/tokens', JSON.stringify(tokens)) + localStorage.setItem('@portalmec/tokens', JSON.stringify(tokens)) return true } } +function getNewAccessToken (newAccessToken) { + if (!newAccessToken || newAccessToken.trim().length === 0) { + return localStorage.getItem('@portalmec/accessToken') + } + else { + return newAccessToken + } +} + + function updateAccessToken (newAccessToken) { + let newToken = getNewAccessToken(newAccessToken) - if (checkPreviousTokens(newAccessToken)) { + if (checkPreviousTokens(newToken)) { - sessionStorage.setItem('@portalmec/accessToken', newAccessToken) + localStorage.setItem('@portalmec/accessToken', newToken) - let auth_headers = JSON.parse(sessionStorage.getItem('@portalmec/auth_headers')) + let auth_headers = JSON.parse(localStorage.getItem('@portalmec/auth_headers')) if (auth_headers) { - auth_headers['access-token'] = newAccessToken + auth_headers['access-token'] = newToken } - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) } } @@ -263,7 +276,8 @@ export const validateGoogleLoginToken = (url, config, onSuccess, onError) => { "token-type": "Bearer" } - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/accessToken', auth_headers["access-token"]) return response.json().catch(err => { return {}; @@ -297,7 +311,8 @@ export async function authentication (url, payload, onSuccess, onError) { "token-type": "Bearer" } - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/accessToken', auth_headers["access-token"]) let json = await response.json().catch(err => { return {}; @@ -317,7 +332,7 @@ export async function authentication (url, payload, onSuccess, onError) { // "token-type": "Bearer" // } // - // sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + // localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) // // return response.json().catch(err => { // return {}; diff --git a/src/Components/HomeScreenSearchBar.js b/src/Components/HomeScreenSearchBar.js index ef12b7cc21d761f9ac73d634d1a4e24fe180bd0d..634b625e1c487e585f97ed95965fe5b53d87a175 100644 --- a/src/Components/HomeScreenSearchBar.js +++ b/src/Components/HomeScreenSearchBar.js @@ -92,9 +92,9 @@ export default function HomeScreenSearchBar(props) { const WIDTH = window.innerWidth; return ( - - <StyledGrid container> - {goSearch && <Redirect to={`/busca?query=${state.search.query}&search_class=${state.search.class}`} />} + + <StyledGrid container> + {goSearch && <Redirect to={`/busca?page=0&results_per_page=12&order=review_average&query=${state.search.query}&search_class=${state.search.class}`} />} <Grid item md={7} xs={12} className="first white"> <StyledTextField id="standard-search" diff --git a/src/Components/MenuBar.js b/src/Components/MenuBar.js index 7cf1153b7bdf834d4694b1d7367df27fbc9319ca..c79d52b6f2cefa5ccf8b2e9ab5b65c5db26a5883 100644 --- a/src/Components/MenuBar.js +++ b/src/Components/MenuBar.js @@ -127,6 +127,14 @@ export default function MenuBar(props) { href: "/admin/home", value: '6', }) + + const canUserCurator = (elem) => elem.id === 4 + if (userRoles.some(canUserCurator)) + minhaArea.push({ + name: "Curadoria", + href: "/perfil", + value: '5', + }) } return minhaArea; @@ -175,8 +183,7 @@ export default function MenuBar(props) { <CloudUploadIcon style={{ color: "white", marginLeft: "0" }} /> <span style={{ color: "#fff", textAlign: "center", alignSelf: "center", fontWeight: "500" }} > PUBLICAR RECURSO - </span> - + </span> </ButtonPublicarRecurso> </Link> </div> diff --git a/src/Components/MobileDrawerMenu.js b/src/Components/MobileDrawerMenu.js index 654ee7b9154f7fd34b15c8b36ee0c163e301f45f..f99498f24c46eec01ff1b6aa6ee1f20bbe8d4197 100644 --- a/src/Components/MobileDrawerMenu.js +++ b/src/Components/MobileDrawerMenu.js @@ -33,6 +33,7 @@ import DefaultAvatar from '../img/default_profile0.png' import SettingsIcon from '@material-ui/icons/Settings'; import { apiDomain } from '../env.js' import { deleteRequest } from './HelperFunctions/getAxiosConfig' +import CloudUploadIcon from '@material-ui/icons/CloudUpload'; export default function MobileDrawerMenu(props) { const { state, dispatch } = useContext(Store) @@ -64,6 +65,14 @@ export default function MobileDrawerMenu(props) { href: "/admin/home", value: '6', }) + + const canUserCurator = (elem) => elem.id === 4 + if (userRoles.some(canUserCurator)) + minhaArea.push({ + name: "Curadoria", + href: "/perfil", + value: '5', + }) } return minhaArea; @@ -126,33 +135,43 @@ export default function MobileDrawerMenu(props) { { /*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> + ( + <> + <div style={{ display: "flex", justifyContent: "left", marginBottom: "10px" }}> + <Link to="/termos-publicar-recurso"> + <ButtonPublicarRecurso> + <CloudUploadIcon style={{ color: "white", marginRight: "10px" }} /> + <span style={{ color: "white", textAlign: "center", alignSelf: "center", fontWeight: "500" }} > + PUBLICAR RECURSO + </span> + </ButtonPublicarRecurso> + </Link> + </div> + <div style={{ borderTop: "1px solid #e5e5e5", display: "flex", flexDirection: "column", marginTop: "10px", paddingTop: "10px", 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> + </> ) : ( @@ -160,7 +179,7 @@ export default function MobileDrawerMenu(props) { <div style={{ display: "flex", justifyContent: "center", marginTop: "10px" }}> <ButtonPublicarRecurso onClick={props.openLogin}> PUBLICAR RECURSO? - </ButtonPublicarRecurso> + </ButtonPublicarRecurso> </div> <div style={{ display: "flex", flexDirection: "row", margin: "10px 0", justifyContent: "center" }}> @@ -228,6 +247,7 @@ const MyArea = styled.div` const ButtonPublicarRecurso = styled(Button)` font-weight : 500 !important; border : 1.5px #666 solid !important; + background-color : #ff7f00 !important; color: #666; box-shadow: none; margin : 0 8px !important; diff --git a/src/Components/PublicationPermissionsContent.js b/src/Components/PublicationPermissionsContent.js index 1159d667ac2d542368d96b490db2cc10441f3156..2f404e49217f7c9c83541ed84c3852ce94d06b65 100644 --- a/src/Components/PublicationPermissionsContent.js +++ b/src/Components/PublicationPermissionsContent.js @@ -72,7 +72,7 @@ export default function PublicationPermissionsContent (props) { <p>{question.description}</p> </Grid> <Grid item xs={2}> - <RadioGroup row name={"radio" + (index + 1)} onChange={props.handleRadios}> + <RadioGroup row name={"radio" + (question.id)} onChange={props.handleRadios}> <FormControlLabel value="Sim" control={<BlueRadio/>} label="Sim"/> <FormControlLabel value="Não" control={<BlueRadio/>} label="Não"/> </RadioGroup> </Grid> diff --git a/src/Components/ResourceCard.css b/src/Components/ResourceCard.css index c7b97b5cb76d3373765410177a1cfd4749a31fef..345a97b61a931e5b09c711afb69a4c192cb4b7d6 100644 --- a/src/Components/ResourceCard.css +++ b/src/Components/ResourceCard.css @@ -1,22 +1,26 @@ /* transform: translateX(-1284.61px); visibility: hidden; */ -/* .slideContentLinkAfterActivefalse{ - transform: translateX(-1285.55px); +.slideContentLinkAfterActivefalse{ position: relative; -}*/ -.slideContentLinkAfterActivetrue{ - position: absolute; transform: none; + transition: cubic-bezier(1, 1, 0, 0) 750ms; +} + +.slideContentLinkAfterActivetrue{ + transform: translateX(-272.5px); + transition: transform 750ms; + position: relative; /* transition: transform 1000ms cubic-bezier(0,0,0.2,1) 0ms; */ } .slideContentLinkBeforeActivefalse{ - position: absolute; + position: relative; transform: none; - transition: transform 500ms cubic-bezier(0,0,0.2,1) 0ms; + transition: cubic-bezier(0, 0, 1, 1) 750ms; } .slideContentLinkBeforeActivetrue{ - transform: translateX(-1285.55px); + transform: translateX(-272.5px); + transition: transform 750ms; position: relative; } \ No newline at end of file diff --git a/src/Components/ResourceCardFunction.js b/src/Components/ResourceCardFunction.js index d688ca3e6e154871fc8633416529f651e531e530..62aa64614e3427ad4f9617f1ac6ce3daf956ce28 100644 --- a/src/Components/ResourceCardFunction.js +++ b/src/Components/ResourceCardFunction.js @@ -27,13 +27,16 @@ import Rating from '@material-ui/lab/Rating'; import StarBorderIcon from '@material-ui/icons/StarBorder'; import FavoriteIcon from '@material-ui/icons/Favorite'; import ButtonGuardarColecao from './ButtonGuardarColecao.js' -import Slide from '@material-ui/core/Slide'; import Grid from '@material-ui/core/Grid'; import { Link } from 'react-router-dom'; import { getDefaultThumbnail } from './HelperFunctions/getDefaultThumbnail' import GetIconByName from './UploadPageComponents/GetIconByName' import "./ResourceCard.css"; import { putRequest } from './HelperFunctions/getAxiosConfig' +import SignUpModal from './SignUpModal' +import LoginModal from './LoginModal.js' +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; export default function ResourceCardFunction(props) { const [thumbnail, setThumbnail] = useState(null) @@ -45,6 +48,14 @@ export default function ResourceCardFunction(props) { const [liked, toggleLiked] = useState(props.liked) const [likesCount, setLikesCount] = useState(props.likeCount) + const [signUpOpen, setSignUp] = useState(false) + const [loginOpen, setLogin] = useState(false) + const [successfulLoginOpen, handleSuccessfulLogin] = useState(false) + + function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; + } + useEffect(() => { //decide which thumbnail to use if (props.thumbnail) { @@ -74,6 +85,21 @@ export default function ResourceCardFunction(props) { putRequest(url, {}, handleSuccessLike, (error) => { console.log(error) }) } + const handleLogin = () => { + setLogin(!loginOpen) + } + + const handleSignUp = () => { + setSignUp(!signUpOpen) + } + + function toggleLoginSnackbar(reason) { + if (reason === 'clickaway') { + return; + } + handleSuccessfulLogin(false); + } + const SlideAnimationContent = () => { return ( <SlideContentDiv> @@ -106,64 +132,77 @@ export default function ResourceCardFunction(props) { } return ( - <StyledCard> - <CardDiv> - <CardReaDiv> - <Header onMouseEnter={controlSlide} onMouseLeave={controlSlide}> - { - <Slide direction="left" in={slideIn} timeout={1000}> - <div className={`slideContentLinkAfterActive${slideIn}`}> - <Link to={props.href} className="text" > - {SlideAnimationContent()} - </Link> + <React.Fragment> + <SignUpModal open={signUpOpen} handleClose={handleSignUp} openLogin={handleLogin} + /> + <LoginModal open={loginOpen} handleClose={() => setLogin(false)} openSignUp={handleSignUp} + openSnackbar={() => { handleSuccessfulLogin(true) }} + /> + <Snackbar open={successfulLoginOpen} autoHideDuration={1000} onClose={toggleLoginSnackbar} + anchorOrigin={{ vertical: 'top', horizontal: 'center' }} + > + <Alert severity="success" style={{ backgroundColor: "#00acc1" }}>Você está conectado(a)!</Alert> + </Snackbar> + <StyledCard> + <CardDiv> + <CardReaDiv> + <Link to={props.href}> + <Header onMouseEnter={controlSlide} onMouseLeave={controlSlide}> + <div className={`slideContentLinkBeforeActive${slideIn}`} style={{ height: '189px' }}> + <img className="img-cover" src={thumbnail} alt="learning object thumbnail" style={{ width: "272.5px" }} /> </div> - </Slide > - } - <div className={`slideContentLinkBeforeActive${slideIn}`} style={{ height: '100%' }}> - <img className="img-cover" src={thumbnail} alt="learning object thumbnail" style={{ width: "272.5px" }} /> - </div> - </Header> - <Description> - <Link to={props.href} className="text" style={{ height: '45px' }}> {/*add link to learningObject*/} - <Title> - {props.title} - </Title> + { + <div className={`slideContentLinkAfterActive${slideIn}`}> + <div className="text" > + {SlideAnimationContent()} + </div> + </div> + } + </Header> </Link> - <Rating - name="customized-empty" - value={props.rating} - readOnly - style={{ color: "#666" }} - emptyIcon={<StarBorderIcon fontSize="inherit" />} - /> - <Footer> - <Type> - {GetIconByName(label)} - <span>{label}</span> - </Type> - <LikeCounter> - <span>{likesCount}</span> - <ButtonNoWidth onClick={handleLike}> - <FavoriteIcon style={{ color: liked ? "red" : "#666" }} /> - </ButtonNoWidth> - </LikeCounter> - </Footer> - </Description> - </CardReaDiv> - <CardReaFooter> - <div style={{ display: "flex", height: "100%" }}> - <ButtonGuardarColecao thumb={props.thumbnail} title={props.title} learningObjectId={props.id} + <Description> + <Link to={props.href} className="text" style={{ height: '45px' }}> {/*add link to learningObject*/} + <Title> + {props.title} + </Title> + </Link> + <Rating + name="customized-empty" + value={props.rating} + readOnly + style={{ color: "#666" }} + emptyIcon={<StarBorderIcon fontSize="inherit" />} + /> + <Footer> + <Type> + {GetIconByName(label)} + <span>{label}</span> + </Type> + <LikeCounter> + <span>{likesCount}</span> + <ButtonNoWidth onClick={handleLike}> + <FavoriteIcon style={{ color: liked ? "red" : "#666" }} /> + </ButtonNoWidth> + </LikeCounter> + </Footer> + </Description> + </CardReaDiv> + <CardReaFooter> + <div style={{ display: "flex", height: "100%" }}> + <ButtonGuardarColecao thumb={props.thumbnail} title={props.title} learningObjectId={props.id} + /> + </div> + <ResourceCardOptions + learningObjectId={props.id} + downloadableLink={props.downloadableLink} + thumb={props.thumbnail} + title={props.title} + handleLogin={handleLogin} /> - </div> - <ResourceCardOptions - learningObjectId={props.id} - downloadableLink={props.downloadableLink} - thumb={props.thumbnail} - title={props.title} - /> - </CardReaFooter> - </CardDiv> - </StyledCard> + </CardReaFooter> + </CardDiv> + </StyledCard> + </React.Fragment> ) } /*---------- USED IN SLIDE DIV ONLY -----------*/ diff --git a/src/Components/ResourceCardOptions.js b/src/Components/ResourceCardOptions.js index 5d2821f3d9a39cc92af23d5ff1fa7c71de868777..2e89a35a708663188a9e843c3fbb08c8de6deaff 100644 --- a/src/Components/ResourceCardOptions.js +++ b/src/Components/ResourceCardOptions.js @@ -36,10 +36,6 @@ import ShareModal from './ShareModal' import SnackbarComponent from './SnackbarComponent' import OpenInBrowserIcon from '@material-ui/icons/OpenInBrowser'; import Tooltip from '@material-ui/core/Tooltip'; -import SignUpModal from './SignUpModal' -import LoginModal from './LoginModal.js' -import Snackbar from '@material-ui/core/Snackbar'; -import MuiAlert from '@material-ui/lab/Alert'; import { getRequest } from './HelperFunctions/getAxiosConfig' export default function ResourceCardOptions(props) { @@ -68,7 +64,7 @@ export default function ResourceCardOptions(props) { const [saveToCol, toggleSave] = useState(false) const handleGuardar = () => { if (!state.currentUser.id) { - handleLogin(); + props.handleLogin(); } else { toggleSave(true); @@ -93,7 +89,7 @@ export default function ResourceCardOptions(props) { const handleShare = () => { if (!state.currentUser.id) { - handleLogin() + props.handleLogin() } else { toggleShare(true); @@ -104,17 +100,9 @@ export default function ResourceCardOptions(props) { return (window.origin + "/recurso/" + props.learningObjectId) } - const handleSignUp = () => { - setSignUp(!signUpOpen) - } - - const handleLogin = () => { - setLogin(!loginOpen) - } - const handleReport = () => { if (!state.currentUser.id) { - handleLogin() + props.handleLogin() } else { handleModalReportar(true); @@ -122,21 +110,7 @@ export default function ResourceCardOptions(props) { handleClose(); } - function Alert(props) { - return <MuiAlert elevation={6} variant="filled" {...props} />; - } - - function toggleLoginSnackbar(reason) { - if (reason === 'clickaway') { - return; - } - handleSuccessfulLogin(false); - } - const [snackbarOpen, toggleSnackbar] = useState(false) - const [signUpOpen, setSignUp] = useState(false) - const [loginOpen, setLogin] = useState(false) - const [successfulLoginOpen, handleSuccessfulLogin] = useState(false) return ( <> @@ -155,16 +129,6 @@ export default function ResourceCardOptions(props) { /> <SnackbarComponent snackbarOpen={snackbarOpen} severity={"info"} handleClose={() => { toggleSnackbar(false) }} text={"Baixando o Recurso... Lembre-se de relatar sua experiência após o uso do Recurso!"} /> - <SignUpModal open={signUpOpen} handleClose={handleSignUp} openLogin={handleLogin} - /> - <LoginModal open={loginOpen} handleClose={() => setLogin(false)} openSignUp={handleSignUp} - openSnackbar={() => { handleSuccessfulLogin(true) }} - /> - <Snackbar open={successfulLoginOpen} autoHideDuration={1000} onClose={toggleLoginSnackbar} - anchorOrigin={{ vertical: 'top', horizontal: 'center' }} - > - <Alert severity="success" style={{ backgroundColor: "#00acc1" }}>Você está conectado(a)!</Alert> - </Snackbar> <div style={{ fontSize: "12px", display: "flex", flexDirection: "column", justifyContent: "center" }}> <ButtonNoWidth aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick} style={{ color: "#666" }}> <MoreVertIcon style={{ color: "#666" }} /> diff --git a/src/Components/ResourceList.js b/src/Components/ResourceList.js index 4f2572f4fae05fe6ee995918d48a4584af4b0264..e32176c7166f62820cf88517c7f8f5dc8faf503c 100644 --- a/src/Components/ResourceList.js +++ b/src/Components/ResourceList.js @@ -41,7 +41,11 @@ export default function ResourceList(props) { 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 [snackInfo, setSnackInfo] = useState({ + open: false, + text: "", + severity: "", + }); const updateSelected = (index) => { let new_selected = selected.slice(); @@ -49,6 +53,10 @@ export default function ResourceList(props) { setSelected(new_selected); } + const handleSnackInfo = (info) => { + setSnackInfo({ ...info }) + } + const checkBoxIcon = (s) => { if (s) return <CheckBoxIcon />; @@ -56,9 +64,36 @@ export default function ResourceList(props) { return <CheckBoxOutlineBlankIcon />; } - const handleDownloadSelection = () => { + const handleDownloadSelection = (e) => { + e.preventDefault() // const selected_resources = props.resources.filter(resource => selected[props.resources.indexOf(resource)]); - setSnackbarOpen(true); + let snackInfo = {} + if (download_url) { + window.open(download_url, '_blank') + snackInfo = { + open: true, + text: "Os recursos estão sendo baixados...", + severity: "success", + } + handleSnackInfo(snackInfo) + } + else { + snackInfo = { + open: true, + text: "Selecione os recursos que deseja baixar", + severity: "warning", + } + handleSnackInfo(snackInfo) + } + } + + const handleCloseSnack = () => { + const snackInfo = { + open: false, + text: "", + severity: "", + } + handleSnackInfo(snackInfo) } useEffect(() => { @@ -103,16 +138,14 @@ export default function ResourceList(props) { </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> + <Button + color="primary" + variant="outlined" + startIcon={<GetAppIcon fontSize="large" />} + onClick={handleDownloadSelection} + > + <PanelButtonText>baixar seleção</PanelButtonText> + </Button> </Grid> </Grid> <Grid container direction="row" justify="center" alignItems="center"> @@ -151,16 +184,18 @@ export default function ResourceList(props) { })} </Grid> <Snackbar - open={snackbar_open} + open={snackInfo.open} autoHideDuration={6000} - onClose={() => setSnackbarOpen(false)} + onClose={handleCloseSnack} anchorOrigin={{ vertical: 'top', horizontal: 'right' }} > - <Alert onClose={() => setSnackbarOpen(false)} severity="info"> - Os recursos serão baixados + <Alert onClose={handleCloseSnack} severity={snackInfo.severity}> + {snackInfo.text} </Alert> </Snackbar> - <FloatingDownloadButton url={download_url} empty={selected.indexOf(true) === -1} /> + <FloatingDownloadButton + handleDownloadSelection={handleDownloadSelection} + /> </ResourceListContainer> ); } @@ -182,7 +217,4 @@ const PanelButtonText = styled.span` ` const ResourceGrid = styled(Grid)` padding-right: 7px; -` -const UnstyledAnchor = styled.a` - text-decoration: none !important; -` +` \ No newline at end of file diff --git a/src/Components/ResourcePageComponents/CommentForm.js b/src/Components/ResourcePageComponents/CommentForm.js index 0b1c38ba693b98b03c689f18035a6f81478d9cd9..0272d76fc6f63b264b9197d390818729caa46cc1 100644 --- a/src/Components/ResourcePageComponents/CommentForm.js +++ b/src/Components/ResourcePageComponents/CommentForm.js @@ -1,4 +1,4 @@ -import React, {useState} from 'react' +import React, { useState } from 'react' import styled from 'styled-components' import Rating from '@material-ui/lab/Rating'; import StarIcon from '@material-ui/icons/Star'; @@ -6,27 +6,27 @@ import TextField from "@material-ui/core/TextField"; import { Button } from '@material-ui/core'; import EditIcon from '@material-ui/icons/Edit'; import Grid from '@material-ui/core/Grid'; -import {postRequest} from '../HelperFunctions/getAxiosConfig' +import { postRequest } from '../HelperFunctions/getAxiosConfig' -export default function CommentForm (props) { +export default function CommentForm(props) { const [rating, setRating] = useState({ - error : true, - value : 0 + error: true, + value: 0 }) const [comment, setComment] = useState({ - error : false, - value : '' + error: false, + value: '' }) const handleChange = (e) => { const userInput = e.target.value const flag = (userInput.length === 0 ? true : false); - setComment({...comment, error : flag, value : userInput}) + setComment({ ...comment, error: flag, value: userInput }) } const [attemptedSubmit, setAttempt] = useState(false) - function handleSuccess (data) { + function handleSuccess(data) { props.handleSnackbar(1) props.rerenderCallback() } @@ -40,18 +40,18 @@ export default function CommentForm (props) { const url = `/${type}/${props.recursoId}/reviews` let payload = { - "review" : { - "description" : finalComment.value, - "review_ratings_attributes" : [ + "review": { + "description": finalComment.value, + "review_ratings_attributes": [ { - "rating_id" : 1, - "value" : finalRating.value + "rating_id": 1, + "value": finalRating.value } ] } } - postRequest(url, payload, handleSuccess, (error) => {console.log(error)}) + postRequest(url, payload, handleSuccess, (error) => { console.log(error) }) } else { setAttempt(true) @@ -65,42 +65,42 @@ export default function CommentForm (props) { </label> <div className="stars-container"> <Rating - name="avaliacao-estrelas" - value={rating.value} - precision={0.5} - style={{color:"#ff9226"}} - onChange = {(e, newValue) => {setRating({...rating, error : newValue === null ? true : false, value : newValue})}} - emptyIcon={<StarIcon fontSize="inherit" style={{color : "#666"}} />} - getLabelText={(value) => {return(value + ' Estrela' + (value !== 1 ? 's' : ''))}} + name="avaliacao-estrelas" + value={rating.value} + precision={0.5} + style={{ color: "#ff9226" }} + onChange={(e, newValue) => { setRating({ ...rating, error: newValue === null ? true : false, value: newValue }) }} + emptyIcon={<StarIcon fontSize="inherit" style={{ color: "#666" }} />} + getLabelText={(value) => { return (value + ' Estrela' + (value !== 1 ? 's' : '')) }} /> </div> - <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> + <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> <Grid item xs={12} md={9}> - <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") : ''} - /> + <StyledTextField + colecao={!props.recurso} + value={comment.value} + multiline + rows="5" + error={comment.error} + label="Relate sua experiência" + 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} md={3}> - <div style={{height : "100%", display : "flex", flexDirection : "column", justifyContent : "flex-end"}}> + <div style={{ height: "100%", display: "flex", flexDirection: "column", justifyContent: "flex-end" }}> { props.recurso ? - ( - <OrangeButton type="submit">Publicar</OrangeButton> - ) - : - ( - <PurpleButton type="submit"><EditIcon/>Enviar</PurpleButton> - ) + ( + <OrangeButton type="submit">Publicar</OrangeButton> + ) + : + ( + <PurpleButton type="submit"><EditIcon />Enviar</PurpleButton> + ) } </div> </Grid> @@ -149,7 +149,7 @@ const StyledTextField = styled(TextField)` } .MuiInput-underline::after { - border-bottom: ${props => props.colecao ? "2px solid #673ab7" : "2px solid rgb(255,127,0)" }; + border-bottom: ${props => props.colecao ? "2px solid #673ab7" : "2px solid rgb(255,127,0)"}; } label.Mui-focused.Mui-error { diff --git a/src/Components/ResourcePageComponents/CommentsArea.js b/src/Components/ResourcePageComponents/CommentsArea.js index 946ce4d4fc3e276b95e673a742b58a973f6fe065..e68a1a23893fa698241899c5a969005e0402e526 100644 --- a/src/Components/ResourcePageComponents/CommentsArea.js +++ b/src/Components/ResourcePageComponents/CommentsArea.js @@ -16,34 +16,63 @@ 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 React, { useState, useContext, useEffect } from 'react' +import { Store } from '../../Store.js' import styled from 'styled-components' import Grid from '@material-ui/core/Grid'; import { Button } from '@material-ui/core'; import ExitToAppIcon from '@material-ui/icons/ExitToApp'; import Comentarios from '../../img/comentarios.png' -import {apiDomain} from '../../env'; +import { apiDomain } from '../../env'; import CommentForm from './CommentForm.js' import Comment from '../Comment.js' -import {getRequest} from '../HelperFunctions/getAxiosConfig' +import { getRequest } from '../HelperFunctions/getAxiosConfig' import LoginModal from './../LoginModal.js' import Snackbar from '@material-ui/core/Snackbar'; import SignUpModal from './../SignUpModal' import MuiAlert from '@material-ui/lab/Alert'; +import CircularProgress from '@material-ui/core/CircularProgress'; +import noAvatar from '../../img/default_profile.png'; +import IconButton from '@material-ui/core/IconButton'; +import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown'; +import SnackBarComponent from '../../Components/SnackbarComponent'; function Alert(props) { return <MuiAlert elevation={6} variant="filled" {...props} />; } -export default function CommentsArea (props) { - const {state} = useContext(Store) +export default function CommentsArea(props) { + const { state } = useContext(Store) const [comentarios, setComentarios] = useState([]) + const [totalReviews, setTotalReviews] = useState(0); + const [currPageReviews, setCurrPageReviews] = useState(0); const [gambiarra, setState] = useState(0) - const forceUpdate = () => {setState(gambiarra + 1)} + const forceUpdate = () => { setState(gambiarra + 1) } const [loginOpen, setLogin] = useState(false) const [successfulLoginOpen, handleSuccessfulLogin] = useState(false) const [signUpOpen, setSignUp] = useState(false) + const [isLoading, setIsLoading] = useState(false) + const [snackInfo, setSnackInfo] = useState({ + open: false, + text: '', + severity: '', + color: '' + }); + + function handleSnackInfo(info) { + setSnackInfo({ + ...info + }) + } + + function handleCloseSnack() { + setSnackInfo({ + open: false, + text: '', + severity: '', + color: '', + }) + } const handleSignUp = () => { setSignUp(!signUpOpen) @@ -53,26 +82,54 @@ export default function CommentsArea (props) { setLogin(!loginOpen) } + const handlePost = () => { + props.handleSnackbar(2) + } + const toggleSnackbar = (event, reason) => { if (reason === 'clickaway') { return; } - - handleSuccessfulLogin(false); + + handleSuccessfulLogin(false); } - function handleSuccess (data) { - setComentarios(data.sort((a, b) => a.updated_at > b.updated_at ? -1 : 1)) + function handleLoadMoreReviews() { + if (comentarios.length !== parseInt(totalReviews)) + setCurrPageReviews((previous) => previous + 1) + else { + const info = { + open: true, + text: 'Não há mais comentários para carregar.', + severity: 'warning', + color: '', + } + handleSnackInfo(info) + } } - useEffect( () => { - const url = `/learning_objects/${props.recursoId}/reviews` + function handleSuccess(data, headers) { + setIsLoading(false) + setComentarios((previous) => previous.concat(data.sort((a, b) => a.updated_at > b.updated_at ? -1 : 1))) + if (headers.has('X-Total-Count')) + setTotalReviews(headers.get('X-Total-Count')) + } - getRequest(url, handleSuccess, (error) => {console.log(error)}) - }, [gambiarra]) + useEffect(() => { + setIsLoading(true) + const url = `/learning_objects/${props.recursoId}/reviews?page=${currPageReviews}` + getRequest(url, handleSuccess, (error) => { console.log(error); setIsLoading(false) }) + }, [gambiarra, currPageReviews]) return ( <React.Fragment> + <SnackBarComponent + snackbarOpen={snackInfo.open} + handleClose={handleCloseSnack} + severity={snackInfo.severity} + text={snackInfo.text} + color={snackInfo.color} + /> <Snackbar open={successfulLoginOpen} autoHideDuration={1000} onClose={toggleSnackbar} anchorOrigin={{ vertical: 'top', horizontal: 'center' }} > @@ -83,88 +140,114 @@ export default function CommentsArea (props) { openSnackbar={() => { handleSuccessfulLogin(true) }} /> <SignUpModal open={signUpOpen} handleClose={handleSignUp} openLogin={handleLogin} /> - {/*----------------------------------------------------------------------------*/} - <Grid container spacing={2} style={{padding : "10px"}}> + {/*----------------------------------------------------------------------------*/} + <Grid container spacing={2} style={{ padding: "10px" }}> { (state.currentUser.id !== '') ? - ( + ( <Grid item xs={12} > <GrayContainer> <h3>Conte sua experiência com o Recurso</h3> - <Grid container style={{paddingTop : "20px"}}> - <Grid item xs={2} style={{paddingLeft : "15px", paddingRight : "15px"}}> - <img src={apiDomain + state.currentUser.avatar} className="minha-imagem" alt="user avatar"/> + <Grid container style={{ paddingTop: "20px" }} spacing={1}> + <Grid item xs={12} sm={2} style={{ paddingLeft: "15px", paddingRight: "15px" }}> + <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}> + <img src={state.currentUser.avatar ? apiDomain + state.currentUser.avatar : noAvatar} className="minha-imagem" alt="user avatar" /> + </div> </Grid> - <Grid item xs={10}> + <Grid item xs={12} sm={10}> <CommentForm recursoId={props.recursoId} handleSnackbar={props.handleSnackbar} rerenderCallback={forceUpdate} recurso={props.recurso} - /> + /> </Grid> </Grid> </GrayContainer> </Grid> - ) - : - ( + ) + : + ( <Grid item xs={12}> <LogInToComment> <span className="span-laranja">Você precisa entrar para comentar</span> - <Button onClick={() => handleLogin(true)} style={{textTransform : "uppercase", color : "#666", fontWeight : "700"}}> - <ExitToAppIcon/>ENTRAR + <Button onClick={() => handleLogin(true)} style={{ textTransform: "uppercase", color: "#666", fontWeight: "700" }}> + <ExitToAppIcon />ENTRAR </Button> </LogInToComment> </Grid> - ) + ) } { - comentarios.length !== 0 ? - ( + isLoading ? + <LoadingDiv> + <CircularProgress className="loading" /> + </LoadingDiv> + : + totalReviews !== 0 ? + ( <ComentariosBox> - <h3>{comentarios.length} {comentarios.length !== 1 ? 'Relatos' : 'Relato'} sobre o uso do Recurso</h3> + <h3>{totalReviews} {totalReviews !== 1 ? 'Relatos' : 'Relato'} sobre o uso do Recurso</h3> { - comentarios.map( comentario => - <div className="comentario-template" key={comentario.id}> - <Comment - authorID={comentario.user ? comentario.user.id : null} - authorAvatar={comentario.user ? comentario.user.avatar : null} - authorName={comentario.user ? comentario.user.name : null} - name={comentario.name} - rating={comentario.rating_average} - reviewRatings = {comentario.review_ratings} - description={comentario.description} - createdAt={comentario.created_at} - recurso={true} - reviewID={comentario.id} - objectID={props.recursoId} - rerenderCallback={forceUpdate} - handleSnackbar={props.handleSnackbar} - /> - </div> + comentarios.map(comentario => + <div className="comentario-template" key={comentario.id}> + <Comment + isCollection={false} + authorID={comentario.user ? comentario.user.id : null} + authorAvatar={comentario.user ? comentario.user.avatar : null} + authorName={comentario.user ? comentario.user.name : null} + name={comentario.name} + rating={comentario.rating_average} + reviewRatings={comentario.review_ratings} + description={comentario.description} + createdAt={comentario.created_at} + recurso={true} + reviewID={comentario.id} + objectID={props.recursoId} + handlePost={handlePost} + rerenderCallback={forceUpdate} + handleSnackbar={props.handleSnackbar} + /> + </div> ) } + <div className="load-more"> + <IconButton className="button" onClick={handleLoadMoreReviews}> + <KeyboardArrowDownIcon /> + </IconButton> + </div> </ComentariosBox> - ) - : - ( - <Grid item xs={12}> - <LogInToComment> - <img alt="" src={Comentarios} /> - <span className="span-laranja">Compartilhe sua experiência com a Rede!</span> - <AoRelatar> - Ao relatar sua experiência de uso do Recurso você estará auxiliando professores de todo paÃs. + ) + : + ( + <Grid item xs={12}> + <LogInToComment> + <img alt="" src={Comentarios} /> + <span className="span-laranja">Compartilhe sua experiência com a Rede!</span> + <AoRelatar> + Ao relatar sua experiência de uso do Recurso você estará auxiliando professores de todo paÃs. </AoRelatar> - </LogInToComment> - </Grid> - ) + </LogInToComment> + </Grid> + ) } </Grid> </React.Fragment> ) } +const LoadingDiv = styled.div` + width: 100%; + margin: 1em auto; + display: flex; + justify-content: center; + align-items: center; + .loading{ + align-self: center; + color: #ff7f00; + size: 24px; + } +` const ComentariosBox = styled.div` display : flex; @@ -183,9 +266,22 @@ const ComentariosBox = styled.div` } .comentario-template { + margin-top: 5px; padding : 20px 0; border-bottom : 1px solid #f4f4f4; } + + .load-more{ + width: 100%; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + } + + .button{ + box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2); + } ` const AoRelatar = styled.div` width : 70%; @@ -218,24 +314,19 @@ const LogInToComment = styled.div` const GrayContainer = styled.div` background-color : #fafafa; font-weight : 400; - 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; + text-align: center; font-weight: 300; font-style: normal; color: #666; diff --git a/src/Components/ResourcePageComponents/TextoObjeto.js b/src/Components/ResourcePageComponents/TextoObjeto.js index 1554cc9ebd70387fd72cb155f749232133f1b5c0..f19b82e1d1c55de62c7884e36c63827c7fe77b70 100644 --- a/src/Components/ResourcePageComponents/TextoObjeto.js +++ b/src/Components/ResourcePageComponents/TextoObjeto.js @@ -104,7 +104,12 @@ export default function TextoObjeto (props) { return ( <TextoObjetoDiv> { publisherDeletedObject && - <Redirect to="/"/> + <Redirect + to={{ + pathname: "/perfil", + state: 1 + }} + /> } <Snackbar open={snackbarOpen} autoHideDuration={1000} onClose={() => {toggleSnackbar(false)}} anchorOrigin = {{ vertical:'top', horizontal:'right' }} diff --git a/src/Components/ResourcePageComponents/VideoPlayer.js b/src/Components/ResourcePageComponents/VideoPlayer.js index 940917df9190d882df8c4d5f77798cbe04b4bb93..57b1b06c0271db6a4d36133db6426159f7082255 100644 --- a/src/Components/ResourcePageComponents/VideoPlayer.js +++ b/src/Components/ResourcePageComponents/VideoPlayer.js @@ -19,58 +19,61 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React from 'react' import styled from 'styled-components' -function GetEmbeddedLink (link) { +function GetEmbeddedLink(link) { var embed = undefined var link_id = undefined if (link.indexOf("youtube") !== -1) { //plain youtebe.com/ link - if(link.indexOf("embed/") !== -1) { //if it's already an embedded link, return it + if (link.indexOf("embed/") !== -1) { //if it's already an embedded link, return it return link } link = link.split("&")[0] //else remove features and other queries link_id = link.split("v=")[1] //get video id embed = "https://www.youtube.com/embed/" + link_id; //create embedded link - } - else if (link.indexOf("youtu.be") !== -1) { //if it's a youtu.be link - link = link.split("&")[0].split("?")[0] //remove queries and features if existent - link_id = link.split(".be/")[1] //get video id - embed = "https://www.youtube.com/embed/" + link_id; //create embedded link - } - else if (link.indexOf("vimeo") !== -1) { //if the 13th character = o (vimeo videos) - link_id = link.split("?")[0].split("/") - console.log(link_id) //key # = from 19th character on - embed = "https://player.vimeo.com/video/" + link_id.pop(); //Add vimeo link before key # - } - return embed + } + else if (link.indexOf("youtu.be") !== -1) { //if it's a youtu.be link + link = link.split("&")[0].split("?")[0] //remove queries and features if existent + link_id = link.split(".be/")[1] //get video id + embed = "https://www.youtube.com/embed/" + link_id; //create embedded link + } + else if (link.indexOf("vimeo") !== -1) { //if the 13th character = o (vimeo videos) + link_id = link.split("?")[0].split("/") + console.log(link_id) //key # = from 19th character on + embed = "https://player.vimeo.com/video/" + link_id.pop(); //Add vimeo link before key # + } + return embed } -export default function VideoPlayer (props) { +export default function VideoPlayer(props) { return ( <> - { - props.urlVerified ? - ( - <VideoContainer> - <iframe - title="Video Player" - src={GetEmbeddedLink(props.link)} - frameBorder="0" allowFullScreen className="video" - /> - </VideoContainer> - ) - : - ( - <VideoContainer> - <video controls className="video"> - <source src={props.videoUrl} type="video/webm"/> - <source src={props.videoUrl} type="video/mp4"/> - <p>Seu navegador não permite a exibição deste vÃdeo. É necessário baixar o vÃdeo para poder visualizá-lo.</p> - </video> - </VideoContainer> - - ) - } + { + props.urlVerified ? + ( + <VideoContainer> + <iframe + title="Video Player" + src={GetEmbeddedLink(props.link)} + frameBorder="0" allowFullScreen className="video" + /> + </VideoContainer> + ) + : + ( + props.videoType === "video/mp4" ? + <VideoContainer> + <video controls className="video"> + <source src={props.videoUrl} type="video/webm" /> + <source src={props.videoUrl} type="video/mp4" /> + </video> + </VideoContainer> + : + <ErrorParagraph> + Seu navegador não permite a exibição deste vÃdeo. É necessário baixar o vÃdeo para poder visualizá-lo. + </ErrorParagraph> + ) + } </> ) } @@ -89,3 +92,7 @@ const VideoContainer = styled.div` left : 0; } ` + +const ErrorParagraph = styled.p` + text-align: center; +` diff --git a/src/Components/SearchBar.js b/src/Components/SearchBar.js index 1c36964e90f24460d54fd70e0386839ac9754335..8e0ea969a6655039cd1b71419fbc34367e385a77 100644 --- a/src/Components/SearchBar.js +++ b/src/Components/SearchBar.js @@ -139,7 +139,7 @@ export default function SearchBar(props) { } const linkTarget = { - pathname: `/busca?query=${state.search.query}&search_class=${state.search.class}`, + pathname: `/busca?page=0&results_per_page=12&order=review_average&query=${state.search.query}&search_class=${state.search.class}`, key: uuidv4(), // we could use Math.random, but that's not guaranteed unique. state: { applied: true @@ -149,7 +149,7 @@ export default function SearchBar(props) { return ( <Grid container> <Grid container item xs={12} sm={6} md={6} lg={6} xl={6}> - {goSearch && <Redirect to={`/busca?query=${state.search.query}&search_class=${state.search.class}`} />} + {goSearch && <Redirect to={`/busca?page=0&results_per_page=12&order=review_average&query=${state.search.query}&search_class=${state.search.class}`} />} <TextFieldStyled id="standard-search" label="O que você está buscando" diff --git a/src/Components/SearchExpansionPanel/SearchEPCompCurriculum.js b/src/Components/SearchExpansionPanel/SearchEPCompCurriculum.js index 180eaeef90d4ec92d3c6fa367cb0eb22489d3ef9..43941d039dc31f98950b9c0fe2857bea2486bf4a 100644 --- a/src/Components/SearchExpansionPanel/SearchEPCompCurriculum.js +++ b/src/Components/SearchExpansionPanel/SearchEPCompCurriculum.js @@ -17,88 +17,45 @@ const useStyles = makeStyles(theme => ({ } })); -export default function SearchEPCompCurriculum(props) { +export default function SearchEPCompCurriculum({ onChange, curriculumComponents, setCurriculum }) { const classes = useStyles(); - const [checked, setChecked] = React.useState([0]); - const handleToggle = value => () => { - const currentIndex = checked.indexOf(value); - const newChecked = [...checked]; - - if (currentIndex === -1) { - newChecked.push(value); - } else { - newChecked.splice(currentIndex, 1); - } - - let filterString = ""; - - setChecked(newChecked); - for(let i = 0; i < newChecked.length; i++){ - if(newChecked[i] !== 0){ - filterString = filterString + `&subjects[]=${newChecked[i]}` - console.log(filterString) - } - } - props.onChange("LearningObject", filterString) + const handleToggle = (index) => () => { + const newCurriculumComponents = [...curriculumComponents]; + newCurriculumComponents[index].isChecked = !newCurriculumComponents[index].isChecked + setCurriculum(newCurriculumComponents); }; - const filtrosComponente = [ - { exemplo: "Arte", value: "3" }, - { exemplo: "Biologia", value: "5" }, - { exemplo: "Ciências da Natureza", value: "6" }, - { exemplo: "Direitos Humanos", value: "20" }, - { exemplo: "Educação Ambiental", value: "21" }, - { exemplo: "Educação do Campo", value: "22" }, - { exemplo: "Educação Especial", value: "23" }, - { exemplo: "Educação FÃsica", value: "7" }, - { exemplo: "Educação IndÃgena", value: "24" }, - { exemplo: "Educação Quilombola", value: "25" }, - { exemplo: "Educação Sexual", value: "26" }, - { exemplo: "Ensino Religioso", value: "16" }, - { exemplo: "Filosofia", value: "8" }, - { exemplo: "FÃsica", value: "9" }, - { exemplo: "Geografia", value: "10" }, - { exemplo: "História", value: "11" }, - { exemplo: "Informática", value: "18" }, - { exemplo: "LÃngua Espanhola", value: "1" }, - { exemplo: "LÃngua Inglesa", value: "2" }, - { exemplo: "LÃngua Portuguesa", value: "4" }, - { exemplo: "Matemática", value: "12" }, - { exemplo: "Outras LÃnguas", value: "15" }, - { exemplo: "Outros", value: "17" }, - { exemplo: "QuÃmica", value: "13" }, - { exemplo: "Sociologia", value: "14" } - ]; - - return ( - <List className={classes.root}> - {filtrosComponente.map(item => { - const labelId = `checkbox-list-label-${item.value}`; - return ( - <ListItem - key={item.exemplo} - role={undefined} - dense - button - onClick={handleToggle(item.value)} - > - <ListItemIcon> - <Checkbox - edge="start" - checked={checked.indexOf(item.value) !== -1} - tabIndex={-1} - disableRipple - inputProps={{ "aria-labelledby": labelId }} - /> - </ListItemIcon> - <ListItemText id={labelId} primary={item.exemplo} /> - <ListItemSecondaryAction> - <IconButton edge="end" aria-label="comments"></IconButton> - </ListItemSecondaryAction> - </ListItem> - ); - })} - </List> - ); + if (curriculumComponents) + return ( + <List className={classes.root}> + {curriculumComponents.map((item, index) => { + const labelId = `checkbox-list-label-${item.value}`; + + return ( + <ListItem + key={item.exemplo} + role={undefined} + dense + button + onClick={handleToggle(index)} + > + <ListItemIcon> + <Checkbox + edge="start" + checked={item.isChecked} + tabIndex={-1} + disableRipple + inputProps={{ "aria-labelledby": labelId }} + /> + </ListItemIcon> + <ListItemText id={labelId} primary={item.exemplo} /> + <ListItemSecondaryAction> + <IconButton edge="end" aria-label="comments"></IconButton> + </ListItemSecondaryAction> + </ListItem> + ); + })} + </List> + ); } diff --git a/src/Components/SearchExpansionPanel/SearchEPIdiomas.js b/src/Components/SearchExpansionPanel/SearchEPIdiomas.js index b32f032cbce2efcdb4c5e791582c0a3561683560..06715e4615b21f96a5ab87d6caad1cdc5f2d8eac 100644 --- a/src/Components/SearchExpansionPanel/SearchEPIdiomas.js +++ b/src/Components/SearchExpansionPanel/SearchEPIdiomas.js @@ -17,74 +17,45 @@ const useStyles = makeStyles(theme => ({ } })); -export default function SearchEPIdiomas(props) { +export default function SearchEPIdiomas({ languages, setLanguages }) { const classes = useStyles(); - const [checked, setChecked] = React.useState([0]); - const handleToggle = value => () => { - const currentIndex = checked.indexOf(value); - const newChecked = [...checked]; - - if (currentIndex === -1) { - newChecked.push(value); - } else { - newChecked.splice(currentIndex, 1); - } - - setChecked(newChecked); - let filterString = ""; - - for(let i = 0; i < newChecked.length; i++){ - if(newChecked[i] !== 0){ - filterString = filterString + `&languages[]=${newChecked[i]}` - console.log(filterString) - } - } - props.onChange("LearningObject", filterString) + const handleToggle = (index) => () => { + const newLanguages = [...languages]; + newLanguages[index].isChecked = !newLanguages[index].isChecked + setLanguages(newLanguages); }; - const filtrosIdiomas = [ - { value: "5", exemplo: "Alemão" }, - { value: "3", exemplo: "Espanhol" }, - { value: "4", exemplo: "Francês" }, - { value: "2", exemplo: "Inglês" }, - { value: "6", exemplo: "Italiano" }, - { value: "9", exemplo: "Japonês" }, - { value: "19", exemplo: "LIBRAS" }, - { value: "7", exemplo: "Mandarim" }, - { value: "10", exemplo: "Outro" }, - { value: "1", exemplo: "Português" }, - { value: "8", exemplo: "Russo" } - ]; - return ( - <List className={classes.root}> - {filtrosIdiomas.map(item => { - const labelId = `checkbox-list-label-${item.value}`; + if (languages) + return ( + <List className={classes.root}> + {languages.map((item, index) => { + const labelId = `checkbox-list-label-${item.value}`; - return ( - <ListItem - key={item.exemplo} - role={undefined} - dense - button - onClick={handleToggle(item.value)} - > - <ListItemIcon> - <Checkbox - edge="start" - checked={checked.indexOf(item.value) !== -1} - tabIndex={-1} - disableRipple - inputProps={{ "aria-labelledby": labelId }} - /> - </ListItemIcon> - <ListItemText id={labelId} primary={item.exemplo} /> - <ListItemSecondaryAction> - <IconButton edge="end" aria-label="comments"></IconButton> - </ListItemSecondaryAction> - </ListItem> - ); - })} - </List> - ); + return ( + <ListItem + key={item.exemplo} + role={undefined} + dense + button + onClick={handleToggle(index)} + > + <ListItemIcon> + <Checkbox + edge="start" + checked={item.isChecked} + tabIndex={-1} + disableRipple + inputProps={{ "aria-labelledby": labelId }} + /> + </ListItemIcon> + <ListItemText id={labelId} primary={item.exemplo} /> + <ListItemSecondaryAction> + <IconButton edge="end" aria-label="comments"></IconButton> + </ListItemSecondaryAction> + </ListItem> + ); + })} + </List> + ); } diff --git a/src/Components/SearchExpansionPanel/SearchEPTiposRec.js b/src/Components/SearchExpansionPanel/SearchEPTiposRec.js index 8dc4fcf6782641ca5bee2916a75c75050f6f298c..41b77adf51206db55b674ce259819f0b8bbf2236 100644 --- a/src/Components/SearchExpansionPanel/SearchEPTiposRec.js +++ b/src/Components/SearchExpansionPanel/SearchEPTiposRec.js @@ -17,79 +17,45 @@ const useStyles = makeStyles(theme => ({ } })); -export default function SearchEPTiposRec(props) { +export default function SearchEPCompCurriculum({ onChange, typeOfResources, setTypeRes }) { const classes = useStyles(); - const [checked, setChecked] = React.useState([0]); - const handleToggle = value => () => { - const currentIndex = checked.indexOf(value); - const newChecked = [...checked]; - - if (currentIndex === -1) { - newChecked.push(value); - } else { - newChecked.splice(currentIndex, 1); - } - - let filterString = ""; - - setChecked(newChecked); - for(let i = 0; i < newChecked.length; i++){ - if(newChecked[i] !== 0){ - filterString = filterString + `&object_types[]=${newChecked[i]}` - console.log(filterString) - } - } - props.onChange("LearningObject", filterString) + const handleToggle = (index) => () => { + const newTypeOfRes = [...typeOfResources]; + newTypeOfRes[index].isChecked = !newTypeOfRes[index].isChecked + setTypeRes(newTypeOfRes); }; - const filtrosTipos = [ - { value: "5", exemplo: "Animação" }, - { value: "20", exemplo: "Aplicativo móvel" }, - { value: "17", exemplo: "Apresentação" }, - { value: "7", exemplo: "Ãudio" }, - { value: "4", exemplo: "Experimento prático" }, - { value: "1", exemplo: "Imagem" }, - { value: "18", exemplo: "Infográfico" }, - { value: "19", exemplo: "Jogo" }, - { value: "21", exemplo: "Livro digital" }, - { value: "2", exemplo: "Mapa" }, - { value: "15", exemplo: "Outros" }, - { value: "3", exemplo: "Software Educacional" }, - { value: "6", exemplo: "Texto" }, - { value: "8", exemplo: "VÃdeo" }, - { value: "13", exemplo: "Website externo" }, - { value: "22", exemplo: "Plano de Aula" }, - ]; - - return ( - <List className={classes.root}> - {filtrosTipos.map(item => { - const labelId = `checkbox-list-label-${item.value}`; - return ( - <ListItem - key={item.exemplo} - role={undefined} - dense - button - onClick={handleToggle(item.value)} - > - <ListItemIcon> - <Checkbox - edge="start" - checked={checked.indexOf(item.value) !== -1} - tabIndex={-1} - disableRipple - inputProps={{ "aria-labelledby": labelId }} - /> - </ListItemIcon> - <ListItemText id={labelId} primary={item.exemplo} /> - <ListItemSecondaryAction> - <IconButton edge="end" aria-label="comments"></IconButton> - </ListItemSecondaryAction> - </ListItem> - ); - })} - </List> - ); + if (typeOfResources) + return ( + <List className={classes.root}> + {typeOfResources.map((item, index) => { + const labelId = `checkbox-list-label-${item.value}`; + + return ( + <ListItem + key={item.exemplo} + role={undefined} + dense + button + onClick={handleToggle(index)} + > + <ListItemIcon> + <Checkbox + edge="start" + checked={item.isChecked} + tabIndex={-1} + disableRipple + inputProps={{ "aria-labelledby": labelId }} + /> + </ListItemIcon> + <ListItemText id={labelId} primary={item.exemplo} /> + <ListItemSecondaryAction> + <IconButton edge="end" aria-label="comments"></IconButton> + </ListItemSecondaryAction> + </ListItem> + ); + })} + </List> + ); } diff --git a/src/Components/SearchExpansionPanel/SearchExpansionPanel.js b/src/Components/SearchExpansionPanel/SearchExpansionPanel.js index 7ebfc2c9e26e3ddb29e7445fe46f3df6bf090ce7..8df336aaa3c5966791ed1159775afc3ff301d23a 100644 --- a/src/Components/SearchExpansionPanel/SearchExpansionPanel.js +++ b/src/Components/SearchExpansionPanel/SearchExpansionPanel.js @@ -12,6 +12,8 @@ import SearchEPIdiomas from "./SearchEPIdiomas"; import { TextField } from "@material-ui/core"; import Grid from '@material-ui/core/Grid'; import CircularProgress from '@material-ui/core/CircularProgress'; +import Paper from '@material-ui/core/Paper'; +import styled from 'styled-components'; import './ExpansionPanel.css' @@ -77,7 +79,6 @@ export default function SearchExpansionPanel(props) { const onKeyPressed = (e) => { if (e.key === "Enter") { - const filterString = "&tags[]=" + keyWords if (keyWords.length === 0) { setErrorInKeyWord({ state: true, @@ -85,7 +86,7 @@ export default function SearchExpansionPanel(props) { }) } else - props.onChange("LearningObject", filterString) + props.setTag(keyWords) } } @@ -99,7 +100,7 @@ export default function SearchExpansionPanel(props) { } return ( - <div> + <MainPaper square elevation={4}> <link href="https://fonts.googleapis.com/css?family=Roboto:400,500&display=swap" rel="stylesheet" @@ -136,7 +137,7 @@ export default function SearchExpansionPanel(props) { </ExpansionPanel> <ExpansionPanel square> - <ExpansionPanelSummary + <ExpansionPanelSummary expandIcon={<ExpandMoreIcon />} aria-controls="panel2d-content" @@ -146,7 +147,11 @@ export default function SearchExpansionPanel(props) { </ExpansionPanelSummary> <ExpansionPanelDetails> <div> - <SearchEPCompCurriculum onChange={props.onChange} /> + <SearchEPCompCurriculum + onChange={props.onChange} + curriculumComponents={props.curriculumComponents} + setCurriculum={props.setCurriculum} + /> </div> </ExpansionPanelDetails> </ExpansionPanel> @@ -160,7 +165,11 @@ export default function SearchExpansionPanel(props) { <Typography>Tipos de Recurso</Typography> </ExpansionPanelSummary> <ExpansionPanelDetails> - <SearchEPTiposRec onChange={props.onChange} /> + <SearchEPTiposRec + onChange={props.onChange} + typeOfResources={props.typeOfResources} + setTypeRes={props.setTypeRes} + /> </ExpansionPanelDetails> </ExpansionPanel> @@ -173,7 +182,11 @@ export default function SearchExpansionPanel(props) { <Typography>Etapas de Ensino</Typography> </ExpansionPanelSummary> <ExpansionPanelDetails> - <SearchEPEtapasEns onChange={props.onChange} /> + <SearchEPEtapasEns + onChange={props.onChange} + teachingStage={props.teachingStage} + setTeachingStage={props.setTeachingStage} + /> </ExpansionPanelDetails> </ExpansionPanel> @@ -186,7 +199,11 @@ export default function SearchExpansionPanel(props) { <Typography>Idiomas</Typography> </ExpansionPanelSummary> <ExpansionPanelDetails> - <SearchEPIdiomas onChange={props.onChange} /> + <SearchEPIdiomas + onChange={props.onChange} + languages={props.languages} + setLanguages={props.setLanguages} + /> </ExpansionPanelDetails> </ExpansionPanel> @@ -210,6 +227,18 @@ export default function SearchExpansionPanel(props) { /> </ExpansionPanelDetails> </ExpansionPanel> - </div> + </MainPaper> ); } + +const MainPaper = styled(Paper)` + /* height: 150px; */ + text-align: center; + background-color: #fff; + margin-top: 5px; + margin-bottom: 30px; + color: #666; + .textInfo{ + text-align: start; + } +`; diff --git a/src/Components/SearchExpansionPanel/SesrchEPEtapasEns.js b/src/Components/SearchExpansionPanel/SesrchEPEtapasEns.js index b08fdb680ae4e0e7be65c4c327adf8b34b96b39c..632009aee017ee3b0347a8e1075d30d15376c89c 100644 --- a/src/Components/SearchExpansionPanel/SesrchEPEtapasEns.js +++ b/src/Components/SearchExpansionPanel/SesrchEPEtapasEns.js @@ -17,71 +17,45 @@ const useStyles = makeStyles(theme => ({ } })); -export default function SearchEPEtapasEns(props) { +export default function SearchEPEtapasEns({ teachingStage, setTeachingStage }) { const classes = useStyles(); - const [checked, setChecked] = React.useState([0]); - const handleToggle = value => () => { - const currentIndex = checked.indexOf(value); - const newChecked = [...checked]; - - if (currentIndex === -1) { - newChecked.push(value); - } else { - newChecked.splice(currentIndex, 1); - } - - setChecked(newChecked); - let filterString = ""; - - for(let i = 0; i < newChecked.length; i++){ - if(newChecked[i] !== 0){ - filterString = filterString + `&educational_stages[]=${newChecked[i]}` - } - } - if(filterString) - props.onChange("LearningObject", filterString) - else - props.onChange("LearningObject", "") + const handleToggle = (index) => () => { + const newTypeTeachingStage = [...teachingStage]; + newTypeTeachingStage[index].isChecked = !newTypeTeachingStage[index].isChecked + setTeachingStage(newTypeTeachingStage); }; - const filtrosEtapas = [ - { value: "1", exemplo: "Educação Infantil" }, - { value: "2", exemplo: "Ensino Fundamental I (1º até o 5º ano )" }, - { value: "3", exemplo: "Ensino Fundamental II (do 6º até o 9º ano)" }, - { value: "4", exemplo: "Ensino Médio" }, - { value: "5", exemplo: "Ensino Superior" }, - { value: "6", exemplo: "Outros" } - ]; - - return ( - <List className={classes.root}> - {filtrosEtapas.map(item => { - const labelId = `checkbox-list-label-${item.value}`; - return ( - <ListItem - key={item.exemplo} - role={undefined} - dense - button - onClick={handleToggle(item.value)} - > - <ListItemIcon> - <Checkbox - edge="start" - checked={checked.indexOf(item.value) !== -1} - tabIndex={-1} - disableRipple - inputProps={{ "aria-labelledby": labelId }} - /> - </ListItemIcon> - <ListItemText id={labelId} primary={item.exemplo} /> - <ListItemSecondaryAction> - <IconButton edge="end" aria-label="comments"></IconButton> - </ListItemSecondaryAction> - </ListItem> - ); - })} - </List> - ); + if (teachingStage) + return ( + <List className={classes.root}> + {teachingStage.map((item, index) => { + const labelId = `checkbox-list-label-${item.value}`; + + return ( + <ListItem + key={item.exemplo} + role={undefined} + dense + button + onClick={handleToggle(index)} + > + <ListItemIcon> + <Checkbox + edge="start" + checked={item.isChecked} + tabIndex={-1} + disableRipple + inputProps={{ "aria-labelledby": labelId }} + /> + </ListItemIcon> + <ListItemText id={labelId} primary={item.exemplo} /> + <ListItemSecondaryAction> + <IconButton edge="end" aria-label="comments"></IconButton> + </ListItemSecondaryAction> + </ListItem> + ); + })} + </List> + ); } diff --git a/src/Components/SearchPageComponents/CollectionTemplate.js b/src/Components/SearchPageComponents/CollectionTemplate.js new file mode 100644 index 0000000000000000000000000000000000000000..c3bcb3ee5b8568430afcc2eacd19a5882cd85b13 --- /dev/null +++ b/src/Components/SearchPageComponents/CollectionTemplate.js @@ -0,0 +1,124 @@ +import React, { useEffect } from 'react'; +import Paper from '@material-ui/core/Paper'; +import styled from 'styled-components'; +import Grid from '@material-ui/core/Grid'; +import LoadingSpinner from '../LoadingSpinner'; +import noCollections from '../../img/Pagina_vazia_colecao.png'; +import CollectionCardFunction from '../CollectionCardFunction'; +import IconButton from '@material-ui/core/IconButton'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; + +export default function ResourceTemplate({ isLoading, resources, totalResources, currPage, handlePreviousPage, handleNextPage }) { + const topRef = React.useRef(); + const totalPages = parseInt(totalResources) === 0 ? 0 : Math.ceil(totalResources / 12) - 1; //Dividing by 12 because i want to cath total pages, and results per page is 12 + + useEffect(() => { + topRef.current.scrollIntoView() + }, [isLoading]) + + return ( + <ResourcePaper elevation={4} square> + <div ref={topRef} /> + <Title> + Coleções encontradas ({totalResources}) + </Title> + { + isLoading ? + <LoadingSpinner text='Carregando Coleções...' /> + : + <Grid container justify='center' alignItems='center' spacing={3}> + { + resources.length >= 1 ? + resources.map((card) => { + return <Grid item key={new Date().toISOString() + card.id} > + <CollectionCardFunction + name={card.name} + tags={card.tags} + rating={card.review_average} + id={card.id} + author={card.owner ? card.owner.name : ""} + description={card.description} + thumbnails={card.items_thumbnails} + avatar={card.owner ? card.owner.avatar : ""} + likeCount={card.likes_count} + followed={card.followed} + liked={card.liked} + collections={card.collection_items} + authorID={card.owner.id} + /> + </Grid> + }) + : + <NoContentDiv> + <h3> + Desculpe, não há dados nessa página. + </h3> + <img src={noCollections} alt='No cards' /> + </NoContentDiv> + } + </Grid> + } + { + !isLoading && + <Grid container direction='row' alignItems='center' justify='center' spacing={3}> + <Grid item> + <StyledIconButton elevation={4} disabled={currPage === 0}> + <IconButton onClick={handlePreviousPage} disabled={currPage === 0}> + <ArrowBackIcon className='icon' /> + </IconButton> + </StyledIconButton> + </Grid> + <Grid item> + <ActualPage> + {currPage} + </ActualPage>...{totalPages} + </Grid> + <Grid item> + <StyledIconButton elevation={4} disabled={currPage === totalPages}> + <IconButton onClick={handleNextPage} disabled={currPage === totalPages}> + <ArrowForwardIcon className='icon' /> + </IconButton> + </StyledIconButton> + </Grid> + </Grid> + } + </ResourcePaper> + ) +}; + +const Title = styled.h4` + text-transform: uppercase; + font-weight: 500; + text-align: left; + color: #673ab7; +` +const NoContentDiv = styled.div` + >h3{ + color: #673ab7; + text-align: center; + } +` +const ActualPage = styled.span` + color: #673ab7; +` +const StyledIconButton = styled(Paper)` + border-radius: 50% !important; + background-color: ${props => props.disabled ? "#666" : "#673ab7"} !important; + .icon{ + color: ${props => props.disabled ? "#d4d4d4" : "white"}; + } +` + +const ResourcePaper = styled(Paper)` + /* height: 150px; */ + text-align: center; + background-color: #fff; + margin-top: 5px; + margin-bottom: 30px; + padding: 0.5em 1em; + color: #666; + .textInfo{ + text-align: start; + } +`; \ No newline at end of file diff --git a/src/Components/SearchPageComponents/Error.js b/src/Components/SearchPageComponents/Error.js new file mode 100644 index 0000000000000000000000000000000000000000..7cb9d98ce01c0006ef33a45422ba1357a119323d --- /dev/null +++ b/src/Components/SearchPageComponents/Error.js @@ -0,0 +1,30 @@ +import React from 'react'; +import styled from 'styled-components'; +import Paper from '@material-ui/core/Paper'; + +export default function Error() { + return <ResourcePaper square elevation={4}> + <Title> + Houve um erro durante a obtenção de dados :( + </Title> + </ResourcePaper> +} + +const ResourcePaper = styled(Paper)` + /* height: 150px; */ + text-align: center; + background-color: #fff; + margin-top: 5px; + margin-bottom: 30px; + padding: 0.5em 1em; + color: #666; + width: 100%; +`; + +const Title = styled.h4` + text-transform: uppercase; + font-weight: 500; + text-align: left; + color: #666; + text-align: center; +` \ No newline at end of file diff --git a/src/Components/SearchPageComponents/FilterSummary.js b/src/Components/SearchPageComponents/FilterSummary.js new file mode 100644 index 0000000000000000000000000000000000000000..9cc1a9aeea7868cf92bd7254adb7ab7dcaeb3aee --- /dev/null +++ b/src/Components/SearchPageComponents/FilterSummary.js @@ -0,0 +1,130 @@ +import React from 'react'; +import styled from 'styled-components'; +import Paper from '@material-ui/core/Paper'; +import Grid from '@material-ui/core/Grid'; +import Chip from '@material-ui/core/Chip'; +import Button from "@material-ui/core/Button"; + +export default function FilterSummary + ({ curriculumComponents, typeOfResources, languages, teachingStage, tag, onButtonClicked }) { + return ( + <FilterSummaryPaper square elevation={4}> + <h3 className="title"> + Resumo dos filtros selecionados + </h3> + <Grid container direction='column' spacing={2}> + <Grid item> + <Grid container direction='row' spacing={1} alignItems='center'> + <Grid item> + Componentes curriculares: + </Grid> + <Grid item> + { + curriculumComponents.map((item) => { + return ( + item.isChecked && + <StyledChip key={new Date().toISOString() + item.value} size="small" label={item.exemplo} /> + ); + + }) + } + </Grid> + </Grid> + </Grid> + <Grid item> + <Grid container direction='row' spacing={1} alignItems='center'> + <Grid item> + Tipos de recursos: + </Grid> + <Grid item> + { + typeOfResources.map((item) => { + return ( + item.isChecked && + <StyledChip key={new Date().toISOString() + item.value} size="small" label={item.exemplo} /> + ); + }) + } + </Grid> + </Grid> + </Grid> + <Grid item> + <Grid container direction='row' spacing={1} alignItems='center'> + <Grid item> + Etapas de ensino: + </Grid> + <Grid item> + { + teachingStage.map((item) => { + return ( + item.isChecked && + <StyledChip key={new Date().toISOString() + item.value} size="small" label={item.exemplo} /> + ); + }) + } + </Grid> + </Grid> + </Grid> + <Grid item> + <Grid container direction='row' spacing={1} alignItems='center'> + <Grid item> + Idiomas: + </Grid> + <Grid item> + { + languages.map((item) => { + return ( + item.isChecked && + <StyledChip key={new Date().toISOString() + item.value} size="small" label={item.exemplo} /> + ); + }) + } + </Grid> + </Grid> + </Grid> + <Grid item> + <Grid container direction='row' spacing={1} alignItems='center'> + <Grid item> + Palavra chave: + </Grid> + <Grid item> + { + tag && + <StyledChip size="small" label={tag} /> + } + </Grid> + </Grid> + </Grid> + <Grid item> + <StyledButton variant="contained" onClick={onButtonClicked}> + <span className="text"> + Aplicar filtro + </span> + </StyledButton> + </Grid> + </Grid> + </FilterSummaryPaper> + ) +} + +const FilterSummaryPaper = styled(Paper)` + background-color: #fff; + margin-top: 5px; + margin-bottom: 30px; + padding: 0.5em 1em; + .title{ + text-transform: uppercase; + color: #666; + font-weight: 500; + } +` +const StyledButton = styled(Button)` + background-color: #ff7f00 !important; + .text{ + color: white; + } +` + +const StyledChip = styled(Chip)` + margin: 0.2em +` diff --git a/src/Components/SearchPageComponents/HeaderFilters.js b/src/Components/SearchPageComponents/HeaderFilters.js new file mode 100644 index 0000000000000000000000000000000000000000..21bcc78c8527f9f6ee276af7ca6c1dc188352330 --- /dev/null +++ b/src/Components/SearchPageComponents/HeaderFilters.js @@ -0,0 +1,132 @@ +import React from 'react'; +import styled from 'styled-components'; +import Paper from '@material-ui/core/Paper'; +import Grid from '@material-ui/core/Grid'; +import TextField from '@material-ui/core/TextField'; +import MenuItem from '@material-ui/core/MenuItem'; + +export default function HeaderFilters({ options, orders, currOption, currOrder, handleChangeOption, handleChangeOrder }) { + + if (currOption !== 'User') + return ( + <FiltersPaper elevation={4} square> + <Grid container direction='row' spacing={2} alignItems='center'> + <Grid item xs={12} sm={6}> + <Grid container alignItems='center'> + <Grid item xs={12} md={2}> + <Label> + Buscar por: + </Label> + </Grid> + <Grid item xs={12} md={10}> + <TextField + select + fullWidth + value={currOption} + onChange={handleChangeOption} + variant="outlined" + > + {options.map((option) => ( + <MenuItem + key={option.value} + value={option.name} + name={option.value} + > + <span style={{ color: option.color }}> + {option.value} + </span> + </MenuItem> + ))} + </TextField> + </Grid> + </Grid> + </Grid> + + <Grid item xs={12} sm={6}> + <Grid container alignItems='center'> + <Grid item xs={12} md={2}> + <Label> + Ordenar por: + </Label> + </Grid> + <Grid item xs={12} md={10}> + <TextField + select + fullWidth + value={currOrder} + onChange={handleChangeOrder} + variant="outlined" + > + {orders.map((option) => ( + <MenuItem + key={option.value} + value={option.name} + name={option.value} + > + {option.value} + </MenuItem> + ))} + </TextField> + </Grid> + </Grid> + </Grid> + </Grid> + </FiltersPaper> + ) + else + return ( + <FiltersPaper elevation={4} square> + <Grid container direction='row' alignItems='center'> + <Grid item xs={12}> + <Grid container alignItems='center'> + <Grid item xs={12} md={2}> + <Label> + Buscar por: + </Label> + </Grid> + <Grid item xs={12} md={10}> + <TextField + select + fullWidth + value={currOption} + onChange={handleChangeOption} + variant="outlined" + > + {options.map((option) => ( + <MenuItem + key={option.value} + value={option.name} + name={option.value} + > + <span style={{ color: option.color }}> + {option.value} + </span> + </MenuItem> + ))} + </TextField> + </Grid> + </Grid> + </Grid> + </Grid> + </FiltersPaper> + ) +} + +const Label = styled.p` + text-align: center; + font-weight: 600; +` + + +const FiltersPaper = styled(Paper)` + /* height: 150px; */ + text-align: center; + background-color: #fff; + margin-top: 5px; + margin-bottom: 30px; + padding: 0.5em 1em; + color: #666; + .textInfo{ + text-align: start; + } +`; \ No newline at end of file diff --git a/src/Components/SearchPageComponents/ResourceTemplate.js b/src/Components/SearchPageComponents/ResourceTemplate.js new file mode 100644 index 0000000000000000000000000000000000000000..01f747366796e9d9a556861e6201399285622bea --- /dev/null +++ b/src/Components/SearchPageComponents/ResourceTemplate.js @@ -0,0 +1,124 @@ +import React, { useEffect } from 'react'; +import Paper from '@material-ui/core/Paper'; +import styled from 'styled-components'; +import Grid from '@material-ui/core/Grid'; +import LoadingSpinner from '../LoadingSpinner'; +import noResources from '../../img/Pagina_vazia_Sem_publicar.png'; +import ResourceCardFunction from '../ResourceCardFunction'; +import IconButton from '@material-ui/core/IconButton'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; + +export default function ResourceTemplate({ isLoading, resources, totalResources, currPage, handlePreviousPage, handleNextPage }) { + const totalPages = parseInt(totalResources) === 0 ? 0 : Math.ceil(totalResources / 12) - 1; //Dividing by 12 because i want to cath total pages, and results per page is 12 + const topRef = React.useRef(); + + useEffect(() => { + topRef.current.scrollIntoView(); + }, [isLoading]) + + return ( + <ResourcePaper elevation={4} square> + <div ref={topRef} /> + <Title> + Recursos encontrados ({totalResources}) + </Title> + { + isLoading ? + <LoadingSpinner text='Carregando recursos...' /> + : + <Grid container justify='center' alignItems='center' spacing={3}> + { + resources.length >= 1 ? + resources.map((card) => { + return <Grid item key={new Date().toISOString() + card.id} > + <ResourceCardFunction + avatar={card.publisher ? 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} + /> + </Grid> + }) + : + <NoContentDiv> + <h3> + Desculpe, não há dados nessa página. + </h3> + <img src={noResources} alt='No cards' /> + </NoContentDiv> + } + </Grid> + } + { + !isLoading && + <Grid container direction='row' alignItems='center' justify='center' spacing={3}> + <Grid item> + <StyledIconButton elevation={4} disabled={currPage === 0}> + <IconButton onClick={handlePreviousPage} disabled={currPage === 0}> + <ArrowBackIcon className='icon' /> + </IconButton> + </StyledIconButton> + </Grid> + <Grid item> + <ActualPage> + {currPage} + </ActualPage>...{totalPages} + </Grid> + <Grid item> + <StyledIconButton elevation={4} disabled={currPage === totalPages}> + <IconButton onClick={handleNextPage} disabled={currPage === totalPages}> + <ArrowForwardIcon className='icon' /> + </IconButton> + </StyledIconButton> + </Grid> + </Grid> + } + </ResourcePaper> + ) +}; + +const Title = styled.h4` + text-transform: uppercase; + font-weight: 500; + text-align: left; + color: #ff7f00; +` +const NoContentDiv = styled.div` + >h3{ + color: #ff7f00; + text-align: center; + } +` +const ActualPage = styled.span` + color: #ff7f00; +` +const StyledIconButton = styled(Paper)` + border-radius: 50% !important; + background-color: ${props => props.disabled ? "#666" : "#ff7f00"} !important; + .icon{ + color: ${props => props.disabled ? "#d4d4d4" : "white"}; + } +` + +const ResourcePaper = styled(Paper)` + /* height: 150px; */ + text-align: center; + background-color: #fff; + margin-top: 5px; + margin-bottom: 30px; + padding: 0.5em 1em; + color: #666; + .textInfo{ + text-align: start; + } +`; \ No newline at end of file diff --git a/src/Components/SearchPageComponents/UserTemplate.js b/src/Components/SearchPageComponents/UserTemplate.js new file mode 100644 index 0000000000000000000000000000000000000000..991a31d30efa8161dd15584f3455380d20c3b31e --- /dev/null +++ b/src/Components/SearchPageComponents/UserTemplate.js @@ -0,0 +1,119 @@ +import React, { useEffect } from 'react'; +import Paper from '@material-ui/core/Paper'; +import styled from 'styled-components'; +import Grid from '@material-ui/core/Grid'; +import LoadingSpinner from '../LoadingSpinner'; +import ContactCard from '../ContactCard'; +import IconButton from '@material-ui/core/IconButton'; +import ArrowBackIcon from '@material-ui/icons/ArrowBack'; +import ArrowForwardIcon from '@material-ui/icons/ArrowForward'; +import { apiDomain } from '../../env'; + +export default function ResourceTemplate({ isLoading, resources, totalResources, currPage, handlePreviousPage, handleNextPage }) { + const totalPages = parseInt(totalResources) === 0 ? 0 : Math.ceil(totalResources / 12) - 1; //Dividing by 12 because i want to cath total pages, and results per page is 12 + const topRef = React.useRef(); + + useEffect(() => { + topRef.current.scrollIntoView() + }, [isLoading]) + + return ( + <ResourcePaper elevation={4} square> + <div ref={topRef} /> + <Title> + Usuários encontrados ({totalResources}) + </Title> + { + isLoading ? + <LoadingSpinner text='Carregando recursos...' /> + : + <Grid container justify='center' alignItems='center' spacing={3}> + { + resources.length >= 1 ? + resources.map((card) => { + return <Grid item key={new Date().toISOString() + 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> + }) + : + <NoContentDiv> + <h3> + Desculpe, não há dados nessa página. + </h3> + </NoContentDiv> + } + </Grid> + } + { + !isLoading && + <Grid container direction='row' alignItems='center' justify='center' spacing={3}> + <Grid item> + <StyledIconButton elevation={4} disabled={currPage === 0}> + <IconButton onClick={handlePreviousPage} disabled={currPage === 0}> + <ArrowBackIcon className='icon' /> + </IconButton> + </StyledIconButton> + </Grid> + <Grid item> + <ActualPage> + {currPage} + </ActualPage>...{totalPages} + </Grid> + <Grid item> + <StyledIconButton elevation={4} disabled={currPage === totalPages}> + <IconButton onClick={handleNextPage} disabled={currPage === totalPages}> + <ArrowForwardIcon className='icon' /> + </IconButton> + </StyledIconButton> + </Grid> + </Grid> + } + </ResourcePaper> + ) +}; + +const Title = styled.h4` + text-transform: uppercase; + font-weight: 500; + text-align: left; + color: #00bcd4; +` +const NoContentDiv = styled.div` + >h3{ + color: #00bcd4; + text-align: center; + } +` +const ActualPage = styled.span` + color: #00bcd4; +` +const StyledIconButton = styled(Paper)` + border-radius: 50% !important; + background-color: ${props => props.disabled ? "#666" : "#00bcd4"} !important; + .icon{ + color: ${props => props.disabled ? "#d4d4d4" : "white"}; + } +` + +const ResourcePaper = styled(Paper)` + /* height: 150px; */ + text-align: center; + background-color: #fff; + margin-top: 5px; + margin-bottom: 30px; + padding: 0.5em 1em; + color: #666; + .textInfo{ + text-align: start; + } +`; \ No newline at end of file diff --git a/src/Components/SearchPageComponents/filters.js b/src/Components/SearchPageComponents/filters.js new file mode 100644 index 0000000000000000000000000000000000000000..822ea5cdde3acf5d88d2e29210d6243ee4ed56c3 --- /dev/null +++ b/src/Components/SearchPageComponents/filters.js @@ -0,0 +1,74 @@ +const filtersCurriculum = [ + { exemplo: "Arte", value: "3", isChecked: false }, + { exemplo: "Biologia", value: "5", isChecked: false }, + { exemplo: "Ciências da Natureza", value: "6", isChecked: false }, + { exemplo: "Direitos Humanos", value: "20", isChecked: false }, + { exemplo: "Educação Ambiental", value: "21", isChecked: false }, + { exemplo: "Educação do Campo", value: "22", isChecked: false }, + { exemplo: "Educação Especial", value: "23", isChecked: false }, + { exemplo: "Educação FÃsica", value: "7", isChecked: false }, + { exemplo: "Educação IndÃgena", value: "24", isChecked: false }, + { exemplo: "Educação Quilombola", value: "25", isChecked: false }, + { exemplo: "Educação Sexual", value: "26", isChecked: false }, + { exemplo: "Ensino Religioso", value: "16", isChecked: false }, + { exemplo: "Filosofia", value: "8", isChecked: false }, + { exemplo: "FÃsica", value: "9", isChecked: false }, + { exemplo: "Geografia", value: "10", isChecked: false }, + { exemplo: "História", value: "11", isChecked: false }, + { exemplo: "Informática", value: "18", isChecked: false }, + { exemplo: "LÃngua Espanhola", value: "1", isChecked: false }, + { exemplo: "LÃngua Inglesa", value: "2", isChecked: false }, + { exemplo: "LÃngua Portuguesa", value: "4", isChecked: false }, + { exemplo: "Matemática", value: "12", isChecked: false }, + { exemplo: "Outras LÃnguas", value: "15", isChecked: false }, + { exemplo: "Outros", value: "17", isChecked: false }, + { exemplo: "QuÃmica", value: "13", isChecked: false }, + { exemplo: "Sociologia", value: "14", isChecked: false } +]; + +const filtersTypes = [ + { value: "5", exemplo: "Animação", isChecked: false }, + { value: "20", exemplo: "Aplicativo móvel", isChecked: false }, + { value: "17", exemplo: "Apresentação", isChecked: false }, + { value: "7", exemplo: "Ãudio", isChecked: false }, + { value: "4", exemplo: "Experimento prático", isChecked: false }, + { value: "1", exemplo: "Imagem", isChecked: false }, + { value: "18", exemplo: "Infográfico", isChecked: false }, + { value: "19", exemplo: "Jogo", isChecked: false }, + { value: "21", exemplo: "Livro digital", isChecked: false }, + { value: "2", exemplo: "Mapa", isChecked: false }, + { value: "15", exemplo: "Outros", isChecked: false }, + { value: "3", exemplo: "Software Educacional", isChecked: false }, + { value: "6", exemplo: "Texto", isChecked: false }, + { value: "8", exemplo: "VÃdeo", isChecked: false }, + { value: "13", exemplo: "Website externo", isChecked: false }, + { value: "22", exemplo: "Plano de Aula", isChecked: false }, +]; + +const filtersStages = [ + { value: "1", exemplo: "Educação Infantil", isChecked: false }, + { value: "2", exemplo: "Ensino Fundamental I (1º até o 5º ano )", isChecked: false }, + { value: "3", exemplo: "Ensino Fundamental II (do 6º até o 9º ano)", isChecked: false }, + { value: "4", exemplo: "Ensino Médio", isChecked: false }, + { value: "5", exemplo: "Ensino Superior", isChecked: false }, + { value: "6", exemplo: "Outros", isChecked: false } +]; + +const filtersLanguages = [ + { value: "5", exemplo: "Alemão", isChecked: false }, + { value: "3", exemplo: "Espanhol", isChecked: false }, + { value: "4", exemplo: "Francês", isChecked: false }, + { value: "2", exemplo: "Inglês", isChecked: false }, + { value: "6", exemplo: "Italiano", isChecked: false }, + { value: "9", exemplo: "Japonês", isChecked: false }, + { value: "19", exemplo: "LIBRAS", isChecked: false }, + { value: "7", exemplo: "Mandarim", isChecked: false }, + { value: "10", exemplo: "Outro", isChecked: false }, + { value: "1", exemplo: "Português", isChecked: false }, + { value: "8", exemplo: "Russo", isChecked: false } +]; + +export { filtersCurriculum }; +export { filtersTypes }; +export { filtersStages }; +export { filtersLanguages }; diff --git a/src/Components/SignUpContainerFunction.js b/src/Components/SignUpContainerFunction.js index 89343fe5ea8d726c1cdb503b68cb280e82b10c46..15974aee411a66d7431d73f4ce7d6ba8b87d56a0 100644 --- a/src/Components/SignUpContainerFunction.js +++ b/src/Components/SignUpContainerFunction.js @@ -28,6 +28,7 @@ import {apiUrl} from '../env.js' import {GoogleLoginButton} from './LoginContainerFunction' import ValidateUserInput from './HelperFunctions/FormValidationFunction.js' import GoogleLogo from "../img/logo_google.svg" +import ReCaptcha from 'react-recaptcha' async function handleGoogleAttempt () { console.log("handleGoogleAttempt") @@ -37,6 +38,8 @@ async function handleGoogleAttempt () { window.location.replace(request_url) } export default function SignUpContainer (props) { + const [unavailableButton, setButtonAvailability] = useState(true); + const [formNome, setNome] = useState( { key : false, @@ -137,6 +140,12 @@ export default function SignUpContainer (props) { } } + function captchaVerified (response) { + if (response) { + setButtonAvailability(false) + } + } + return ( <ContainerStyled > <DialogHeaderStyled> @@ -208,8 +217,17 @@ export default function SignUpContainer (props) { help = {formConfirmation.key ? (formConfirmation.value.length === 0 ? "Faltou digitar sua senha." : (formConfirmation.value !== formSenha.value ? "As senhas precisam ser iguais" : "A senha precisa ter no mÃnimo 8 caracteres.")) : ""} /> <br/> + <div style={{margin:"0 auto", width: "304px"}}> + { + //<ReCaptcha sitekey={process.env.REACT_APP_SITE_KEY} verifyCallback={captchaVerified} /> //when key set in env + <ReCaptcha sitekey="6LfxuKUUAAAAAIzYpCzEtJyeE8QRjBYa44dvHlTX" verifyCallback={captchaVerified} /> //use this one on production + //<ReCaptcha sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI" verifyCallback={captchaVerified}/> //test key, from google, do not use this one on production + } + </div> <ConfirmContainerStyled> - <StyledSignUpButton type="submit" variant="contained"> + <StyledSignUpButton type="submit" variant="contained" disabled={unavailableButton} + style={unavailableButton ? { backgroundColor: "#e9e9e9" } : { backgroundColor: "#00bcd4" }} + > <span style={{paddingLeft:"16px", paddingRight:"16px", borderRadius:"3px", boxSizing:"border-box", fontFamily:"Roboto, sans serif", fontWeight:"500", color:"#fff"}} @@ -335,7 +353,6 @@ const ConfirmContainerStyled = styled.div` ` const StyledSignUpButton = styled(Button)` - background-color: #00bcd4 !important; box-shadow : none !important; outline: none !important; border : 0 !important; diff --git a/src/Components/SignUpModal.js b/src/Components/SignUpModal.js index e01678072f356a5f7aa4a76da8edfd3052e01167..61c4fb2865b34df44615e742507d94df28e43ad7 100644 --- a/src/Components/SignUpModal.js +++ b/src/Components/SignUpModal.js @@ -15,7 +15,7 @@ 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 React, {useContext, useState} from 'react'; import Modal from '@material-ui/core/Modal'; import Backdrop from '@material-ui/core/Backdrop'; import Fade from '@material-ui/core/Fade'; @@ -23,11 +23,27 @@ import styled from 'styled-components' import SignUpContainer from './SignUpContainerFunction.js' import {Store} from '../Store.js' import {authentication} from './HelperFunctions/getAxiosConfig' +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; //import {postRequest} from './HelperFunctions/getAxiosConfig' +export function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; +} + export default function SignUpModal (props) { const { state, dispatch } = useContext(Store) + const [snackbarOpened, handleSnackbar] = useState(false) + + const handleCloseSnackbar = (event, reason) => { + if (reason === 'clickaway') { + return; + } + + handleSnackbar(false); + } + function handleSuccess (data) { dispatch ({ type: 'USER_SIGNED_UP', @@ -36,6 +52,11 @@ export default function SignUpModal (props) { }) props.handleClose() } + + function handleError (error) { + handleSnackbar(true) + } + const handleLoginInfo = (newLogin) => { const url = `/auth` const payload = { @@ -46,32 +67,39 @@ export default function SignUpModal (props) { // terms_of_service : true, // avatar: "" } - authentication(url, payload, handleSuccess, (error) => {console.log(error)}) + authentication(url, payload, handleSuccess, handleError) //postRequest(url, payload, handleSuccess, (error) => {console.log(error)}) } return ( - <StyledModalSignUp - 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}> - <SignUpContainer - handleClose={props.handleClose} - openLogin={props.openLogin} - handleLoginInfo = {handleLoginInfo} - /> - </Fade> - </StyledModalSignUp> + <> + <Snackbar open={snackbarOpened} autoHideDuration={1000} onClose={handleCloseSnackbar} + anchorOrigin = {{ vertical:'top', horizontal:'right' }} + > + <Alert severity="error">Ocorreu um erro ao se conectar!</Alert> + </Snackbar> + <StyledModalSignUp + 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}> + <SignUpContainer + handleClose={props.handleClose} + openLogin={props.openLogin} + handleLoginInfo = {handleLoginInfo} + /> + </Fade> + </StyledModalSignUp> + </> ) } diff --git a/src/Components/SnackbarComponent.js b/src/Components/SnackbarComponent.js index b0bd36a67d134d598e603d3d8c749763132579d7..60692e9c43f7298f34b9eed84eda31ab36cb640b 100644 --- a/src/Components/SnackbarComponent.js +++ b/src/Components/SnackbarComponent.js @@ -25,7 +25,7 @@ export default function SnackbarComponent(props) { <Snackbar open={props.snackbarOpen} autoHideDuration={3000} onClose={props.handleClose} anchorOrigin={{ vertical: 'top', horizontal: 'right' }} > - <Alert severity={props.severity} style={props.color ? { backgroundColor: props.color } : { backgroundColor: "#00acc1" }}> + <Alert severity={props.severity}> {props.text} </Alert> </Snackbar> diff --git a/src/Components/TabPanels/PanelComponents/ButtonsArea.js b/src/Components/TabPanels/PanelComponents/ButtonsArea.js index 848001761ebc4f63beb1f5cc1c46a317dc8158ab..1b8633ae0b05f6578b98fbbba427a3172775ed96 100644 --- a/src/Components/TabPanels/PanelComponents/ButtonsArea.js +++ b/src/Components/TabPanels/PanelComponents/ButtonsArea.js @@ -29,16 +29,15 @@ export function ButtonsAreaRecurso(props) { </p> { - props.end ? - null : - <React.Fragment> - <ButtonMostrarMaisRecurso onClick={() => props.showMore(4)}> - <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> - </ButtonMostrarMaisRecurso> - <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> - <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> - </ButtonMostrarTodos> - </React.Fragment> + !props.end && + <React.Fragment> + <ButtonMostrarMaisRecurso onClick={() => props.showMore(4)}> + <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> + </ButtonMostrarMaisRecurso> + <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> + <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> + </ButtonMostrarTodos> + </React.Fragment> } </Carregados> @@ -52,18 +51,16 @@ export function ButtonsAreaColecao(props) { {props.sliceLength} coleções carregadas de {props.total} </p> { - props.end ? - null - : - <React.Fragment> - <ButtonMostrarMaisColecao onClick={() => { props.showMore(4) }}> - <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> - </ButtonMostrarMaisColecao> - - <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> - <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> - </ButtonMostrarTodos> - </React.Fragment> + !props.end && + <React.Fragment> + <ButtonMostrarMaisColecao onClick={() => { props.showMore(4) }}> + <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> + </ButtonMostrarMaisColecao> + + <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> + <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> + </ButtonMostrarTodos> + </React.Fragment> } </Carregados> ) @@ -77,18 +74,16 @@ export function ButtonsAreaRede(props) { </p> { - props.end ? - null - : - <React.Fragment> - <ButtonMostrarMaisRede onClick={() => { props.showMore(4) }}> - <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> - </ButtonMostrarMaisRede> - - <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> - <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> - </ButtonMostrarTodos> - </React.Fragment> + !props.end && + <React.Fragment> + <ButtonMostrarMaisRede onClick={() => { props.showMore(4) }}> + <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> + </ButtonMostrarMaisRede> + + <ButtonMostrarTodos onClick={() => { props.showMore(20) }}> + <span style={{ color: "#666", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> + </ButtonMostrarTodos> + </React.Fragment> } </Carregados> diff --git a/src/Components/TabPanels/PanelComponents/NoContent.js b/src/Components/TabPanels/PanelComponents/NoContent.js index ef129ecef30c18abc9ab58d501330ab8b778678f..7c8c7141476c3c2793931b448168ce3db00ddc50 100644 --- a/src/Components/TabPanels/PanelComponents/NoContent.js +++ b/src/Components/TabPanels/PanelComponents/NoContent.js @@ -18,13 +18,21 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React from 'react' import styled from 'styled-components' +import defaultNoContent from '../../../img/img-16.png' -export default function NoContent (props) { + + +export default function NoContent({text, image}) { return ( <DivTextoNoPublications> <InnerDiv> - <NoPubSpan>{props.text}</NoPubSpan> + <ImgDiv> + <img alt="" src={image || defaultNoContent } style={{ width: "130px", verticalAlign: "middle", border: "0" }} /> + </ImgDiv> + <TextDiv> + <NoPubSpan>{text}</NoPubSpan> + </TextDiv> </InnerDiv> </DivTextoNoPublications> ) @@ -44,11 +52,18 @@ const InnerDiv = styled.div` transform : translateY(-50%); ` +const ImgDiv = styled.div` + margin-bottom: 25px; +` + +const TextDiv = styled.div` +` + export const DivTextoNoPublications = styled.div` height : 360px; - text-align : center; padding-left : 15px; padding-right : 15px; + text-align : center; ` // {/*const DivConteudoNaoPublicado = styled.div` diff --git a/src/Components/TabPanels/PanelComponents/PanelTitle.js b/src/Components/TabPanels/PanelComponents/PanelTitle.js index ffe073623b4fa46f583ca4f513b9cb4c7f9c1565..cb139b40670af05ad9e9d7adc3fc8a873d378d3a 100644 --- a/src/Components/TabPanels/PanelComponents/PanelTitle.js +++ b/src/Components/TabPanels/PanelComponents/PanelTitle.js @@ -19,6 +19,7 @@ const Header = styled(Grid)` .titulo { margin : 0; + line-height: normal; font-style : normal; color : #757575; font-size : 1.857em; diff --git a/src/Components/TabPanels/PanelComponents/TemplateColecao.js b/src/Components/TabPanels/PanelComponents/TemplateColecao.js index 7af99a6cf6e901be5a1c03276475edb85a4dc44e..b1526eb584834bb5c45f03436eef946c512b8512 100644 --- a/src/Components/TabPanels/PanelComponents/TemplateColecao.js +++ b/src/Components/TabPanels/PanelComponents/TemplateColecao.js @@ -24,6 +24,7 @@ import Title from './PanelTitle.js' import { WhiteContainer, StyledGrid } from '../StyledComponents.js' import { ButtonsAreaColecao } from './ButtonsArea' import LoadingSpinner from '../../LoadingSpinner.js' +import noCollFound from '../../../img/Pagina_vazia_colecao.png' export default function PanelTemplateColecao(props) { const RenderFollowedColCard = (card, followerBoolean) => { @@ -86,7 +87,10 @@ export default function PanelTemplateColecao(props) { : props.length === 0 ? ( - <NoContent text={props.noContentText} /> + <NoContent + text={props.noContentText} + image={noCollFound} + /> ) : ( @@ -109,7 +113,7 @@ export default function PanelTemplateColecao(props) { length={props.length} showMore={props.showMore} total={props.end} - end={String(props.sliceArr.length) === props.end} + end={String(props.sliceArr.length) === props.end || Number(props.sliceArr.length) === props.end} /> } </React.Fragment> diff --git a/src/Components/TabPanels/PanelComponents/TemplateCuradoria.js b/src/Components/TabPanels/PanelComponents/TemplateCuradoria.js index 4426a239ded8dc1c3d42925e8f83caa7c59598d7..d03415734eb03a7a7ea0ecb7671a50840240c815 100644 --- a/src/Components/TabPanels/PanelComponents/TemplateCuradoria.js +++ b/src/Components/TabPanels/PanelComponents/TemplateCuradoria.js @@ -83,7 +83,7 @@ export default function Template(props) { sliceLength={props.sliceArr.length} length={props.length} showMore={props.showMore} - end={String(props.sliceArr.length) === props.end} + end={String(props.sliceArr.length) === props.end || Number(props.sliceArr.length) === props.end} total={props.end} /> } diff --git a/src/Components/TabPanels/PanelComponents/TemplateRecurso.js b/src/Components/TabPanels/PanelComponents/TemplateRecurso.js index 6bf05604c0d56eef5e435c449b2b8cc103517572..d77f0208d3f072a5385a598d9d99c74e963cead2 100644 --- a/src/Components/TabPanels/PanelComponents/TemplateRecurso.js +++ b/src/Components/TabPanels/PanelComponents/TemplateRecurso.js @@ -24,6 +24,7 @@ import Title from './PanelTitle.js' import { WhiteContainer, StyledGrid } from '../StyledComponents.js' import { ButtonsAreaRecurso } from './ButtonsArea' import LoadingSpinner from '../../LoadingSpinner.js' +import noLearnObjFound from '../../../img/Pagina_vazia_Sem_publicar.png' export default function Template(props) { @@ -44,7 +45,10 @@ export default function Template(props) { : props.length === 0 ? ( - <NoContent text={props.noContentText} /> + <NoContent + text={props.noContentText} + image={noLearnObjFound} + /> ) : ( @@ -82,7 +86,7 @@ export default function Template(props) { length={props.length} showMore={props.showMore} total={props.end} - end={String(props.slice.length) === props.end} + end={Number(props.slice.length) === props.end || String(props.slice.length) === props.end} /> } diff --git a/src/Components/TabPanels/PanelComponents/TemplateRede.js b/src/Components/TabPanels/PanelComponents/TemplateRede.js index c792b7d2de531c63ef2ec1b44b2f4a61b992b163..e5d2a845a2b2cc388331c622912ac904844379be 100644 --- a/src/Components/TabPanels/PanelComponents/TemplateRede.js +++ b/src/Components/TabPanels/PanelComponents/TemplateRede.js @@ -94,7 +94,7 @@ export default function PanelTemplateRede(props) { length={props.length} showMore={props.showMore} total={props.end} - end={String(props.sliceArr.length) === props.end} + end={String(props.sliceArr.length) === props.end || Number(props.sliceArr.length) === props.end} /> } </React.Fragment> diff --git a/src/Components/TabPanels/PublicUserPageTabs/TabColecoes.js b/src/Components/TabPanels/PublicUserPageTabs/TabColecoes.js index 4b46dc0700385baa2b787e847b8a671ed3f1f262..9b987347a51274465b78e7db062a99bd6d9a2273 100644 --- a/src/Components/TabPanels/PublicUserPageTabs/TabColecoes.js +++ b/src/Components/TabPanels/PublicUserPageTabs/TabColecoes.js @@ -21,7 +21,7 @@ import { fetchAllRequest, getRequest } from '../../HelperFunctions/getAxiosConfi import PanelTemplateColecao from '../PanelComponents/TemplateColecao.js' import LoadingSpinner from '../../LoadingSpinner.js' -export default function TabColecoes(props) { +export default function TabColecoes({id, username}) { const [loading, handleLoading] = useState(true) const [errorInUserColl, setErrorInUserColl] = useState(false) @@ -52,7 +52,7 @@ export default function TabColecoes(props) { const getInfo = () => { const urls = [ - `/users/${props.id}/collections?offset=0&limit=4`, + `/users/${id}/collections?offset=0&limit=4`, ] fetchAllRequest(urls, handleSuccess, handleError) } @@ -66,7 +66,7 @@ export default function TabColecoes(props) { const limit = limite; setLoadingMoreUserColl(true); setCurrLimitUserColl(currLimitUserColl + limit) - const url = `/users/${props.id}/collections?offset=${currLimitUserColl}&limit=${limit}`; + const url = `/users/${id}/collections?offset=${currLimitUserColl}&limit=${limit}`; getRequest(url, (data) => { if (data.errors) { @@ -98,14 +98,14 @@ export default function TabColecoes(props) { { loading ? ( - <LoadingSpinner text={'CARREGANDO COLEÇÕES'} /> + <LoadingSpinner text={`Carregando coleções de ${username}`} /> ) : ( <PanelTemplateColecao title={"Coleções Públicas"} length={userCollections.length} - noContentText={props.username + " não possui nenhuma coleção."} + noContentText={username + " não possui nenhuma coleção."} sliceArr={userCollections} showMore={showMoreUserCollections} loadingMore={loadingMoreUserColl} diff --git a/src/Components/TabPanels/PublicUserPageTabs/TabInicio.js b/src/Components/TabPanels/PublicUserPageTabs/TabInicio.js index 0663a44c4412e545429c7b560bf9eb2ca9e88126..7965d58e5111ad748a22cdf2672c25f05bc3f3ce 100644 --- a/src/Components/TabPanels/PublicUserPageTabs/TabInicio.js +++ b/src/Components/TabPanels/PublicUserPageTabs/TabInicio.js @@ -19,11 +19,8 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> import React from 'react' import styled from 'styled-components' import UserDescription from './UserDescription.js' -import NoContentImage from '../../../img/img-16.png' -import Grid from '@material-ui/core/Grid'; -import LastLearnObjs from './LastLearnObj.js' -import LastCols from './LastCollections.js' -import {ContainerStyled} from '../StyledComponents.js' +import Template from '../PanelComponents/TemplateRecurso' +import PanelTemplateColecao from '../PanelComponents/TemplateColecao.js' const NoContentContainer = styled.div` height : 250px; @@ -46,11 +43,11 @@ const NoContentContainer = styled.div` } ` /*Displays given image and text saying user hasn't posted anything yet*/ -export function NoContent (props) { +export function NoContent(props) { return ( <NoContentContainer> - <div style={{paddingTop : "1em"}}> - <img alt="" src={props.image} style={{width : "130px", verticalAlign : "middle", border : "0"}}/> + <div style={{ paddingTop: "1em" }}> + <img alt="" src={props.image} style={{ width: "130px", verticalAlign: "middle", border: "0" }} /> <h3> {props.text1} </h3> @@ -63,55 +60,36 @@ export function NoContent (props) { ) } -export default function TabInicio (props) { - +export default function TabInicio({ id, user, learningObjs, collections }) { return ( <React.Fragment> {/*display user description*/} - {props.user.description && - <UserDescription text={props.user.description}/> - } { - props.user.learning_objects_count === 0 && props.user.collections_count === 0 ? - ( - [ - <ContainerStyled> - <Grid container> - <Grid item xs={12}> - <NoContent - image={NoContentImage} - text1={props.user.name + " ainda não disponibilizou nenhum recurso ou coleção."} - text2={"Quando disponibilizar, eles aparecerão aqui."} - /> - </Grid> - </Grid> - </ContainerStyled> - ] - ) - : - ( - [ - <React.Fragment> - <ContainerStyled style={{flexDirection : "column"}}> - <LastLearnObjs - count={props.user.learning_objects_count} - username={props.user.name} - learningObjs={props.learningObjs} - /> - </ContainerStyled> - - <ContainerStyled style={{flexDirection : "column", paddingTop : "1em"}}> - <LastCols - count={props.user.collections_count} - username={props.user.name} - collections={props.collections} - /> - </ContainerStyled> - </React.Fragment> - ] - ) + user.description && + <UserDescription text={user.description} /> } - {/*display last published learning objects and last alterations in user collections*/} + <Template + length={learningObjs.length} + titleText={learningObjs.length === 1 ? `Último Recurso de ${user.name}` : `Últimos recursos de ${user.name}`} + noContentText={`${user.name} não publicou nenhum recursos ainda`} + slice={learningObjs} + showMore={() => { }} // there is no function here, because we don't want to display more resources in this tab + loadingMore={false} + end={learningObjs.length} + error={false} + /> + <PanelTemplateColecao + title={`Últimas coleçoes de ${user.name}`} + length={collections.length} + noContentText={`${user.name} não publicou nenhuma coleção ainda`} + sliceArr={collections} + showMore={() => { }} // there is no function here, because we don't want to display more collections in this tab + loadingMore={false} + end={collections.length} + followed={false} + error={false} + /> + </React.Fragment> diff --git a/src/Components/TabPanels/PublicUserPageTabs/TabRecursos.js b/src/Components/TabPanels/PublicUserPageTabs/TabRecursos.js index bbce193bcde870391dda55ee9a67c79aacb768b4..b8f38e36b55e62c26f5df389ba6b80bbdba6a301 100644 --- a/src/Components/TabPanels/PublicUserPageTabs/TabRecursos.js +++ b/src/Components/TabPanels/PublicUserPageTabs/TabRecursos.js @@ -17,94 +17,92 @@ 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 { HeaderGrid, ContainerStyled, Carregados } from '../StyledComponents.js' -import Grid from '@material-ui/core/Grid'; -import ResourceCardFunction from '../../ResourceCardFunction.js' -import { ButtonMostrarMaisRecurso } from '../PanelComponents/ButtonsArea' +import LoadingSpinner from '../../LoadingSpinner.js' +import Template from '../PanelComponents/TemplateRecurso.js' import { getRequest } from '../../HelperFunctions/getAxiosConfig' -import { StyledGrid } from '../StyledComponents' - -export default function TabRecursos(props) { - const [arr, setArr] = useState([]) - const [objsSlice, setSlice] = useState([]) - const handleSlice = (newArr) => { setSlice(newArr) } - useEffect(() => { - setArr(props.learningObjs) - setSlice(props.learningObjs.slice(0, 4)) - }, []) +export default function TabPanelAtividades({id, username}) { + const [loading, handleLoading] = useState(true) - function handleSuccess(data) { - setArr(data) - setSlice(data) - } - const showMore = (quantity) => { - var sliceLength = objsSlice.length - var newLength = sliceLength + quantity + const [errorInLearnObj, setErrorInLearnObj] = useState(false) + const [loadingMoreLearnObj, setLoadingMoreLearnObj] = useState(false) + const [currLimitLearnObj, setCurrLimitLearnObj] = useState(4); + const [endOfLearnObj, setEndofLearndObj] = useState(0); + const [learningObjects, setLearningObjects] = useState([]); - if (newLength > 12) { - const url = `/users/${props.id}/learning_objects?limit=${newLength}$offset=4` - getRequest(url, handleSuccess, (error) => { console.log(error) }) + function handleSuccess(data, headers) { + setErrorInLearnObj(data.errors ? true : false) + setLearningObjects(data) + if (headers.has('X-Total-Count')) { + setEndofLearndObj(headers.get('X-Total-Count')); } - else { - handleSlice(arr.slice(0, sliceLength + quantity)) - } - + handleLoading(false) } - return ( - <ContainerStyled style={{ flexDirection: "column" }}> + function handleError(error) { + handleLoading(false) + setErrorInLearnObj(true) + } - <HeaderGrid container> - <Grid item xs={12}> - <h3>Recursos Publicados <b style={{ fontWeight: "500" }}>({props.count})</b></h3> - </Grid> - </HeaderGrid> + useEffect(() => { + const url = `/users/${id}/learning_objects?offset=0&limit=4`; + handleLoading(true); + getRequest(url, handleSuccess, handleError); + }, []) - <StyledGrid container spacing={1} style={{ paddingLeft: "30px", paddingRight: "15px" }}> - { - objsSlice.map((card) => - <Grid item xs={12} sm={6} md={'auto'} lg={3} 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.publisher.name} - tags={card.tags} - href={"/recurso/" + card.id} - downloadableLink={card.default_attachment_location} - /> - </Grid> - ) + const showMoreLearnObj = (limite) => { + setLoadingMoreLearnObj(true); + const limit = limite; + setCurrLimitLearnObj(currLimitLearnObj + limit) + const url = `/users/${id}/learning_objects?offset=${currLimitLearnObj}&limit=${limit}`; + getRequest(url, + (data) => { + if (data.errors) { + setLoadingMoreLearnObj(false); + setErrorInLearnObj(true) } - </StyledGrid> - - <Carregados> - <p style={{ margin: "0 0 10px", fontSize: "14px" }}> - Carregados {objsSlice.length} de {arr.length} - </p> - - { - props.count > 5 && - <React.Fragment> - <ButtonMostrarMaisRecurso onClick={() => { showMore(4) }}> - <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 4</span> - </ButtonMostrarMaisRecurso> - - <ButtonMostrarMaisRecurso onClick={() => { showMore(20) }}> - <span style={{ color: "#fff", fontSize: "14px", fontWeight: "500" }}>MOSTRAR MAIS 20</span> - </ButtonMostrarMaisRecurso> - </React.Fragment> + else if (data.length >= 1) { + let currData = [...learningObjects]; + currData = [...currData.concat(data)]; + setLoadingMoreLearnObj(false); + setLearningObjects(currData); } + else { + setLoadingMoreLearnObj(false); + } + }, + (error) => { + setLoadingMoreLearnObj(false); + setErrorInLearnObj(true) + } + ) + } - </Carregados> - - </ContainerStyled> + return ( + <> + { + loading ? + ( + <LoadingSpinner text={`Carregando os recursos de ${username}`} /> + ) + : + ( + [ + <React.Fragment> + <Template + length={learningObjects.length} + titleText={learningObjects.length === 1 ? `Recurso publicado de ${username}` : `Recursos publicados ${username}`} + noContentText={`${username} ainda não publicou nenhum Recurso!`} + slice={learningObjects} + showMore={showMoreLearnObj} + loadingMore={loadingMoreLearnObj} + end={endOfLearnObj} + error={errorInLearnObj} + /> + </React.Fragment> + ] + ) + } + </> ) } diff --git a/src/Components/TabPanels/PublicUserPageTabs/TabRede.js b/src/Components/TabPanels/PublicUserPageTabs/TabRede.js index 6b8a8a8ee73eb0ede45b2b3ed40785697169cbac..81334d46c6edc88b10c8df88fa0df5366edec587 100644 --- a/src/Components/TabPanels/PublicUserPageTabs/TabRede.js +++ b/src/Components/TabPanels/PublicUserPageTabs/TabRede.js @@ -21,7 +21,7 @@ import PanelTemplateRede from '../PanelComponents/TemplateRede.js' import { fetchAllRequest, getRequest } from '../../HelperFunctions/getAxiosConfig' import LoadingSpinner from '../../LoadingSpinner.js' -export default function TabRede (props) { +export default function TabRede ({id, username}) { const [loading, handleLoading] = useState(true) const [errorInFollowing, setErrorInFollowing] = useState(false) @@ -41,7 +41,7 @@ export default function TabRede (props) { setLoadingFollowing(true); const limit = limite; setCurrFollowingLimit(currFollowingLimit + limit) - const url = `/users/${props.id}/following/User?offset=${currFollowingLimit}&limit=${limit}`; + const url = `/users/${id}/following/User?offset=${currFollowingLimit}&limit=${limit}`; getRequest(url, (data) => { if (data.errors) { @@ -72,7 +72,7 @@ export default function TabRede (props) { setLoadingMoreFollowers(true); const limit = limite; setFollowersLimit(currFollowerLimit + limit) - const url = `/users/${props.id}/followers?offset=${currFollowerLimit}&limit=${limit}`; + const url = `/users/${id}/followers?offset=${currFollowerLimit}&limit=${limit}`; getRequest(url, (data) => { if (data.errors) { @@ -125,7 +125,7 @@ export default function TabRede (props) { useEffect( () => { handleLoading(true) - const urls = [`/users/${props.id}/followers`, `/users/${props.id}/following/User`] + const urls = [`/users/${id}/followers`, `/users/${id}/following/User`] fetchAllRequest(urls, handleSuccess, handleErrors) }, []) @@ -136,7 +136,7 @@ export default function TabRede (props) { loading ? ( [ - <LoadingSpinner text={'CARREGANDO...'} /> + <LoadingSpinner text={`Carregando dados de ${username}`} /> ] ) : @@ -144,7 +144,7 @@ export default function TabRede (props) { [ <React.Fragment> <PanelTemplateRede - title={"Seguidores"} + title={`Seguidores de ${username}`} length={followersList.length} sliceArr={followersList} showMore={showMoreFollowers} @@ -152,11 +152,11 @@ export default function TabRede (props) { end={endOfFollowers} loadingMore={loadingMoreFollowers} error={errorInFollowers} - noContentText={props.username + ' não possui nenhum seguidor'} + noContentText={username + ' não possui nenhum seguidor'} /> <PanelTemplateRede - title={"Seguindo"} + title={`${username} está seguindo`} length={followingList.length} sliceArr={followingList} showMore={showMoreFollowing} @@ -164,7 +164,7 @@ export default function TabRede (props) { end={endOfFollowing} loadingMore={loadingMoreFollowing} error={errorInFollowing} - noContentText={props.username + ' não segue nenhum usuário'} + noContentText={username + ' não segue nenhum usuário'} /> </React.Fragment> ] diff --git a/src/Components/TabPanels/UserPageTabs/PanelAtividades.js b/src/Components/TabPanels/UserPageTabs/PanelAtividades.js index 1d51d2f134a4696bf4c3ed6dd2118b50547dca7c..bd7fd73dce890f685a1e6aba0aa3f9b2e348a42c 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelAtividades.js +++ b/src/Components/TabPanels/UserPageTabs/PanelAtividades.js @@ -168,7 +168,8 @@ export default function TabPanelAtividades(props) { <NoNotificationsDiv> <div> <div> - <H3Styled><img src={Bolo} alt='bolo' style={{ width: "23px" }} /> Você se cadastrou na Plataforma</H3Styled> + <img src={Bolo} alt='bolo' style={{ width: "23px", display: "block", marginLeft: "auto", marginRight: "auto" }} /> + <H3Styled>Você se cadastrou na Plataforma</H3Styled> </div> <p style={{ fontSize: "15px", fontWeight: "lighter", margin: "0 0 10px", display: "flex", justifyContent: "center", textAlign: "center" }} @@ -259,6 +260,7 @@ const H3Styled = styled.h3` margin-bottom : 10px; display : flex; justify-content : center; + text-align : center; align-items : center; ` diff --git a/src/Components/TabPanels/UserPageTabs/PanelColecoes.js b/src/Components/TabPanels/UserPageTabs/PanelColecoes.js index eef4d1eaa7df0728081c75d13d87e15db0f199b7..3abc14f58d9dae31f8a949f890890dcfa0f85c25 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelColecoes.js +++ b/src/Components/TabPanels/UserPageTabs/PanelColecoes.js @@ -23,7 +23,6 @@ import Grid from '@material-ui/core/Grid'; import LoadingSpinner from '../../LoadingSpinner.js' import PanelTemplateColecao from '../PanelComponents/TemplateColecao.js' import PaginaVaziaColecao from '../../../img/Pagina_vazia_colecao.png' -import NoContent from '../PanelComponents/NoContent.js' import { WhiteContainer, StyledGrid } from '../StyledComponents.js' import CreateNewFolderIcon from '@material-ui/icons/CreateNewFolder'; import Title from '../PanelComponents/PanelTitle.js' @@ -47,12 +46,12 @@ export default function TabPanelColecoes(props) { const [loadingMoreUserColl, setLoadingMoreUserColl] = useState(false); const [loadingMoreFollowedColl, setLoadingMoreFollowedColl] = useState(false); - const [endOfUserColl, setEndOfUserColl] = useState(false); - const [endOfFollowedColl, setEndOfFollowedColl] = useState(false); + const [endOfUserColl, setEndOfUserColl] = useState(0); + const [endOfFollowedColl, setEndOfFollowedColl] = useState(0); - const removeColl = (itemId) => { - let newSlice = userCollections.filter(item => item.id !== itemId); - setUserCollections(newSlice); + const removeColl = (itemId) => { + let newSlice = userCollections.filter(item => item.id !== itemId); + setUserCollections(newSlice); setEndOfUserColl(String(endOfUserColl - 1)) }; @@ -100,7 +99,6 @@ export default function TabPanelColecoes(props) { (data) => { if (data.errors) { setLoadingMoreUserColl(false); - setEndOfUserColl(true) setErrorInUserColl(true) } else if (data.length >= 1) { @@ -111,12 +109,10 @@ export default function TabPanelColecoes(props) { } else { setLoadingMoreUserColl(false); - setEndOfUserColl(true) } }, (error) => { setLoadingMoreUserColl(false); - setEndOfUserColl(true) setErrorInUserColl(true) } ) @@ -131,7 +127,6 @@ export default function TabPanelColecoes(props) { (data) => { if (data.errors) { setLoadingMoreFollowedColl(false); - setEndOfFollowedColl(true) setErrorInFollowedColl(true) } else if (data.length >= 1) { @@ -142,12 +137,10 @@ export default function TabPanelColecoes(props) { } else { setLoadingMoreFollowedColl(false); - setEndOfFollowedColl(true) } }, (error) => { setLoadingMoreFollowedColl(false); - setEndOfFollowedColl(true) setErrorInFollowedColl(true) } ) @@ -168,18 +161,23 @@ export default function TabPanelColecoes(props) { title={"Minhas Coleções"} length={userCollections.length} noContentText={ - <div> - <img src={PaginaVaziaColecao} alt="PaginaVaziaColecao" style={{ height: "150px", width: "150px", verticalAlign: "middle", border: "0" }} /> - <br /> - <span style={{ fontFamily: "Roboto", fontWeight: "lighter", fontSize: "24px" }}> - Criamos a sua primeira Coleção! - </span> - <p style={{ fontFamily: "Roboto", fontSize: "16px", margin: "10px 0 0", fontWeight: "normal" }}> - Adicione nela recursos que você queira acessar mais tarde. - <br /> - Crie novas coleções clicando no cartão roxo "Criar Colecão". - </p> - </div> + <Grid direction='column' justify='center' alignItems='center'> + <Grid item> + <img src={PaginaVaziaColecao} alt="PaginaVaziaColecao" style={{ height: "150px", width: "150px", verticalAlign: "middle", border: "0" }} /> + </Grid> + <Grid> + <span style={{ fontFamily: "Roboto", fontWeight: "lighter", fontSize: "24px", textAlign: 'center' }}> + Criamos a sua primeira Coleção! + </span> + </Grid> + <Grid> + <p style={{ fontFamily: "Roboto", fontSize: "16px", margin: "10px 0 0", fontWeight: "normal" }}> + Adicione nela recursos que você queira acessar mais tarde. + <br /> + Crie novas coleções clicando no cartão roxo "Criar Colecão". + </p> + </Grid> + </Grid> } sliceArr={userCollections} showMore={showMoreUserCollections} @@ -254,7 +252,9 @@ function Tentativa(props) { ( [ <Grid item lg={6} md={4} sm={6} xs={12}> - <NoContent text={props.noContentText} /> + <div> + {props.noContentText} + </div> </Grid> ] ) diff --git a/src/Components/TabPanels/UserPageTabs/PanelCuradoria.js b/src/Components/TabPanels/UserPageTabs/PanelCuradoria.js index d9a3ac296fd3d2f0b6faa3c765bb701323c1f09c..084f865b9077e0752df8b34d221debade2a35492 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelCuradoria.js +++ b/src/Components/TabPanels/UserPageTabs/PanelCuradoria.js @@ -27,7 +27,7 @@ export default function TabPanelCuradoria(props) { const [errorCurating, setErrorCurating] = useState(false) const [loadingMoreCurating, setLoadingMoreCurating] = useState(false) const [currLimitCurating, setcurrLimitCurating] = useState(4); - const [endOfCurating, setEndofCurating] = useState(); + const [endOfCurating, setEndofCurating] = useState(0); const [curating, setCurating] = useState([]); const showMoreCurating = (limite) => { diff --git a/src/Components/TabPanels/UserPageTabs/PanelEditarPerfil.js b/src/Components/TabPanels/UserPageTabs/PanelEditarPerfil.js index ce5a319efaacbf631c7a3871c0ee8672a8f68db1..f65e6417a460b08bf87221fb28aa8cec321a2c97 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelEditarPerfil.js +++ b/src/Components/TabPanels/UserPageTabs/PanelEditarPerfil.js @@ -42,7 +42,7 @@ export default function TabPanelEditarPerfil(props) { }) const [formAboutMe, setAboutMe] = useState({ - key: state.currentUser.description ? false : true, + key: false, value: state.currentUser.description ? state.currentUser.description : "" }) diff --git a/src/Components/TabPanels/UserPageTabs/PanelFavoritos.js b/src/Components/TabPanels/UserPageTabs/PanelFavoritos.js index 8c9fff1ba0a9dce2b90cdd477ddc0decf8242c32..9cf489886054275662595ce75d29302caf0ab2a0 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelFavoritos.js +++ b/src/Components/TabPanels/UserPageTabs/PanelFavoritos.js @@ -36,8 +36,8 @@ export default function TabPanelFavoritos(props) { const [loadingMoreLearnObj, setLoadingMoreLearnObj] = useState(false) const [loadingMoreColl, setLoadingMoreColl] = useState(false) - const [endOfLearnObj, setEndofLearndObj] = useState(false) - const [endOfColl, setEndoffColl] = useState(false) + const [endOfLearnObj, setEndofLearndObj] = useState(0) + const [endOfColl, setEndoffColl] = useState(0) function handleSuccess(responseArr, headersArr) { @@ -82,7 +82,6 @@ export default function TabPanelFavoritos(props) { (data) => { if (data.errors) { setLoadingMoreLearnObj(false); - setEndofLearndObj(true); setErrorInLikedInLearnObj(true); } else if (data.length >= 1) { @@ -93,12 +92,10 @@ export default function TabPanelFavoritos(props) { } else { setLoadingMoreLearnObj(false); - setEndofLearndObj(true) } }, (error) => { setLoadingMoreLearnObj(false); - setEndofLearndObj(true); setErrorInLikedInLearnObj(true); } ) @@ -113,7 +110,6 @@ export default function TabPanelFavoritos(props) { (data) => { if (data.errors) { setLoadingMoreColl(false); - setEndoffColl(true) setErrorInLikedInColl(true) } if (data.length >= 1) { @@ -124,12 +120,10 @@ export default function TabPanelFavoritos(props) { } else { setLoadingMoreColl(false); - setEndoffColl(true) } }, (error) => { setLoadingMoreColl(false); - setEndoffColl(true) setErrorInLikedInColl(true) } ) @@ -147,14 +141,9 @@ export default function TabPanelFavoritos(props) { [ <React.Fragment> <Template - length={endOfLearnObj} - titleText={"Recursos Favoritados"} - noContentText={<p style={{ fontFamily: "Roboto", fontSize: "16px" }}>Quando você favorita um recurso ele aparece nesta seção. Além disso, você - <br /> - aumenta o prestÃgio dele na Plataforma. Para favoritar, basta clicar no Ãcone de - <br /> - coração que aparece nos Recursos. - </p>} + length={likedLearnObjs.length} + titleText={likedLearnObjs.length === 1 ? "Recurso favoritado" : "Recursos favoritados"} + noContentText={"Você não favoritou nenhum recurso ainda"} slice={likedLearnObjs} showMore={showMoreLikedLearnObj} loadingMore={loadingMoreLearnObj} @@ -164,7 +153,7 @@ export default function TabPanelFavoritos(props) { <PanelTemplateColecao title={"Coleções favoritadas"} - length={endOfColl} + length={likedCollections.length} noContentText={"Você ainda não curtiu nenhuma coleção."} sliceArr={likedCollections} showMore={showMoreLikedCollections} diff --git a/src/Components/TabPanels/UserPageTabs/PanelMeusRecursos.js b/src/Components/TabPanels/UserPageTabs/PanelMeusRecursos.js index c6c3099a11ac3007bb63adc605896512d79caea1..46400fa191908298e8c373e83a5971b74da1dcf3 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelMeusRecursos.js +++ b/src/Components/TabPanels/UserPageTabs/PanelMeusRecursos.js @@ -105,7 +105,6 @@ export default function TabPanelAtividades(props) { } else { setLoadingMoreLearnObj(false); - setEndofLearndObj(true) } }, (error) => { @@ -136,7 +135,6 @@ export default function TabPanelAtividades(props) { } else { setLoadingMoreDrafts(false); - setEndofDrafts(true); } }, (error) => { @@ -165,7 +163,6 @@ export default function TabPanelAtividades(props) { } else { setLoadingMoreCurating(false); - setEndofCurating(true); } }, @@ -187,7 +184,7 @@ export default function TabPanelAtividades(props) { ( [ <React.Fragment> - <Template + <Template length={learningObjects.length} titleText={learningObjects.length === 1 ? "Recurso Publicado" : "Recursos Publicados"} noContentText={"Você ainda não publicou nenhum Recurso!"} diff --git a/src/Components/TabPanels/UserPageTabs/PanelRede.js b/src/Components/TabPanels/UserPageTabs/PanelRede.js index 03f4083bb18f0ad729f2a6234ef16c455666cef8..ba5741a5044359462e57d866a74e946c4ae0d444 100644 --- a/src/Components/TabPanels/UserPageTabs/PanelRede.js +++ b/src/Components/TabPanels/UserPageTabs/PanelRede.js @@ -31,12 +31,12 @@ export default function TabPanelRede(props) { const [followingList, setFollowing] = useState([]) const [currFollowingLimit, setCurrFollowingLimit] = useState(12) const [loadingMoreFollowing, setLoadingFollowing] = useState(false) - const [endOfFollowing, setEndOfFollowing] = useState(false) + const [endOfFollowing, setEndOfFollowing] = useState(0) const [followersList, setFollowers] = useState([]) const [currFollowerLimit, setFollowersLimit] = useState(12) const [loadingMoreFollowers, setLoadingMoreFollowers] = useState(false) - const [endOfFollowers, setEndOfFollowers] = useState(false) + const [endOfFollowers, setEndOfFollowers] = useState(0) const showMoreFollowing = (limite) => { setLoadingFollowing(true); @@ -47,7 +47,6 @@ export default function TabPanelRede(props) { (data) => { if (data.errors) { setLoadingFollowing(false); - setEndOfFollowing(true); setErrorInFollowing(true); } else if (data.length >= 1) { @@ -58,12 +57,10 @@ export default function TabPanelRede(props) { } else { setLoadingFollowing(false); - setEndOfFollowing(true); } }, (error) => { setLoadingFollowing(false); - setEndOfFollowing(true); setErrorInFollowing(true); } ) @@ -78,7 +75,6 @@ export default function TabPanelRede(props) { (data) => { if (data.errors) { setLoadingMoreFollowers(false); - setEndOfFollowers(true); setErrorInFollowers(true); } else { @@ -90,13 +86,11 @@ export default function TabPanelRede(props) { } else { setLoadingMoreFollowers(false); - setEndOfFollowers(true) } } }, (error) => { setLoadingMoreFollowers(false); - setEndOfFollowers(true); setErrorInFollowers(true); } ) @@ -118,7 +112,6 @@ export default function TabPanelRede(props) { function handleErrors() { setLoadingMoreFollowers(false); - setEndOfFollowers(true); setErrorInFollowers(true); } diff --git a/src/Components/UploadPageComponents/FileToUpload.ts b/src/Components/UploadPageComponents/FileToUpload.ts index fddbf404078bdb1eed4d04a666955d63ccdbac87..60b6ecb0435943d67b7eae390c06aefa47f167b7 100644 --- a/src/Components/UploadPageComponents/FileToUpload.ts +++ b/src/Components/UploadPageComponents/FileToUpload.ts @@ -34,7 +34,7 @@ export default class FileToUpload { if(this.readyState === XMLHttpRequest.DONE){ if (this.getResponseHeader('access-token') != null) { console.log(this.getResponseHeader('access-token')) - sessionStorage.setItem('@portalmec/accessToken', this.getResponseHeader('access-token')!) + localStorage.setItem('@portalmec/accessToken', this.getResponseHeader('access-token')!) } } } @@ -58,14 +58,14 @@ export default class FileToUpload { //set necessary headers this.request.setRequestHeader('Content-Range', `bytes ${this.currentChunkStartByte}-${this.currentChunkFinalByte}/${this.file.size}`); - if (sessionStorage.getItem('@portalmec/uid') != undefined) { - this.request.setRequestHeader('uid', sessionStorage.getItem('@portalmec/uid')!) + if (localStorage.getItem('@portalmec/uid') != undefined) { + this.request.setRequestHeader('uid', localStorage.getItem('@portalmec/uid')!) } - if (sessionStorage.getItem('@portalmec/clientToken') != undefined) { - this.request.setRequestHeader('client', String(sessionStorage.getItem('@portalmec/clientToken'))) + if (localStorage.getItem('@portalmec/clientToken') != undefined) { + this.request.setRequestHeader('client', String(localStorage.getItem('@portalmec/clientToken'))) } - if (sessionStorage.getItem('@portalmec/accessToken') != undefined) { - this.request.setRequestHeader('access-token', String(sessionStorage.getItem('@portalmec/accessToken'))) + if (localStorage.getItem('@portalmec/accessToken') != undefined) { + this.request.setRequestHeader('access-token', String(localStorage.getItem('@portalmec/accessToken'))) } this.request.onload = () => { diff --git a/src/Components/UploadPageComponents/Forms/Autor.js b/src/Components/UploadPageComponents/Forms/Autor.js index 30a3535b04fc2f2e4f0790227f4c9f61e8d40bb4..4ab8bde9e9db318c225064eecd79aab7f3dda421 100644 --- a/src/Components/UploadPageComponents/Forms/Autor.js +++ b/src/Components/UploadPageComponents/Forms/Autor.js @@ -51,23 +51,25 @@ function Autor (props) { <b>Autor do recurso</b> </StyledFormLabel> <RadioGroup ara-label="Autor do Recurso" name="Autor do Recurso" value={authorValue} onChange={(e) => {setAuthorValue(e.target.value)}}> - <FormControlLabel value="0" control={<BlueRadio />} label="Sou o(a) autor(a) deste recurso"/> - <FormControlLabel value="1" control={<BlueRadio/>} - label={ - <div style={{display : "flex", alignItems : "center"}}> - Outro: - <OutroAutorTextField - id = {"outro-autor-form"} - placeholder={"Nome dos autores"} - type = {"text"} - value = {outroAutor} - onChange = {e => {setOutroAutor(e.target.value)}} - disabled = {authorValue === "0"} - style={{paddingLeft : "5px", width : "100%"}} + <FormControlLabel value="0" control={<BlueRadio />} label="Sou o(a) autor(a) deste recurso"/> + <FormControlLabel value="1" control={<BlueRadio/>} + label={ + <div style={{display : "flex", alignItems : "center"}}> + Outro: + <OutroAutorTextField + id = {"outro-autor-form"} + placeholder={"Nome dos autores"} + type = {"text"} + value = {outroAutor} + onChange = {e => {setOutroAutor(e.target.value)}} + fullWidth + multiline + disabled = {authorValue === "0"} + style={{paddingLeft : "5px", width : "100%"}} /> </div>} /> - </RadioGroup> + </RadioGroup> </FormControl> ) } diff --git a/src/Components/UploadPageComponents/Forms/Idioma.js b/src/Components/UploadPageComponents/Forms/Idioma.js index 7d033a44d9ef18c7ffdd55f5b7894176077d3e7d..79de2d04f8be2e66ca72f772679999af94e06b78 100644 --- a/src/Components/UploadPageComponents/Forms/Idioma.js +++ b/src/Components/UploadPageComponents/Forms/Idioma.js @@ -26,38 +26,46 @@ import Select from '@material-ui/core/Select'; export default function Idioma (props) { const [chosenLanguage, setChosenLanguage] = useState(props.initialValue ? props.initialValue : []) - const [ids, setIds] = useState(props.initialIDValues ? props.initialIDValues : []) + const [ids, setIds] = useState(props.initialIDValue ? props.initialIDValue : []) const handleChangeLanguage = (event) => { - console.log(event.target.value) let newLanguage = event.target.value.pop() - setChosenLanguage(chosenLanguage => [...chosenLanguage, newLanguage.name]); - setIds(ids => [...ids, newLanguage.id]) - }; + if (!chosenLanguage.some(language => language === newLanguage.name)) { + setChosenLanguage(chosenLanguage => [...chosenLanguage, newLanguage.name]); + setIds(ids => [...ids, newLanguage.id]) + } + else + { + if (chosenLanguage.length > 0) { + setChosenLanguage(chosenLanguage.filter((language) => {return language !== newLanguage.name})); + setIds(ids.filter((id) => {return id !== newLanguage.id})) + } + } + }; return ( - <FormControl required style={{minWidth : "30%"}}> + <FormControl style={{minWidth : "30%"}}> <StyledFormLabel component="legend" style={{fontSize : "14px", marginBottom : "10px"}}> - <b>Idioma</b> + <b>Idioma</b><span>*</span> </StyledFormLabel> - <Select - value={chosenLanguage} - multiple - renderValue={(selected) => selected.join(', ')} - name="Idioma" - onChange={handleChangeLanguage} - onBlur={() => {props.onBlurCallback("language_ids", ids, props.draftID)}} - > - { - props.languages.map( language => - <MenuItem key={language.name} value={language}> - <Checkbox checked={chosenLanguage.indexOf(language.name) > -1} /> - <ListItemText primary={language.name} /> - </MenuItem> - ) - } - </Select> + <Select + value={chosenLanguage} + multiple + renderValue={(selected) => selected.join(', ')} + name="Idioma" + onChange={handleChangeLanguage} + onBlur={() => {props.onBlurCallback("language_ids", ids, props.draftID)}} + > + { + props.languages.map( language => + <MenuItem key={language.name} value={language}> + <Checkbox checked={chosenLanguage.indexOf(language.name) > -1} /> + <ListItemText primary={language.name} /> + </MenuItem> + ) + } + </Select> </FormControl> ) } diff --git a/src/Components/UploadPageComponents/Forms/Keywords.js b/src/Components/UploadPageComponents/Forms/Keywords.js index 34c7b8ec36103d4eb27f1fbba515f2cd686ffdad..fa2418b706dc96f56f88f60f7ef1014fd66b40dd 100644 --- a/src/Components/UploadPageComponents/Forms/Keywords.js +++ b/src/Components/UploadPageComponents/Forms/Keywords.js @@ -16,7 +16,7 @@ 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, memo} from 'react' +import React, {useState, memo, useEffect, useRef} from 'react' import FormControl from '@material-ui/core/FormControl'; import {StyledTextField, StyledFormLabel} from '../StyledComponents.js' import FormHelperText from '@material-ui/core/FormHelperText'; @@ -27,9 +27,18 @@ function Keywords (props) { const [keywords, setKeywords] = useState(props.initialValue ? props.initialValue : []) const handleSetKeywords = (newKeyword) => {setKeywords(newKeyword)} const deleteKeyword = (keywordToDelete) => { - setKeywords(keywords.filter((keyword) => keyword !== keywordToDelete)) + handleSetKeywords(keywords.filter((keyword) => keyword !== keywordToDelete)) } + const resettingRef = useRef(false); + + useEffect(() => { + if(resettingRef.current){ //used to ensure that keywords are updated before sending (after a delete) + resettingRef.current = false; + props.onBlurCallback("tags", keywords, props.draftID); + } + },[keywords]) + const [keywordsBuffer, setKeywordsBuffer] = useState('') const handleKeywords = (event) => { @@ -64,8 +73,9 @@ function Keywords (props) { onKeyDown={(event) => { if(event.keyCode === 13){ handleSetKeywords([...keywords, keywordsBuffer]) - setKeywordsBuffer('')}} - } + setKeywordsBuffer('') + }} + } fullWidth onBlur={() => {props.onBlurCallback("tags", keywords, props.draftID)}} /> @@ -75,7 +85,7 @@ function Keywords (props) { <FormHelperText> { keywords.map( (keyword) => - <Chip label={keyword} key={keyword} onDelete={() => deleteKeyword(keyword)} /> + <Chip label={keyword} key={keyword} onDelete={() => {resettingRef.current = true; deleteKeyword(keyword);}} /> ) } </FormHelperText> diff --git a/src/Components/UploadPageComponents/Forms/NewTitle.js b/src/Components/UploadPageComponents/Forms/NewTitle.js index 0a763dc0a08fd0d399f7daf3b127a9620d24965c..b5d27708068df08fa2969420afde3342465873d2 100644 --- a/src/Components/UploadPageComponents/Forms/NewTitle.js +++ b/src/Components/UploadPageComponents/Forms/NewTitle.js @@ -51,6 +51,7 @@ function NewTitle (props) { helperText = {objTitle.value.length + "/100"} error = {objTitle.error} fullWidth + multiline onBlur={() => {props.onBlurCallback("name", objTitle.value, props.draftID)}} /> {objTitle.value.length === 0 && objTitle.error && diff --git a/src/Components/UploadPageComponents/PartOne.js b/src/Components/UploadPageComponents/PartOne.js index fbb47cb5b0e325fa01cf5ba7666acd454a398134..250428dbf319dd5488a5bcebb31743d787d6a73b 100644 --- a/src/Components/UploadPageComponents/PartOne.js +++ b/src/Components/UploadPageComponents/PartOne.js @@ -16,7 +16,8 @@ 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 React, {useState, useEffect, useContext, useRef} from 'react' +import {Store} from '../../Store.js' import Grid from '@material-ui/core/Grid'; import ButtonsDiv from './ButtonsDiv.js' import SobreORecurso from './Forms/SobreORecurso.js' @@ -27,67 +28,194 @@ import TipoDeRecurso from './Forms/TipoDeRecurso.js' import Idioma from './Forms/Idioma.js' import {SendInfo} from './SendInfo.js' import {getRequest} from '../HelperFunctions/getAxiosConfig.js' +import SnackBar from '../../Components/SnackbarComponent'; +import LoadingSpinner from '../../Components/LoadingSpinner' export default function PartOne (props) { // {/*const [subjects, setSubjects] = useState([])*/} + const {state} = useContext(Store) + const didMountRef = useRef(false); + const didMountRefObj = useRef(false); + const [languages, setLanguages] = useState([]) const [objTypes, setObjTypes] = useState([]) + const [learningObject, setLearningObject] = useState({}) + + const [loading, toggleLoading] = useState(true) + const [loadingObj, toggleLoadingObj] = useState(true) + + const [snackInfo, setSnackInfo] = useState({ + open: false, + text: '', + severity: '', + color: '', + }) + + function handleCloseSnackBar() { + const info = { + open: false, + text: '', + severity: '', + color: '', + } + handleSnackInfo(info) + } + + function handleSnackInfo(info) { + setSnackInfo({ + ...info + }) + } + + function checkPartOne (data) { + return ( + data.name !== null && + data.tags.length !== 0 && + data.author !== null && + data.object_type !== null && + data.language.length !== 0 && + (data.attachments.length !== 0 || + data.link !== null) + ) + } + function handleSuccessGetObjTypes (data) { setObjTypes(data.sort((a, b) => (a.name) > (b.name) ? 1 : -1)) } + + function handleSuccessGetFormData (data) { + if (checkPartOne(data)) { + props.stepperControl(1) + } else { + const info = { + open: true, + text: 'Preencha todos os campos obrigatórios, inclusive o de "Enviar Recurso"!', + severity: 'warning', + color: '#FFC125', + } + handleSnackInfo(info) + } + } + + function handleSuccessfulGet (data) { + setLearningObject(data) + } + useEffect( () => { - getRequest(`/object_types/`, handleSuccessGetObjTypes, (error) => {console.log(error)}) + getRequest(`/object_types/`, handleSuccessGetObjTypes, (error) => {console.log(error)}) + getRequest(`/languages/`, (data) => {setLanguages(data)}, (error) => {console.log(error)}) - getRequest(`/languages/`, (data) => {setLanguages(data)}, (error) => {console.log(error)}) + const url = `/learning_objects/${props.draftID}` + getRequest(url, handleSuccessfulGet, (error) => {console.log(error)}) }, []) - const handleSubmit = () => { - props.stepperControl(1) + useEffect( () => { + if (didMountRef.current) { + toggleLoading(false) + } + else { + didMountRef.current = true; + } + }, [learningObject]) + + useEffect( () => { + if (didMountRefObj.current) { + toggleLoadingObj(false) + } + else { + didMountRefObj.current = true; + } + }, [objTypes]) + + const handleSubmit = (e) => { + e.preventDefault(); + getRequest(`/learning_objects/${props.draftID}`, + handleSuccessGetFormData, + () => { + const info = { + open: true, + text: 'Não foi possÃvel verificar o status da publicação!', + severity: 'error', + color: 'red', + } + handleSnackInfo(info) + } + ) } return ( - <form onSubmit={handleSubmit}> - {/*------------------------------Titulo-----------------------------------------*/} - <Grid item xs={12} style={{paddingBottom : "40px"}}> - <NewTitle draftID={props.draftID} onBlurCallback={SendInfo}/> - </Grid> - - {/*------------------------------Sobre------------------------------------------*/} - <Grid item xs={12} style={{paddingBottom : "40px"}}> - <SobreORecurso draftID={props.draftID} onBlurCallback={SendInfo}/> - </Grid> - - {/*------------------------------Palavras-chave------------------------------------------*/} - <Grid item xs={12} style={{paddingBottom : "40px"}}> - <Keywords draftID={props.draftID} onBlurCallback={SendInfo}/> - </Grid> - - {/*------------------------------Autor------------------------------------------*/} - <Grid item xs={12} style={{paddingBottom : "40px"}}> - <Autor draftID={props.draftID} onBlurCallback={SendInfo}/> - </Grid> - - {/*------------------------------Tipo do Objeto------------------------------------------*/} - <Grid item xs={12} style={{paddingBottom : "40px"}}> - <TipoDeRecurso objTypes={objTypes} draftID={props.draftID} onBlurCallback={SendInfo}/> - </Grid> - - {/*------------------------------Idioma------------------------------------------*/} - <Grid item xs={12} style={{paddingBottom : "40px"}}> - <Idioma languages={languages} draftID={props.draftID} onBlurCallback={SendInfo}/> - </Grid> - - {/*------------------------------Botoes------------------------------------------*/} - <Grid item xs={12}> - <ButtonsDiv draftID={props.draftID} stepperControl={props.stepperControl}/> - </Grid> - - <Grid item xs={12} style={{marginTop : "20px"}}> - <span style={{marginTop : "20px", fontWeight : "200", color : "#a5a5a5", paddingLeft : "10px"}}> - * Campos obrigatórios - </span> - </Grid> - </form> + <React.Fragment> + <SnackBar + snackbarOpen={snackInfo.open} + handleClose={handleCloseSnackBar} + severity={snackInfo.severity} + color={snackInfo.color} + text={snackInfo.text} + /> + { + !loading && !loadingObj ? ( + <form onSubmit={handleSubmit}> + {/*------------------------------Titulo-----------------------------------------*/} + <Grid item xs={12} style={{paddingBottom : "40px"}}> + <NewTitle draftID={props.draftID} onBlurCallback={SendInfo} initialValue={learningObject.name}/> + </Grid> + + {/*------------------------------Sobre------------------------------------------*/} + <Grid item xs={12} style={{paddingBottom : "40px"}}> + <SobreORecurso draftID={props.draftID} onBlurCallback={SendInfo} initialValue={learningObject.description}/> + </Grid> + + {/*------------------------------Palavras-chave------------------------------------------*/} + <Grid item xs={12} style={{paddingBottom : "40px"}}> + <Keywords draftID={props.draftID} onBlurCallback={SendInfo} initialValue={learningObject.tags !== undefined ? learningObject.tags.map((tag) => tag.name) : null}/> + </Grid> + + {/*------------------------------Autor------------------------------------------*/} + <Grid item xs={12} style={{paddingBottom : "40px"}}> + <Autor draftID={props.draftID} onBlurCallback={SendInfo} + initialValue={ + learningObject.author === state.currentUser.name ? + 0 : 1 + } + initialOutroAutor={ + learningObject.author !== state.currentUser.name ? + learningObject.author : '' + } + /> + </Grid> + + {/*------------------------------Tipo do Objeto------------------------------------------*/} + <Grid item xs={12} style={{paddingBottom : "40px"}}> + <TipoDeRecurso objTypes={objTypes} draftID={props.draftID} onBlurCallback={SendInfo} + initialValue={learningObject.object_type !== undefined && learningObject.object_type !== null ? objTypes.filter((type) => type.name === learningObject.object_type)[0].id : null} + /> + </Grid> + + {/*------------------------------Idioma------------------------------------------*/} + <Grid item xs={12} style={{paddingBottom : "40px"}}> + <Idioma languages={languages} draftID={props.draftID} onBlurCallback={SendInfo} + initialValue={learningObject.language !== undefined ? learningObject.language.map((language) => language.name) : null} initialIDValues={learningObject.language !== undefined ? learningObject.language.map((language) => language.id) : null} + /> + </Grid> + + {/*------------------------------Botoes------------------------------------------*/} + <Grid item xs={12}> + <ButtonsDiv draftID={props.draftID} stepperControl={props.stepperControl}/> + </Grid> + + <Grid item xs={12} style={{marginTop : "20px"}}> + <span style={{marginTop : "20px", fontWeight : "200", color : "#a5a5a5", paddingLeft : "10px"}}> + * Campos obrigatórios + </span> + </Grid> + </form> + ) + : + ( + <LoadingSpinner text={"CARREGANDO"}/> + ) + } + </React.Fragment> ) } diff --git a/src/Components/UploadPageComponents/PartThree.js b/src/Components/UploadPageComponents/PartThree.js index b1eb3f564739b77c4c13ffb2e5e6a04a2699004d..5170659ca6f2e961a14e314a827656737def4000 100644 --- a/src/Components/UploadPageComponents/PartThree.js +++ b/src/Components/UploadPageComponents/PartThree.js @@ -35,11 +35,13 @@ import { GrayButton, OrangeButton } from './StyledComponents'; import ModalCancelar from './ModalCancelar.js' import { getDefaultThumbnail } from '../HelperFunctions/getDefaultThumbnail' import { getRequest } from '../HelperFunctions/getAxiosConfig.js' +import ReCaptcha from 'react-recaptcha' export default function PartThree(props) { var moment = require('moment') const { state } = useContext(Store) const [loading, setLoading] = useState(false) + const [unavailableButton, setButtonAvailability] = useState(true); const [draft, setDraft] = useState({}) const [subjects, setSubjects] = useState('') @@ -84,6 +86,12 @@ export default function PartThree(props) { return (state.currentUser.roles.filter((role) => role.name === userRole).length > 0) } + function captchaVerified (response) { + if (response) { + setButtonAvailability(false) + } + } + return ( <React.Fragment> { @@ -205,8 +213,14 @@ export default function PartThree(props) { </span> </Grid> - <Grid item xs={windowWidth > 990 ? 6 : 12} style={{ paddingRight: "15px", paddingLeft: "15px", textAlign: windowWidth > 990 ? 'left' : 'center' }}> - <span>Recaptcha</span> + <Grid item xs={windowWidth > 990 ? 6 : 12} style={{ paddingRight: "15px", paddingLeft: "15px"}}> + <div style={{margin:"0 auto", width: "304px"}}> + { + //<ReCaptcha sitekey={process.env.REACT_APP_SITE_KEY} verifyCallback={captchaVerified} /> //when key set in env + <ReCaptcha sitekey="6LfxuKUUAAAAAIzYpCzEtJyeE8QRjBYa44dvHlTX" verifyCallback={captchaVerified} /> //use this one on production + //<ReCaptcha sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI" verifyCallback={captchaVerified} /> //test key, from google, do not use this one on production + } + </div> </Grid> <Grid item xs={12} style={{ paddingRight: "15px", paddingLeft: "15px", marginTop: "30px", textAlign: 'center' }}> <GrayButton onClick={() => { props.stepperControl(-1) }}>VOLTAR</GrayButton> @@ -214,11 +228,23 @@ export default function PartThree(props) { { checkAccessLevel("partner") ? ( - <OrangeButton onClick={props.handlePost}>PUBLICAR RECURSO</OrangeButton> + unavailableButton ? ( + <GrayButton disabled={unavailableButton}>PUBLICAR RECURSO</GrayButton> + ) + : + ( + <OrangeButton onClick={props.handlePost}>PUBLICAR RECURSO</OrangeButton> + ) ) : ( - <OrangeButton onClick={props.handleSubmit}>SUBMETER RECURSO</OrangeButton> + unavailableButton ? ( + <GrayButton disabled={unavailableButton}>SUBMETER RECURSO</GrayButton> + ) + : + ( + <OrangeButton onClick={props.handleSubmit}>SUBMETER RECURSO</OrangeButton> + ) ) } diff --git a/src/Components/UploadPageComponents/PartTwo.js b/src/Components/UploadPageComponents/PartTwo.js index 221998c85f4e04e0a35204fcb89bd675b95b68f0..cf65a4de9952a0450b5bfedf71bd671511bcecbe 100644 --- a/src/Components/UploadPageComponents/PartTwo.js +++ b/src/Components/UploadPageComponents/PartTwo.js @@ -16,7 +16,7 @@ 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 React, {useState, useEffect, useRef} from 'react' import Grid from '@material-ui/core/Grid'; import styled from 'styled-components' import DragAndDropThumbnail from './PartTwoComponents/DragAndDropThumbnail' @@ -33,6 +33,8 @@ import EditThumbnail from './PartTwoComponents/EditThumbnail.js' import DisplayThumbnail from './PartTwoComponents/DisplayThumbnail.js' import CustomCircularProgress from './PartTwoComponents/CustomCircularProgress'; import {getRequest, putRequest} from '../HelperFunctions/getAxiosConfig.js' +import SnackBar from '../../Components/SnackbarComponent'; +import LoadingSpinner from '../../Components/LoadingSpinner' export function LoadingDiv () { return ( @@ -43,27 +45,96 @@ export function LoadingDiv () { } export default function PartTwo (props) { + const didMountRef = useRef(false); + const [eduStages, setEduStages] = useState([]) const [subjects, setSubjects] = useState([]) const [themes, setThemes] = useState([]) + const [learningObject, setLearningObject] = useState({}) + + const [loading, toggleLoading] = useState(true) + + const [snackInfo, setSnackInfo] = useState({ + open: false, + text: '', + severity: '', + color: '', + }) + + function handleCloseSnackBar() { + const info = { + open: false, + text: '', + severity: '', + color: '', + } + handleSnackInfo(info) + } + + function handleSnackInfo(info) { + setSnackInfo({ + ...info + }) + } + function handleSuccess (data) { setSubjects(data.filter(subject => subject.theme === false).sort((a,b) => a.name > b.name ? 1 : -1)) setThemes(data.filter(subject => subject.theme === true).sort((a,b) => a.name > b.name ? 1 : -1)) } + function checkPartTwo (data) { + return ( + data.educational_stages.length !== 0 && + data.subjects.length !== 0 && + data.license !== null && + termsCheckbox + ) + } + + function handleSuccessGetFormData (data) { + if (checkPartTwo(data)) { + props.stepperControl(1) + } else { + const info = { + open: true, + text: 'Preencha todos os campos obrigatórios, inclusive o acordo de termos de uso e de propriedade intelectual!', + severity: 'warning', + color: '#FFC125', + } + handleSnackInfo(info) + } + } + + function handleSuccessfulGet (data) { + setLearningObject(data) + } + useEffect(() => { getRequest(`/educational_stages/`, (data) => {setEduStages(data)}, (error) => {console.log(error)}) getRequest(`/subjects/`, handleSuccess, (error) => {console.log(error)}) + + const url = `/learning_objects/${props.draftID}` + getRequest(url, handleSuccessfulGet, (error) => {console.log(error)}) }, []) + useEffect( () => { + if (didMountRef.current) { + console.log(learningObject); + toggleLoading(false) + } + else { + didMountRef.current = true; + } + }, [learningObject]) + /*------------------------Licenca------------------------*/ const [termsCheckbox, setChecked] = useState(false) - const toggleCheckbox = (event) => { - setChecked(event.target.checked) + const toggleCheckbox = () => { + setChecked(!termsCheckbox) } const [thumbnail, setThumbnail] = useState('') @@ -107,46 +178,79 @@ export default function PartTwo (props) { } } - const handleSubmit = () => { - props.stepperControl(1) - } + const handleSubmit = (e) => { + e.preventDefault(); + getRequest(`/learning_objects/${props.draftID}`, + handleSuccessGetFormData, + () => { + const info = { + open: true, + text: 'Não foi possÃvel verificar o status da publicação!', + severity: 'error', + color: 'red', + } + handleSnackInfo(info) + } + ) + } return ( - <form style={{width : "100%"}} onSubmit={handleSubmit}> - <Grid item xs={12} style={{paddingBottom : "40px"}}> - {chooseRenderStageThumbnail()} - </Grid> - - <Grid item xs={12} style={{paddingBottom : "40px"}}> - <EducationalStage draftID={props.draftID} eduStages={eduStages} onBlurCallback={SendInfo}/> - </Grid> - - <SubjectsAndThemes draftID={props.draftID} subjects={subjects} themes={themes} onUploadPage={true} onBlurCallback={SendInfo}/> - - <Grid item xs={12} style={{paddingBottom : "40px"}}> - <Licenca draftID={props.draftID} onBlurCallback={SendInfo}/> - </Grid> - - <Grid item xs={12} style={{paddingBottom : "40px"}}> - <StyledFormControl required > - <StyledFormLabel component="legend" style={{fontSize : "14px", marginBottom : "10px"}} onClick={() => window.open("/termos/", "_blank")}> - <b>Confirme se você concorda com os <strong style={{color : "#ff7f00"}}>termos de uso e de propriedade intelectual</strong></b> - </StyledFormLabel> - <FormControlLabel label={<span className="label">Li e concordo com os termos de uso e de propriedade intelectual.</span>} control={<Checkbox checked={termsCheckbox} onChange={toggleCheckbox}/>} + <React.Fragment> + <SnackBar + snackbarOpen={snackInfo.open} + handleClose={handleCloseSnackBar} + severity={snackInfo.severity} + color={snackInfo.color} + text={snackInfo.text} + /> + { + !loading ? ( + <form style={{width : "100%"}} onSubmit={handleSubmit}> + <Grid item xs={12} style={{paddingBottom : "40px"}}> + {chooseRenderStageThumbnail()} + </Grid> + + <Grid item xs={12} style={{paddingBottom : "40px"}}> + <EducationalStage draftID={props.draftID} eduStages={eduStages} onBlurCallback={SendInfo} + initialValue={learningObject.educational_stages !== null ? learningObject.educational_stages.map((stage) => String(stage.id)) : null} + /> + </Grid> + + <SubjectsAndThemes draftID={props.draftID} subjects={subjects} themes={themes} onUploadPage={true} onBlurCallback={SendInfo} + initialValue={learningObject.subjects !== null ? learningObject.subjects.map(subject => String(subject.id)) : null} /> - </StyledFormControl> - </Grid> - - <Grid item xs={12}> - <ButtonsDiv draftID={props.draftID} stepperControl={props.stepperControl} onPartTwo={true}/> - </Grid> - - <Grid item xs={12} style={{marginTop : "20px"}}> - <span style={{marginTop : "20px", fontWeight : "200", color : "#a5a5a5", paddingLeft : "10px"}}> - * Campos obrigatórios - </span> - </Grid> - </form> + + <Grid item xs={12} style={{paddingBottom : "40px"}}> + <Licenca draftID={props.draftID} onBlurCallback={SendInfo} initialValue={learningObject.license ? learningObject.license.id : null}/> + </Grid> + + <Grid item xs={12} style={{paddingBottom : "40px"}}> + <StyledFormControl required > + <StyledFormLabel component="legend" style={{fontSize : "14px", marginBottom : "10px"}} onClick={() => window.open("/termos/", "_blank")}> + <b>Confirme se você concorda com os <strong style={{color : "#ff7f00"}}>termos de uso e de propriedade intelectual</strong></b> + </StyledFormLabel> + <FormControlLabel label={<span className="label">Li e concordo com os termos de uso e de propriedade intelectual.</span>} control={<Checkbox checked={termsCheckbox} onChange={toggleCheckbox}/>} + /> + </StyledFormControl> + </Grid> + + <Grid item xs={12}> + <ButtonsDiv draftID={props.draftID} stepperControl={props.stepperControl} onPartTwo={true}/> + </Grid> + + <Grid item xs={12} style={{marginTop : "20px"}}> + <span style={{marginTop : "20px", fontWeight : "200", color : "#a5a5a5", paddingLeft : "10px"}}> + * Campos obrigatórios + </span> + </Grid> + </form> + ) + : + ( + <LoadingSpinner text={"CARREGANDO"}/> + ) + } + </React.Fragment> ) } diff --git a/src/Components/UploadPageComponents/SendInfo.js b/src/Components/UploadPageComponents/SendInfo.js index ebcb1b95f377fe018e3a178716ff7d1621009dba..606a7f72c7bb97e7b7eda26a95a76ca5bcc29e4a 100644 --- a/src/Components/UploadPageComponents/SendInfo.js +++ b/src/Components/UploadPageComponents/SendInfo.js @@ -23,8 +23,8 @@ export function SendInfo (fieldName, payload, draftID) { const key = fieldName let value = payload if (key === "tags") { - value = payload.map( (tag, index) => - index = { "name" : tag} + value = payload.map( (tag, index) => { + return (index = { "name" : tag})} ) } diff --git a/src/Pages/CollectionPage.js b/src/Pages/CollectionPage.js index 3ccb5ab1929d32cc3be204d59fa939664b85596f..0c60a9603ce4290798e5598267e0cd8f9bb16372 100644 --- a/src/Pages/CollectionPage.js +++ b/src/Pages/CollectionPage.js @@ -22,18 +22,23 @@ 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 { apiDomain } from '../env'; +import LoadingSpinner from '../Components/LoadingSpinner'; import styled from 'styled-components'; import DowloadButton from '../Components/CollectionDowloadButton.js'; import Breadcrumbs from "@material-ui/core/Breadcrumbs"; import { Link } from 'react-router-dom'; import FollowCollectionButton from '../Components/FollowCollectionButton'; -import { Store } from '../Store.js' -import { getRequest } from '../Components/HelperFunctions/getAxiosConfig.js' +import { Store } from '../Store.js'; +import Button from '@material-ui/core/Button'; +import { getRequest } from '../Components/HelperFunctions/getAxiosConfig.js'; +import noAvatar from '../img/default_profile.png'; +import { apiDomain } from '../env.js'; export default function CollectionPage(props) { const { state } = useContext(Store); + const [error, setError] = useState(false) + const [loading, setLoading] = useState(true) const [collection, setCollection] = useState({ name: '', id: 0, @@ -43,82 +48,114 @@ export default function CollectionPage(props) { useEffect(() => { const url = `/collections/${collection_id}` - - getRequest(url, (data) => { setCollection(Object.assign({}, data)) }, (error) => { console.log(error) }) - }, []); + getRequest(url, (data) => { setCollection(Object.assign({}, data)); setLoading(false) }, (error) => { setError(true); setLoading(false) }) + }, [state.currentUser.id]); const handleScrollToComments = () => { comment_ref.current.scrollIntoView({ behavior: 'smooth' }) } - return ( - <> - <BreadCrumbsDiv> - <StyledBreadCrumbs> - <Link to="/">Página Inicial</Link> - <span>Coleções</span> - </StyledBreadCrumbs> - </BreadCrumbsDiv> - <Grid container direction="row" justify="center" alignItems="center"> - <Grid item 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> - - - <Grid item md={5}> - <CollectionDescription - scrollToComments={handleScrollToComments} - title={collection.name ? collection.name : ""} - collection_id={collection.id ? collection.id : 0} /> - </Grid> - <Grid item md={3}> - <DowloadButton - id={collection.id ? collection.id : 0} - /> - <div style={{ height: 12 }}></div> - <FollowCollectionButton - user_id={state.currentUser.id} - collection_id={collection_id} /> + if (error) + return <CollectionNotFound> + <Grid container direction='column' justify='center' alignItems='center' spacing={1}> + <Grid item> + <p className="not-found"> + A coleção não foi encontrado em nossa base de dados. + </p> </Grid> + <Grid item> + + <Link className="link" to={`/busca?page=0&results_per_page=12&order=review_average&query=*&search_class=Collection`}> + <Button + variant='contained' + className="back-button" + > + Voltar para a busca de coleções. + </Button> + </Link> </Grid> - - <VerticalRuler width={1} height={100} color="rgb(238, 238, 238)" /> - - <Grid container justify="center" style={{ backgroundColor: '#f4f4f4' }}> - {/* <Grid item xs={1}/> */} - <Grid item xs={10}> - <ResourceList resources={ - collection.collection_items ? - collection.collection_items.map(i => { - return { - type: i.collectionable.object_type, - author: i.collectionable.author, - 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), - id: i.collectionable.id, - downloadableLink: i.collectionable.default_attachment_location, - publisher: i.collectionable.publisher.name, - published: i.collectionable.state - } - }) - : [] - } /> - + </Grid> + </CollectionNotFound > + if (loading) + return <LoadingSpinner text="Carregando coleção..." /> + else + return ( + <> + <BreadCrumbsDiv> + <StyledBreadCrumbs> + <Link to="/">Página Inicial</Link> + <span>Coleções</span> + </StyledBreadCrumbs> + </BreadCrumbsDiv> + <Grid container direction="row" justify="center" alignItems="center"> + <Grid item md={3}> + <CollectionAuthor + author_id={collection.owner.id ? collection.owner.id : 0} + name={collection.owner.name ? collection.owner.name : ""} + imgsrc={collection.owner.avatar ? apiDomain + collection.owner.avatar : noAvatar} /> + </Grid> + + + <Grid item md={5}> + <CollectionDescription + stars={collection.review_average} + likes={collection.likes_count} + liked={collection.liked} + scrollToComments={handleScrollToComments} + title={collection.name ? collection.name : ""} + collection_id={collection_id} /> + </Grid> + + <Grid item md={3}> + <DowloadButton + id={collection_id} + /> + <div style={{ height: 12 }}></div> + <FollowCollectionButton + followed={collection.followed} + user_id={state.currentUser.id} + collection_id={collection_id} /> + </Grid> </Grid> - <Grid container item xs={12} style={{ marginTop: 40, paddingBottom: 40 }} ref={comment_ref}> - <CollectionCommentSection id={collection_id} /> + + <VerticalRuler width={1} height={100} color="rgb(238, 238, 238)" /> + + <Grid container justify="center" style={{ backgroundColor: '#f4f4f4' }}> + {/* <Grid item xs={1}/> */} + <Grid item xs={10}> + <ResourceList resources={ + collection.collection_items ? + collection.collection_items.map(i => { + return { + type: i.collectionable.object_type, + author: i.collectionable.author, + 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), + id: i.collectionable.id, + downloadableLink: i.collectionable.default_attachment_location, + publisher: i.collectionable.publisher.name, + published: i.collectionable.state + } + }) + : [] + } /> + + </Grid> + <Grid container item xs={12} style={{ marginTop: 40, paddingBottom: 40 }} ref={comment_ref}> + <CollectionCommentSection + id={collection_id} + currentUserId={state.currentUser.id} + avatar={state.currentUser.avatar ? apiDomain + state.currentUser.avatar : noAvatar} + /> + </Grid> </Grid> - </Grid> - </> - ); + </> + ); } const StyledBreadCrumbs = styled(Breadcrumbs)` @@ -133,6 +170,27 @@ const StyledBreadCrumbs = styled(Breadcrumbs)` } `; +const CollectionNotFound = styled.div` + margin: 1em; + + .not-found{ + font-family: 'Roboto', sans-serif; + font-weight: 500; + text-align: left; + padding: 0; + margin: 0; + } + + .back-button{ + background-color: #673ab7; + color: whitesmoke; + } + + .link{ + text-decoration: none; + } +` + const BreadCrumbsDiv = styled.div` padding: 10px; display: flex; diff --git a/src/Pages/EditLearningObjectPage.js b/src/Pages/EditLearningObjectPage.js index 5f8e84fd37ca9631c73f1ede50177413be608507..c785bf3564d672834c0ed00f964fcc139040a8c5 100644 --- a/src/Pages/EditLearningObjectPage.js +++ b/src/Pages/EditLearningObjectPage.js @@ -24,6 +24,7 @@ import Grid from '@material-ui/core/Grid'; import UploadFileWrapper from '../Components/UploadPageComponents/UploadFileWrapper.js' import Alert from '../Components/Alert.js'; import Snackbar from '@material-ui/core/Snackbar'; +import {Redirect} from 'react-router-dom' import {GreyButton, OrangeButton, InfoBox} from '../Components/UploadPageComponents/StyledComponents.js' import {Background} from '../Components/UploadPageComponents/StyledComponents' import LoadingSpinner from '../Components/LoadingSpinner' @@ -46,6 +47,7 @@ export default function EditLearningObjectPage (props) { const recursoId = props.match.params.recursoId const {state} = useContext(Store) const [learningObject, setLearningObject] = useState({}) + const [publisherDeletedObject, toggleDeleted] = useState(false) const [objTypes, setObjTypes] = useState([]) const [languages, setLanguages] = useState([]) const [eduStages, setEduStages] = useState([]) @@ -115,7 +117,7 @@ export default function EditLearningObjectPage (props) { function handleSuccessfulDelete (data) { toggleSnackbar(true) - props.history.push("/") + toggleDeleted(true) } const handleDelete = () => { @@ -237,6 +239,15 @@ export default function EditLearningObjectPage (props) { } return ( <React.Fragment> + { + publisherDeletedObject && + <Redirect + to={{ + pathname: "/perfil", + state: 1 + }} + /> + } <Snackbar open={snackbarOpen} autoHideDuration={1000} onClose={() => {toggleSnackbar(false)}} anchorOrigin = {{ vertical:'top', horizontal:'right' }} > @@ -276,7 +287,7 @@ export default function EditLearningObjectPage (props) { </Grid> <Grid item xs={12} style={{paddingBottom : "40px"}}> - <Keywords draftID={learningObject.id} initialValue={learningObject.tags.map((tag) => tag.name)} + <Keywords draftID={learningObject.id} initialValue={learningObject.tags !== undefined ? learningObject.tags.map((tag) => tag.name) : null} onBlurCallback={onBlurCallback}/> </Grid> @@ -296,20 +307,21 @@ export default function EditLearningObjectPage (props) { <Grid item xs={12} style={{paddingBottom : "40px"}}> <TipoDeRecurso objTypes={objTypes} draftID={learningObject.id} - initialValue={learningObject.object_type !== null ? objTypes.filter((type) => type.name === learningObject.object_type)[0].id : null} onBlurCallback={onBlurCallback} /> + initialValue={learningObject.object_type !== undefined && learningObject.object_type !== null ? objTypes.filter((type) => type.name === learningObject.object_type)[0].id : null} onBlurCallback={onBlurCallback} /> </Grid> <Grid item xs={12} style={{paddingBottom : "40px"}}> - <Idioma languages={languages} draftID={learningObject.id} initialValue={learningObject.language.map((language) => language.name)} initialIDValues={learningObject.language.map((language) => language.id)} - onBlurCallback={onBlurCallback} /> + <Idioma languages={languages} draftID={learningObject.id} + initialValue={learningObject.language !== undefined ? learningObject.language.map((language) => language.name) : null} initialIDValues={learningObject.language !== undefined ? learningObject.language.map((language) => language.id) : null} + onBlurCallback={onBlurCallback} /> </Grid> <Grid item xs={12} style={{paddingBottom : "40px"}}> - <EducationalStage draftID={learningObject.id} eduStages={eduStages} initialValue={learningObject.educational_stages.map((stage) => String(stage.id))} onBlurCallback={onBlurCallback} + <EducationalStage draftID={learningObject.id} eduStages={eduStages} initialValue={learningObject.educational_stages !== null ? learningObject.educational_stages.map((stage) => String(stage.id)) : null} onBlurCallback={onBlurCallback} /> </Grid> - <SubjectsAndThemes draftId={learningObject.id} subjects={subjects} initialValue={learningObject.subjects.map(subject => String(subject.id))} onBlurCallback={onBlurCallback}/> + <SubjectsAndThemes draftId={learningObject.id} subjects={subjects} initialValue={learningObject.subjects !== null ? learningObject.subjects.map(subject => String(subject.id)) : null} onBlurCallback={onBlurCallback}/> <Grid item xs={12} style={{paddingBottom : "40px"}}> <Licenca draftID={learningObject.id} initialValue={learningObject.license ? learningObject.license.id : null} onBlurCallback={onBlurCallback}/> diff --git a/src/Pages/EditProfilePage.js b/src/Pages/EditProfilePage.js index 0cf1e91667ca942dca98460c73cb6223519de77c..f85c888d5bc7624c7988c6f76119554ba0c5da05 100644 --- a/src/Pages/EditProfilePage.js +++ b/src/Pages/EditProfilePage.js @@ -59,11 +59,11 @@ export default function EditProfilePage(props) { } function handleSuccessUpdateEmail(data) { - let auth_headers = JSON.parse(sessionStorage.getItem('@portalmec/auth_headers')) + let auth_headers = JSON.parse(localStorage.getItem('@portalmec/auth_headers')) auth_headers['uid'] = data.uid - sessionStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) + localStorage.setItem('@portalmec/auth_headers', JSON.stringify(auth_headers)) const target = state.currentUser const source = { uid: data.uid } diff --git a/src/Pages/PageNotFound.js b/src/Pages/PageNotFound.js new file mode 100644 index 0000000000000000000000000000000000000000..7e9a5b0ca55aa05bc584bad105e8ebe0f3f306e5 --- /dev/null +++ b/src/Pages/PageNotFound.js @@ -0,0 +1,44 @@ +/*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 styled from "styled-components"; + +export default function PageNotFound (props) { + return ( + <div> + <link + href="https://fonts.googleapis.com/css?family=Roboto:100,400,500&display=swap" + rel="stylesheet" + /> + <StyledDiv><span style={{ fontSize: '50px' }}>Desculpe</span></StyledDiv> + <StyledDiv><span style={{ fontSize: '30px' }}>Não foi possÃvel encontrar a página que você está procurando.</span></StyledDiv> + <StyledDiv><a href='/'><span style={{ fontSize: '20px' }}>Voltar para a página inicial</span></a></StyledDiv> + </div> + ) +} + +const StyledDiv = styled('div')` + width: 100%; + margin-top: 70px; + margin-bottom: 70px; + justify-content : space-evenly; + display: flex; + color: #757575; + text-align:center; +` \ No newline at end of file diff --git a/src/Pages/PublicUserPage.js b/src/Pages/PublicUserPage.js index 070d3cb4f7e265299ddf3efe5dfbad3124f57cbe..e853439ae47ad7504232d15d320353098d2db249 100644 --- a/src/Pages/PublicUserPage.js +++ b/src/Pages/PublicUserPage.js @@ -37,6 +37,9 @@ import { HeaderContainer, UserProfileContainer, CoverContainer, UserProfileInfoD import { fetchAllRequest } from '../Components/HelperFunctions/getAxiosConfig' import Typography from '@material-ui/core/Typography'; import CircularProgress from '@material-ui/core/CircularProgress'; +import LoadingSpinner from '../Components/LoadingSpinner'; +import Button from '@material-ui/core/Button' +import { Link } from 'react-router-dom' function RenderFollowContainer(props) { const { state } = useContext(Store) @@ -112,9 +115,13 @@ export default function PublicUserPage(props) { setUserData(data) } /*---------------------------------------------------------*/ - const [following, setFollowing] = useState([]); + const [following, setFollowing] = useState(0); const fillFollowing = (data) => { - setFollowing(data); + if (data) + if (data.errors) + setFollowing('Você precisa logar para ver o que usuário está '); + else + setFollowing(data.length); } /*content control variables--------------------------------*/ @@ -142,7 +149,7 @@ export default function PublicUserPage(props) { handleCollections(responseArr[2]) - fillFollowing(responseArr[3]); + fillFollowing(responseArr[3]) setLoading(false); } @@ -156,8 +163,30 @@ export default function PublicUserPage(props) { }, [state.currentUser.id, props.match.params.userId]) /*---------------------------------------------------------*/ - return ( - <React.Fragment> + if (loading) + return <LoadingSpinner text="Carregando dados do usuário..." /> + else if (!userData && !following && !learningObjArr && !collectionsArr) + return <UserNotFoundDiv> + <Grid container direction='column' justify='center' alignItems='center' spacing={1}> + <Grid item> + <p className="not-found"> + O usuário não foi encontrado em nossa base de dados. + </p> + </Grid> + <Grid item> + <Link className="link" to={`/busca?page=0&results_per_page=12&query=*&search_class=User`}> + <Button + variant='contained' + className="back-button" + > + Voltar para a busca de usuários. + </Button> + </Link> + </Grid> + </Grid> + </UserNotFoundDiv> + else + return <React.Fragment> <link href="https://fonts.googleapis.com/css?family=Roboto:100,400,500&display=swap" rel="stylesheet" /> <BackgroundDiv> <CustomizedBreadcrumbs @@ -191,7 +220,7 @@ export default function PublicUserPage(props) { </Grid> <Grid style={{ marginTop: '0.5em', marginBottom: '0.5em', borderTop: "0.5px solid #DCDCDC", borderBottom: "0.5px solid #DCDCDC" }} container spacing={4} justify="center" alignItems="center" direction="row"> <Grid item> - <Typography variant="h6" > + <Typography variant="h6" style={{ textAlign: 'center' }}> { loading ? <CircularProgress size={20} /> : @@ -200,13 +229,11 @@ export default function PublicUserPage(props) { </Typography> </Grid> <Grid item> - <Typography variant="h6" > + <Typography variant="h6" style={{ textAlign: 'center' }} > { loading ? <CircularProgress size={20} /> : - following ? - `${following.length} seguindo` : - "0 seguindo" + `${following} seguindo` } </Typography> </Grid> @@ -221,7 +248,7 @@ export default function PublicUserPage(props) { onChange={handleChangeTab} indicatorColor="primary" textColor="primary" - variant="fullwidth" + variant="scrollable" scrollButtons="desktop" TabIndicatorProps={{ style: { background: "#00bcd4" } }} > @@ -246,7 +273,7 @@ export default function PublicUserPage(props) { {tabValue === 0 && <TabInicio id={id} user={userData} learningObjs={learningObjArr} collections={collectionsArr} />} {tabValue === 1 && - <TabRecursos count={userData.learning_objects_count} learningObjs={learningObjArr} id={id} />} + <TabRecursos id={id} username={userData.name} />} {tabValue === 2 && <TabColecoes id={id} username={userData.name} />} {tabValue === 3 && @@ -256,7 +283,6 @@ export default function PublicUserPage(props) { </Grid> </BackgroundDiv> </React.Fragment> - ) } @@ -285,6 +311,26 @@ const ProfileAvatarDiv = styled.div` } ` +const UserNotFoundDiv = styled.div` + margin: 1em; + + .not-found{ + font-family: 'Roboto', sans-serif; + font-weight: 500; + text-align: left; + padding: 0; + margin: 0; + } + + .back-button{ + background-color: #00bcd4; + color: whitesmoke; + } + + .link{ + text-decoration: none; + } +` const FollowContainer = styled.div` padding : 4px 10px; diff --git a/src/Pages/PublicationPermissionsPage.js b/src/Pages/PublicationPermissionsPage.js index d7dcb6ac34900cb4155629e3382997be37650f10..52bdbd8a8caf5b3b2ff7cfb465b230ac120206bb 100644 --- a/src/Pages/PublicationPermissionsPage.js +++ b/src/Pages/PublicationPermissionsPage.js @@ -95,8 +95,7 @@ export default function PermissionsContainer(props) { temp[e.target.name] = e.target.value; setRadioValues(temp); - - setCheckboxAvailability(!(radios.radio1 && radios.radio2 && radios.radio3)); + setCheckboxAvailability(!(radios.radio1 === "Não" && radios.radio2 === "Não" && radios.radio3 === "Não")); }; const handleAgreement = () => { @@ -144,7 +143,7 @@ export default function PermissionsContainer(props) { <div> <div style={{ fontSize: "14px" }}> <LabeledCheckbox - disabledCheckbox={unavailableCheckbox} + disabled={unavailableCheckbox} label={ <Styledspan> Li e permito a publicação do meu recurso na @@ -159,9 +158,9 @@ export default function PermissionsContainer(props) { style={{ justifyContent: "center", display: "flex" }} > <Button - disabled={unavailableButton} + disabled={unavailableButton || unavailableCheckbox} style={ - unavailableButton + unavailableButton || unavailableCheckbox ? { backgroundColor: "#e9e9e9" } : { backgroundColor: "#00bcd4" } } @@ -169,7 +168,7 @@ export default function PermissionsContainer(props) { > <Styledspan style={ - unavailableButton + unavailableButton || unavailableCheckbox ? { color: "#666666", fontWeight : "600" } : { color: "#ffffff", fontWeight : "600" } } diff --git a/src/Pages/ResourcePage.js b/src/Pages/ResourcePage.js index ff63e4f479a36799c3d8240d5a3afa3e5905eb2c..317663da5c5d3b4f4f2ac2bd9c321e7cdcc494c7 100644 --- a/src/Pages/ResourcePage.js +++ b/src/Pages/ResourcePage.js @@ -36,6 +36,8 @@ import ButtonAvaliarRecurso from "../Components/ButtonAvaliarRecurso"; import ModalAvaliarRecurso from "../Components/ModalAvaliarRecurso"; import ModalConfirmarCuradoria from "../Components/ModalConfirmarCuradoria"; import { getRequest } from "../Components/HelperFunctions/getAxiosConfig"; +import Button from '@material-ui/core/Button'; +import { Link } from 'react-router-dom'; function urlVerify(url) { return url @@ -47,6 +49,7 @@ export default function LearningObjectPage(props) { const { state } = useContext(Store); const id = props.match.params.recursoId; const [carregando, toggle] = useState(true); + const [erro, setErro] = useState(false); const [recurso, setRecurso] = useState({}); function handleSuccessfulGet(data) { @@ -60,6 +63,7 @@ export default function LearningObjectPage(props) { url, handleSuccessfulGet, (error) => { + setErro(true) toggle(false); handleSnackbar(7) } @@ -137,178 +141,200 @@ export default function LearningObjectPage(props) { ); }; - return ( - <React.Fragment> - <Snackbar - open={snackbarOpen} - autoHideDuration={6000} - onClose={toggleSnackbar} - anchorOrigin={{ vertical: "top", horizontal: "right" }} - > - <Alert severity="info" - style={{ backgroundColor: "#00acc1" }}> - {snackbarText[snackbarIndex]} - </Alert> - </Snackbar> - - <ModalAvaliarRecurso - open={modalCuradoriaOpen} - handleClose={() => { - handleModalCuradoria(false); - }} - title={recurso.name} - confirm={handleConfirm} - setCriteria={setReportCriteria} - /> - <ModalConfirmarCuradoria - aceito={submissionAccepted} - reportCriteria={reportCriteria} - justificativa={justificativa} - open={modalConfirmarCuradoriaOpen} - handleClose={() => { - handleModalConfirmarCuradoria(false); - }} - cancel={() => { - handleModalCuradoria(true); - }} - recursoId={recurso.submission_id} - finalizeCuratorshipFlow={finalizeCuratorshipFlow} - handleErrorAprove={() => { - handleSnackbar(6) - }} - /> - <Background> - {carregando ? ( - <LoadingSpinner text={"Carregando Recurso"} /> - ) : ( - <> - <Grid container spacing={2}> - {recurso.object_type === "VÃdeo" && !recurso.link ? ( + if (erro) + return <LearnObjectNotFound> + <Grid container direction='column' justify='center' alignItems='center' spacing={1}> + <Grid item> + <p className="not-found"> + O recurso não foi encontrado em nossa base de dados. + </p> + </Grid> + <Grid item> + <Link className="link" to={`/busca?page=0&results_per_page=12&order=review_average&query=*&search_class=LearningObject`}> + <Button + variant='contained' + className="back-button" + > + Voltar para a busca de recursos. + </Button> + </Link> + </Grid> + </Grid> + </LearnObjectNotFound> + else + return ( + <React.Fragment> + <Snackbar + open={snackbarOpen} + autoHideDuration={6000} + onClose={toggleSnackbar} + anchorOrigin={{ vertical: "top", horizontal: "right" }} + > + <Alert severity="info" + style={{ backgroundColor: "#00acc1" }}> + {snackbarText[snackbarIndex]} + </Alert> + </Snackbar> + + <ModalAvaliarRecurso + open={modalCuradoriaOpen} + handleClose={() => { + handleModalCuradoria(false); + }} + title={recurso.name} + confirm={handleConfirm} + setCriteria={setReportCriteria} + /> + <ModalConfirmarCuradoria + aceito={submissionAccepted} + reportCriteria={reportCriteria} + justificativa={justificativa} + open={modalConfirmarCuradoriaOpen} + handleClose={() => { + handleModalConfirmarCuradoria(false); + }} + cancel={() => { + handleModalCuradoria(true); + }} + recursoId={recurso.submission_id} + finalizeCuratorshipFlow={finalizeCuratorshipFlow} + handleErrorAprove={() => { + handleSnackbar(6) + }} + /> + <Background> + {carregando ? ( + <LoadingSpinner text={"Carregando Recurso"} /> + ) : ( + <> + <Grid container spacing={2}> + {recurso.object_type === "VÃdeo" && !recurso.link ? ( + <Grid item xs={12}> + <Card> + <VideoPlayer + link={recurso.link} + urlVerified={false} + videoUrl={recurso.default_attachment_location} + videoType={recurso.default_mime_type} + /> + </Card> + </Grid> + ) : ( + urlVerify(recurso.link) && ( + <Grid item xs={12}> + <Card> + <VideoPlayer link={recurso.link} urlVerified={true} /> + </Card> + </Grid> + ) + )} + <Grid item xs={12}> <Card> - <VideoPlayer - link={recurso.link} - urlVerified={false} - videoUrl={recurso.default_attachment_location} - /> - </Card> - </Grid> - ) : ( - urlVerify(recurso.link) && ( - <Grid item xs={12}> - <Card> - <VideoPlayer link={recurso.link} urlVerified={true} /> - </Card> - </Grid> - ) - )} + <div> + {recurso.thumbnail && ( + <img alt="" src={apiDomain + recurso.thumbnail} /> + )} - <Grid item xs={12}> - <Card> - <div> - {recurso.thumbnail && ( - <img alt="" src={apiDomain + recurso.thumbnail} /> - )} + <TextoObjeto + name={recurso.name} + rating={recurso.review_average} + recursoId={id} + likesCount={recurso.likes_count} + likedBool={recurso.liked} + objType={recurso.object_type} + subjects={recurso.subjects} + educationalStages={recurso.educational_stages} + viewCount={recurso.views_count} + downloadCount={recurso.downloads_count} + id={recurso.publisher ? recurso.publisher.id : undefined} + stateRecurso={recurso.state} + attachments={recurso.attachments} + audioUrl={recurso.default_attachment_location} + /> + </div> - <TextoObjeto - name={recurso.name} - rating={recurso.review_average} + <Footer recursoId={id} - likesCount={recurso.likes_count} - likedBool={recurso.liked} - objType={recurso.object_type} - subjects={recurso.subjects} - educationalStages={recurso.educational_stages} - viewCount={recurso.views_count} - downloadCount={recurso.downloads_count} - id={recurso.publisher ? recurso.publisher.id : undefined} - stateRecurso={recurso.state} - attachments={recurso.attachments} - audioUrl={recurso.default_attachment_location} + downloadableLink={recurso.default_attachment_location} + handleSnackbar={handleSnackbar} + link={recurso.link} + title={recurso.name} + thumb={recurso.thumbnail} + currPageLink={window.location.href} + complained={recurso.complained} /> - </div> - - <Footer - recursoId={id} - downloadableLink={recurso.default_attachment_location} - handleSnackbar={handleSnackbar} - link={recurso.link} - title={recurso.name} - thumb={recurso.thumbnail} - currPageLink={window.location.href} - complained={recurso.complained} - /> - </Card> - </Grid> - - <Grid item xs={12}> - <Card> - {/*todo: change render method on additional item info*/} - <Sobre - avatar={ - recurso.publisher - ? recurso.publisher.avatar - ? apiDomain + recurso.publisher.avatar - : noAvatar - : noAvatar - } - publisher={ - recurso.publisher ? recurso.publisher.name : undefined - } - id={recurso.publisher ? recurso.publisher.id : undefined} - description={recurso.description} - author={recurso.author} - tags={recurso.tags} - attachments={recurso.attachments} - language={recurso.language} - mimeType={recurso.default_mime_type} - createdAt={recurso.created_at} - updatedAt={recurso.updated_at} - license={recurso.license} - followed={recurso.publisher.followed} - /> - </Card> - </Grid> + </Card> + </Grid> - {recurso.state !== "submitted" && ( <Grid item xs={12}> <Card> - {/*adicionar funcionalidade ao botao de entrar*/} - <CommentsArea - recursoId={id} - handleSnackbar={handleSnackbar} - objType={recurso.object_type} - recurso={true} + {/*todo: change render method on additional item info*/} + <Sobre + avatar={ + recurso.publisher + ? recurso.publisher.avatar + ? apiDomain + recurso.publisher.avatar + : noAvatar + : noAvatar + } + publisher={ + recurso.publisher ? recurso.publisher.name : undefined + } + id={recurso.publisher ? recurso.publisher.id : undefined} + description={recurso.description} + author={recurso.author} + tags={recurso.tags} + attachments={recurso.attachments} + language={recurso.language} + mimeType={recurso.default_mime_type} + createdAt={recurso.created_at} + updatedAt={recurso.updated_at} + license={recurso.license} + followed={recurso.publisher ? recurso.publisher.followed : undefined} /> </Card> </Grid> - )} - </Grid> - - {recurso.state === "submitted" && checkAccessLevel("curator") && ( - <AppBar - position="fixed" - color="primary" - className={classes.appBar} - > - <StyledAppBarContainer> - <div className="container"> - <div className="botoes"> - <ButtonAvaliarRecurso - callback={() => { - handleModalCuradoria(true); - }} + + {recurso.state !== "submitted" && ( + <Grid item xs={12}> + <Card> + {/*adicionar funcionalidade ao botao de entrar*/} + <CommentsArea + recursoId={id} + handleSnackbar={handleSnackbar} + objType={recurso.object_type} + recurso={true} /> + </Card> + </Grid> + )} + </Grid> + + {recurso.state === "submitted" && checkAccessLevel("curator") && ( + <AppBar + position="fixed" + color="primary" + className={classes.appBar} + > + <StyledAppBarContainer> + <div className="container"> + <div className="botoes"> + <ButtonAvaliarRecurso + callback={() => { + handleModalCuradoria(true); + }} + /> + </div> </div> - </div> - </StyledAppBarContainer> - </AppBar> - )} - </> - )} - </Background> - </React.Fragment> - ); + </StyledAppBarContainer> + </AppBar> + )} + </> + )} + </Background> + </React.Fragment> + ); } const useStyles = makeStyles((theme) => ({ @@ -353,6 +379,27 @@ const Background = styled.div` padding-top: 30px; `; +const LearnObjectNotFound = styled.div` + margin: 1em; + + .not-found{ + font-family: 'Roboto', sans-serif; + font-weight: 500; + text-align: left; + padding: 0; + margin: 0; + } + + .back-button{ + background-color: #ff7f00; + color: whitesmoke; + } + + .link{ + text-decoration: none; + } +` + const Card = styled.div` background-color: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24); diff --git a/src/Pages/Search.js b/src/Pages/Search.js index db1c0201834e8a4b54f7ac4f3313425255cf436e..15628592193b74b9363dd9d4e139a6858230bd85 100644 --- a/src/Pages/Search.js +++ b/src/Pages/Search.js @@ -1,462 +1,547 @@ -/*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, { useEffect, useState, useContext } from "react"; -import { apiDomain } from '../env'; -import { Link, useHistory } from "react-router-dom"; -import styled from "styled-components"; -import Paper from "@material-ui/core/Paper"; -import LoadingSpinner from '../Components/LoadingSpinner'; -import Breadcrumbs from "@material-ui/core/Breadcrumbs"; -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 SearchExpansionPanel from "../Components/SearchExpansionPanel/SearchExpansionPanel"; -import ResourceCardFunction from "../Components/ResourceCardFunction"; -import CollectionCardFunction from "../Components/CollectionCardFunction"; -import ContactCard from "../Components/ContactCard"; -import CircularProgress from '@material-ui/core/CircularProgress'; -import { getRequest } from '../Components/HelperFunctions/getAxiosConfig' -import ColecaoVazia from '../img/Pagina_vazia_colecao.png' -import RecursoVazio from '../img/Pagina_vazia_Sem_publicar.png' - - -let order = "review_average"; -let currFilter = ""; -let currOption; - -export default function Search(props) { - const history = useHistory() - - const { state, dispatch } = useContext(Store); - const [resultsResource, setResultsResource] = useState([]); - const [resultsCollection, setResultsCollection] = useState([]); - const [resultsUser, setResultsUser] = useState([]); - const [currOrder, setCurrOrder] = useState(order); - const [page] = useState(0); - const [isloading, setIsLoading] = useState(false); - const [loadingMoreData, setLoadingMoreData] = useState(false); - const [isFiltering, setIsFiltering] = useState(false); - const [resultsPerPage, setResultsPerPage] = useState(12); - const [showingResults, setShowingResults] = useState(0); - const [totalResults, setTotalResults] = useState(0); - const [options] = React.useState([ - { label: "Recursos", value: "LearningObject" }, - { label: "Coleções", value: "Collection" }, - { label: "Usuários", value: "User" }, - ]); - const [ordenar] = useState([ - { label: "Mais Estrelas", value: "review_average" }, - { label: "Mais Relevante", value: "score" }, - { label: "Mais Baixados", value: "downloads" }, - { label: "Mais Favoritados", value: "likes" }, - { label: "Mais Recentes", value: "publicationdesc" }, - { label: "Ordem Alfabética", value: "title" }, - ]); - - const [option, setOption] = useState( - new URLSearchParams(window.location.search).get("search_class") - ); - const [optionResult, setOptionResult] = useState(option); - currOption = option; - - function handleSuccessfulGet(data, headers) { - if (currOption === "LearningObject") setResultsResource(data); - else if (currOption === "Collection") setResultsCollection(data); - else if (currOption === "User") setResultsUser(data); - dispatch({ - type: "SAVE_SEARCH", - newSearch: { - query: state.search.query, - class: currOption, - }, - }); - if (headers.has('X-Total-Count')) { - setTotalResults(headers.get('X-Total-Count')); +// /*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, { useEffect, useState, Fragment, useContext } from 'react'; +import styled from 'styled-components'; +import { Link } from 'react-router-dom'; +import Breadcrumbs from '@material-ui/core/Breadcrumbs'; +import HeaderFilters from '../Components/SearchPageComponents/HeaderFilters'; +import ResourceTemplate from '../Components/SearchPageComponents/ResourceTemplate'; +import CollectionTemplate from '../Components/SearchPageComponents/CollectionTemplate'; +import UserTemplate from '../Components/SearchPageComponents/UserTemplate'; +import Error from '../Components/SearchPageComponents/Error'; +import { getRequest } from '../Components/HelperFunctions/getAxiosConfig'; +import { useHistory } from 'react-router-dom'; +import SearchExpansionPanel from '../Components/SearchExpansionPanel/SearchExpansionPanel'; +import FilterSummary from '../Components/SearchPageComponents/FilterSummary'; +import { + filtersCurriculum, + filtersTypes, + filtersStages, + filtersLanguages, +} from '../Components/SearchPageComponents/filters'; +import Snackbar from '@material-ui/core/Snackbar'; +import MuiAlert from '@material-ui/lab/Alert'; +import { Store } from '../Store' + +function Alert(props) { + return <MuiAlert elevation={6} variant="filled" {...props} />; +} + +export default function Search() { + const history = useHistory(); + const { state } = useContext(Store) + + const [currOption, setCurrOption] = useState(''); + const [currOrder, serCurrOrder] = useState('review_average'); + const [currQuery, setCurrQuery] = useState(''); + const [currPage, setCurrPage] = useState(0); + const [currCurriculumValues, setCurrCurriculumValues] = useState(''); + const [currTypeOfResValues, setCurrTypeOfResValues] = useState(''); + const [currTeachingStageValues, setCurrTeachingStageValues] = useState(''); + const [currLanguagesValues, setCurrLanguagesValues] = useState(''); + const [currTag, setCurrTag] = useState(''); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(false); + const [snackInfo, setSnackInfo] = useState({ + open: false, + text: "", + severity: "", + }); + + const [curriculumComponents, setCurriculumComponents] = useState([]); + const [typeOfResources, setTypeOfResources] = useState([]); + const [teachingStage, setTeachingStage] = useState([]); + const [languages, setLanguages] = useState([]); + const [tag, setTag] = useState(''); + + const [resourcesArray, setResourcesArray] = useState([]); + const [totalResources, setTotalResources] = useState(0); + + const [collectionsArray, setCollectionsArray] = useState([]) + const [totalCollections, setTotalCollections] = useState(0); + + const [usersArray, setUsersArray] = useState([]) + const [totalUsers, setTotalUsers] = useState(0); + + const options = [ + { value: 'Recursos', name: 'LearningObject', color: '#ff7f00' }, + { value: 'Coleções', name: 'Collection', color: '#673ab7' }, + { value: 'Usuários', name: 'User', color: '#00bcd4' }, + ]; + + const orders = [ + { value: 'Mais Estrelas', name: 'review_average' }, + { value: 'Mais Relevante', name: 'score' }, + { value: 'Mais Baixados', name: 'downloads' }, + { value: 'Mais Favoritados', name: 'likes' }, + { value: 'Mais Recentes', name: 'publicationdesc' }, + { value: 'Ordem Alfabética', name: 'title' }, + ]; + + function handleSnackInfo(info) { + setSnackInfo({ ...info }) + } + + function handleCloseSnack() { + const snackInfo = { + open: false, + text: "", + severity: "", } - setShowingResults(data.length) - setIsLoading(false); - setIsFiltering(false); - setLoadingMoreData(false); + handleSnackInfo(snackInfo) } - const collectStuff = (tipoBusca, filtro) => { + function onButtonClicked() { + const curriculumValues = []; + const typeOfResourcesValues = []; + const teachingStageValues = []; + const languagesValues = []; - const urlParams = new URLSearchParams(window.location.search); - const query = urlParams.get("query"); - const searchClass = urlParams.get("search_class"); + for (let index = 0; index < curriculumComponents.length; index++) { + const element = curriculumComponents[index]; + if (element.isChecked) + curriculumValues.push(element.value); + } - if (!loadingMoreData) // this line prevents resetting filter when loading more data - currFilter = filtro; - if (filtro) - setIsFiltering(true); - const url = `/search?page=${page}&results_per_page=${resultsPerPage}&order=${order}&query=${query}${currFilter ? currFilter : ""}&search_class=${searchClass}` - getRequest(url, handleSuccessfulGet, (error) => { console.log(error) }) - }; + for (let index = 0; index < typeOfResources.length; index++) { + const element = typeOfResources[index]; + if (element.isChecked) + typeOfResourcesValues.push(element.value); + } - useEffect(() => { - setIsLoading(true) + for (let index = 0; index < teachingStage.length; index++) { + const element = teachingStage[index]; + if (element.isChecked) + teachingStageValues.push(element.value); + } - const urlParams = new URLSearchParams(window.location.search); - const query = urlParams.get("query"); - const searchClass = urlParams.get("search_class"); + for (let index = 0; index < languages.length; index++) { + const element = languages[index]; + if (element.isChecked) + languagesValues.push(element.value); + } - if (state.search.query !== query || state.search.class !== searchClass) { - dispatch({ - type: "SAVE_SEARCH", - newSearch: { - query: query, - class: searchClass, - }, - }); - state.search.query = query - state.search.class = searchClass + let url = `/busca?page=0&results_per_page=12&query=${currQuery}&search_class=${currOption}` + + if (currOption !== 'User') { + url = url + `&order=${currOrder}` + if (currOption === 'LearningObject') { + if (curriculumValues.length >= 1) { + url = url + `&subjects=${curriculumValues}` + } + if (typeOfResourcesValues.length >= 1) { + url = url + `&object_types=${typeOfResourcesValues}` + } + if (teachingStageValues.length >= 1) { + url = url + `&educational_stages=${teachingStageValues}` + } + if (languagesValues.length >= 1) { + url = url + `&languages=${languagesValues}` + } + if (tag && tag.length >= 1) + url = url + `&tags=${tag}` + } } - currOption = searchClass - setOption(searchClass) - setOptionResult(searchClass) - collectStuff(searchClass) - - return () => - dispatch({ - type: "HANDLE_SEARCH_BAR", - opened: false, - }); - }, [window.history.state === null ? true : window.history.state.key, state.currentUser.id]) - useEffect(() => { - setIsLoading(true); - collectStuff(option); - }, [resultsPerPage]); - - return ( - <div style={{ backgroundColor: "#f4f4f4" }}> - <Principal> - <BreadCrumbsDiv style={{ margin: "15px 2%", }}> - <StyledBreadCrumbs> - <Link to="/">Página Inicial</Link> - <span>Busca</span> - </StyledBreadCrumbs> - </BreadCrumbsDiv> - - <div style={{ margin: "15px 2%", }}> - <HeaderFilters elevation={4} square> - <Grid container spacing={0} style={{ height: "100%" }}> - <Grid item xs style={{ display: "flex", flexDirection: "column", justifyContent: "center", paddingLeft: 20 }}> - <div style={{ marginRight: 5, marginTop: 15 }}> - <div className="textInfo"> - <span style={{ fontWeight: "bold" }}> - MOSTRAR - </span> - </div> - <Dropdown options={options} value={optionResult} - onChange={(e) => { - setIsLoading(true); - currOption = e.value; - history.push(`/busca?query=${state.search.query}&search_class=${currOption}`) - setOption(currOption); - // collectStuff(currOption, ""); - }} - placeholder="Selecione um tipo" - /> - </div> - </Grid> - - { - optionResult === "User" ? null : - <Grid item xs style={{ display: "flex", flexDirection: "column", justifyContent: "center", paddingRight: 20, }}> - <div style={{ marginLeft: 5, marginTop: 15 }}> - <div className="textInfo"> - <span style={{ fontWeight: "bold" }}> - ORDENAR POR - </span> - </div> - <Dropdown options={ordenar} value={currOrder} onChange={(e) => { - order = e.value; - setCurrOrder(e.label) - collectStuff(optionResult, currFilter); - }} - placeholder="Selecione uma opção" - /> - </div> - </Grid> - } - <Grid item xs={12}> - <div style={{ display: "flex", flexDirection: "column", justifyContent: "center" }}> - <div style={{ textAlign: "center", paddingTop: 10, fontWeight: "bolder" }}> - Exibindo {showingResults === 0 ? 0 : showingResults} resultados de {totalResults} encontrados - </div> - </div> - </Grid> - </Grid> - </HeaderFilters> - - { - isloading ? <LoadingSpinner text="Carregando..." /> : - optionResult === "Collection" ? ( - resultsCollection.length >= 1 ? - <GridBuscaCollection container direction="row" spacing={2}> - <Grid item xs> - <Grid container justify="center" alignItems="center" spacing={2}> - {resultsCollection.map((card) => ( - <Grid container item xs justify="center" alignItems="center" key={card.id}> - <CollectionCardFunction - name={card.name} - tags={card.tags} - rating={card.review_average} - id={card.id} - author={card.owner ? card.owner.name : ""} - description={card.description} - thumbnails={card.items_thumbnails} - avatar={card.owner ? card.owner.avatar : ""} - likeCount={card.likes_count} - followed={card.followed} - liked={card.liked} - collections={card.collection_items} - authorID={card.owner.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={() => { - setLoadingMoreData(true); - setResultsPerPage(resultsPerPage + 12) - }} - > - { - loadingMoreData ? <CircularProgress size={24} color="inherit" /> : "Carregar mais 12" - } - </button> - </div> - </Grid> - </GridBuscaCollection> : - <Grid container direction="row" justify="center" alignItems="center"> - <Grid item> - <img src={ColecaoVazia} alt="coleção vazia" /> - </Grid> - </Grid> - - ) : - - optionResult === "LearningObject" ? ( - resultsResource.length >= 1 ? - <GridBuscaResource container spacing={2}> - <Grid item xs={12} md={2}> - <Grid container > - <Grid item xs={12}> - <Paper elevation={4} square> - <SearchExpansionPanel onChange={collectStuff} onFiltering={isFiltering} /> - </Paper> - </Grid> - </Grid> - </Grid> - <Grid item xs> - <Grid container justify="center" spacing={3} alignItems="center" > - {resultsResource.map((card) => ( - <Grid container justify="center" alignItems="center" item xs={12} sm={6} md={4} lg={3} key={card.id}> - <ResourceCardFunction - avatar={card.publisher ? 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} - /> - </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={() => { - setLoadingMoreData(true); - setResultsPerPage(resultsPerPage + 12) - // collectStuff("LearningObject", ""); - }} - > - { - loadingMoreData ? <CircularProgress size={24} color="inherit" /> : "Carregar mais 12" - } - </button> - </div> - </Grid> - </GridBuscaResource> - - : - - <GridBuscaResource container spacing={2}> - <Grid item xs={12} md={2}> - <Grid container > - <Grid item xs={12}> - <Paper elevation={4} square> - <SearchExpansionPanel onChange={collectStuff} onFiltering={isFiltering} /> - </Paper> - </Grid> - </Grid> - </Grid> - <Grid item xs={12} md={10}> - <Grid container direction="row" justify="center" alignItems="center" style={{ height: "100%", width: "100%" }}> - <Grid> - <img src={RecursoVazio} alt="coleção vazia" /> - </Grid> - </Grid> - </Grid> - </GridBuscaResource> - ) : - optionResult === "User" && ( - <GridBuscaUser container spacing={2}> - <Grid item xs > - <Grid container spacing={2} justify="center" alignItems="center"> - {resultsUser.map((card) => ( - <Grid container justify="center" alignItems="center" item xs 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={() => { - setLoadingMoreData(true); - setResultsPerPage(resultsPerPage + 12) - // collectStuff("User", ""); - }} - > - { - loadingMoreData ? <CircularProgress color="inherit" size={24} /> : "Carregar mais 12" - } - </button> - </div> - </Grid> - </GridBuscaUser> - ) - } - </div> - </Principal> - </div> - ); -} + history.push(url); + } + + function resetFilters() { + for (let index = 0; index < filtersCurriculum.length; index++) { + if (filtersCurriculum[index].isChecked) + filtersCurriculum[index].isChecked = false; + } + for (let index = 0; index < filtersLanguages.length; index++) { + if (filtersLanguages[index].isChecked) + filtersLanguages[index].isChecked = false; + } + for (let index = 0; index < filtersStages.length; index++) { + if (filtersStages[index].isChecked) + filtersStages[index].isChecked = false; + } + for (let index = 0; index < filtersTypes.length; index++) { + if (filtersTypes[index].isChecked) + filtersTypes[index].isChecked = false; + } + setTag('') + } + + function handleChangeOption(e) { + const value = e.target.value; + let url; -const GridBuscaCollection = styled(Grid)` - color: #666; - ${'' /* background-color: green; */} + if (value !== 'User') + url = `/busca?page=0&results_per_page=12&order=review_average&query=*&search_class=${value}` + else + url = `/busca?page=0&results_per_page=12&query=*&search_class=${value}` - h4 { - padding: 0 15px; - font-size: 18px; - margin-block: 10px; - text-transform: uppercase; + resetFilters() + history.push(url); } -`; -const GridBuscaResource = styled(Grid)` - color: #666; - ${'' /* background-color: red; */} - - h4 { - padding: 0 15px; - font-size: 18px; - margin-block: 10px; - text-transform: uppercase; + + function handleChangeOrder(e) { + const value = e.target.value; + let url = `/busca?page=0&results_per_page=12&query=${currQuery}&search_class=${currOption}` + + if (currOption !== 'User') { + url = url + `&order=${value}` + if (currOption === 'LearningObject') { + if (currCurriculumValues) { + url = url + `&subjects=${currCurriculumValues}` + } + if (currTypeOfResValues) { + url = url + `&object_types=${currTypeOfResValues}` + } + if (currTeachingStageValues) { + url = url + `&educational_stages=${currTeachingStageValues}` + } + if (currLanguagesValues) { + url = url + `&languages=${currLanguagesValues}` + } + if (currTag) + url = url + `&tags=${currTag}` + } + } + + history.push(url); } -`; -const GridBuscaUser = styled(Grid)` - color: #666; - ${'' /* background-color: blue; */} - - h4 { - padding: 0 15px; - font-size: 18px; - margin-block: 10px; - text-transform: uppercase; + + function handleNextPage() { + const nextPage = currPage + 1; + let url = `/busca?page=${nextPage}&results_per_page=12&query=${currQuery}&search_class=${currOption}` + + if (currOption !== 'User') { + url = url + `&order=${currOrder}` + if (currOption === 'LearningObject') { + if (currCurriculumValues) { + url = url + `&subjects=${currCurriculumValues}` + } + if (currTypeOfResValues) { + url = url + `&object_types=${currTypeOfResValues}` + } + if (currTeachingStageValues) { + url = url + `&educational_stages=${currTeachingStageValues}` + } + if (currLanguagesValues) { + url = url + `&languages=${currLanguagesValues}` + } + if (currTag) + url = url + `&tags=${currTag}` + } + } + history.push(url); } -`; -const HeaderFilters = styled(Paper)` - height: 150px; - text-align: center; - background-color: #fff; - margin-bottom: 30px; - color: #666; - .textInfo{ - text-align: start; + function handlePreviousPage() { + const previousPage = currPage - 1; + let url = `/busca?page=${previousPage}&results_per_page=12&query=${currQuery}&search_class=${currOption}` + + if (currOption !== 'User') { + url = url + `&order=${currOrder}` + if (currOption === 'LearningObject') { + if (currCurriculumValues) { + url = url + `&subjects=${currCurriculumValues}` + } + if (currTypeOfResValues) { + url = url + `&object_types=${currTypeOfResValues}` + } + if (currTeachingStageValues) { + url = url + `&educational_stages=${currTeachingStageValues}` + } + if (currLanguagesValues) { + url = url + `&languages=${currLanguagesValues}` + } + if (currTag) + url = url + `&tags=${currTag}` + } + } + history.push(url); + } + + function handleSuccess(data, headers, option) { + if (option === 'LearningObject') { + setResourcesArray(data) + if (headers.has('X-Total-Count')) { + setTotalResources(headers.get('X-Total-Count')); + } + } + else if (option === 'Collection') { + setCollectionsArray(data) + if (headers.has('X-Total-Count')) { + setTotalCollections(headers.get('X-Total-Count')); + } + } + else { + setUsersArray(data); + if (headers.has('X-Total-Count')) { + setTotalUsers(headers.get('X-Total-Count')); + } + } + setIsLoading(false); + } + + function handleFail() { + const snackInfo = { + open: true, + text: "Houve um erro ao carregar os dados!", + severity: "warning", + } + handleSnackInfo(snackInfo) + setError(true); + setIsLoading(false); + } + + function handleSubjects(subjectsString) { + if (subjectsString) { + const selectedSubjects = subjectsString.split(','); + for (let i = 0; i < selectedSubjects.length; i++) { + const elementOfSelectedSubs = selectedSubjects[i]; + for (let j = 0; j < filtersCurriculum.length; j++) { + if (elementOfSelectedSubs === filtersCurriculum[j].value) + filtersCurriculum[j].isChecked = true; + } + } + } + setCurriculumComponents(filtersCurriculum); + } + + function handleObjectTypes(objectTypesString) { + if (objectTypesString) { + const selectedObjectTypes = objectTypesString.split(','); + for (let i = 0; i < selectedObjectTypes.length; i++) { + const elementOfSelectedObjectTypes = selectedObjectTypes[i]; + for (let j = 0; j < filtersTypes.length; j++) { + if (elementOfSelectedObjectTypes === filtersTypes[j].value) + filtersTypes[j].isChecked = true; + } + } + } + setTypeOfResources(filtersTypes); } -`; + function handleLanguages(languagesString) { + if (languagesString) { + const selectedLanguages = languagesString.split(','); + + for (let i = 0; i < selectedLanguages.length; i++) { + const elementOfSelectedLanguages = selectedLanguages[i]; + for (let j = 0; j < filtersLanguages.length; j++) { + if (elementOfSelectedLanguages === filtersLanguages[j].value) + filtersLanguages[j].isChecked = true; + } + } + } + setLanguages(filtersLanguages); + } + + function handleStages(stagesString) { + if (stagesString) { + const selectedStages = stagesString.split(','); + + for (let i = 0; i < selectedStages.length; i++) { + const elementOfSelectedStages = selectedStages[i]; + for (let j = 0; j < filtersStages.length; j++) { + if (elementOfSelectedStages === filtersStages[j].value) + filtersStages[j].isChecked = true; + } + } + } + setTeachingStage(filtersStages); + } + + useEffect(() => { + setIsLoading(true) + + const urlParams = new URLSearchParams(window.location.search); + const query = urlParams.get("query"); + const searchClass = urlParams.get("search_class"); + const page = parseInt(urlParams.get("page")); + const order = urlParams.get("order"); + const subjects = urlParams.get("subjects"); + const objectTypes = urlParams.get("object_types"); + const educationalStages = urlParams.get("educational_stages"); + const languages = urlParams.get("languages"); + const tags = urlParams.get("tags"); + + setCurrOption(searchClass); + setCurrQuery(query); + setCurrPage(page); + serCurrOrder(order); + setCurrCurriculumValues(subjects); + setCurrLanguagesValues(languages); + setCurrTeachingStageValues(educationalStages); + setCurrTypeOfResValues(objectTypes); + setCurrTag(tags); + setTag(tags); + + handleSubjects(subjects); + handleObjectTypes(objectTypes); + handleStages(educationalStages); + handleLanguages(languages); + + let url = `/search?page=${page}&results_per_page=12&query=${query}&search_class=${searchClass}` + + if (searchClass !== 'User') { + url = url + `&order=${order}` + if (searchClass === 'LearningObject') { + if (subjects) { + url = url + `&subjects[]=${subjects}` + } + if (objectTypes) { + url = url + `&object_types[]=${objectTypes}` + } + if (educationalStages) { + url = url + `&educational_stages[]=${educationalStages}` + } + if (languages) { + url = url + `&languages[]=${languages}` + } + if (tags) + url = url + `&tags[]=${tags}` + } + } + + getRequest( + url, + (data, headers) => { handleSuccess(data, headers, searchClass) }, + handleFail, + ); + + }, [window.history.state === null ? true : window.history.state.key, state.currentUser.id]) + + if (error) + return ( + <MainPageError> + <Snackbar + open={snackInfo.open} + autoHideDuration={6000} + onClose={handleCloseSnack} + anchorOrigin={{ vertical: 'top', horizontal: 'right' }} + > + <Alert onClose={handleCloseSnack} severity={snackInfo.severity}> + {snackInfo.text} + </Alert> + </Snackbar> + <Error /> + </MainPageError> + ) + else + return ( + <MainPage> + <Snackbar + open={snackInfo.open} + autoHideDuration={6000} + onClose={handleCloseSnack} + anchorOrigin={{ vertical: 'top', horizontal: 'right' }} + > + <Alert onClose={handleCloseSnack} severity={snackInfo.severity}> + {snackInfo.text} + </Alert> + </Snackbar> + <StyledBreadCrumbs> + <Link to='/'>Página Inicial</Link> + <span>Busca</span> + </StyledBreadCrumbs> + <HeaderFilters + options={options} + orders={orders} + currOption={currOption} + currOrder={currOrder} + handleChangeOption={handleChangeOption} + handleChangeOrder={handleChangeOrder} + /> + { + currOption === 'LearningObject' && + <Fragment> + <SearchExpansionPanel + setTag={(tag) => setTag(tag)} + curriculumComponents={curriculumComponents} + setCurriculum={(array) => { setCurriculumComponents(array) }} + typeOfResources={typeOfResources} + setTypeRes={(array) => { setTypeOfResources(array) }} + teachingStage={teachingStage} + setTeachingStage={(array) => { setTeachingStage(array) }} + languages={languages} + setLanguages={(array) => { setLanguages(array) }} + /> + { + <FilterSummary + curriculumComponents={curriculumComponents} + typeOfResources={typeOfResources} + languages={languages} + teachingStage={teachingStage} + tag={tag} + onButtonClicked={onButtonClicked} + /> + } + <ResourceTemplate + handleNextPage={handleNextPage} + handlePreviousPage={handlePreviousPage} + isLoading={isLoading} + currPage={currPage} + resources={resourcesArray} + totalResources={totalResources} + /> + </Fragment> + } + { + currOption === 'Collection' && + <CollectionTemplate + handleNextPage={handleNextPage} + handlePreviousPage={handlePreviousPage} + isLoading={isLoading} + currPage={currPage} + resources={collectionsArray} + totalResources={totalCollections} + /> + } + { + currOption === 'User' && + <UserTemplate + handleNextPage={handleNextPage} + handlePreviousPage={handlePreviousPage} + isLoading={isLoading} + currPage={currPage} + resources={usersArray} + totalResources={totalUsers} + /> + } + </MainPage> + ) +} + +const MainPage = styled.div` + width: 90%; + margin: 1em auto; +` +const MainPageError = styled.div` + width: 90%; + margin: 1em auto; + display: flex; + justify-content: center; + align-items: center; + padding: 1em; +` const StyledBreadCrumbs = styled(Breadcrumbs)` display: flex; justify-content: flex-start; - max-width: 1170px; span { color: #a5a5a5; } @@ -465,12 +550,3 @@ const StyledBreadCrumbs = styled(Breadcrumbs)` text-decoration: none; } `; - -const BreadCrumbsDiv = styled.div` - padding: 10px; - display: flex; -`; - -const Principal = styled.div` - margin-inline: auto; -`; diff --git a/src/Store.js b/src/Store.js index 2cf8d373cb9b4f3f88c18bfd71199b893af0886d..0cb5c0333ff49866a8125e8eb30e88582a815db9 100644 --- a/src/Store.js +++ b/src/Store.js @@ -91,7 +91,7 @@ function reducer(state, action) { currentUser:action.user } case 'USER_LOGGED_OUT': - sessionStorage.clear() + localStorage.clear() return { ...state, userIsLoggedIn:action.userLoggedOut, diff --git a/src/env.js b/src/env.js index b7359157e1c0e9d260976bbe2b2545a2e0ca51b0..95815e96e0a4b6d934c32704a85f04284e77d16e 100644 --- a/src/env.js +++ b/src/env.js @@ -18,14 +18,14 @@ along with Plataforma Integrada MEC. If not, see <http://www.gnu.org/licenses/> var apiDomain = 'https://api.portalmec.c3sl.ufpr.br', - apiVersion = 'v1', - apiUrl = apiDomain + '/' + apiVersion; + apiVersion = 'v1', + apiUrl = apiDomain + '/' + apiVersion; var simcaqAPIDomain = 'https://www.simcaq.c3sl.ufpr.br/api', - apiSimcaqVersion = 'v1', - simcaqAPIurl = simcaqAPIDomain + '/' + apiSimcaqVersion + apiSimcaqVersion = 'v1', + simcaqAPIurl = simcaqAPIDomain + '/' + apiSimcaqVersion -export {apiUrl}; -export {apiDomain}; -export {simcaqAPIurl} +export { apiUrl }; +export { apiDomain }; +export { simcaqAPIurl } diff --git a/src/index.css b/src/index.css index 954a9e8f75d3224cd71757bc80193fdaad5ac914..9f97da500a958e5ee4691b87ba4e79595a6d3ef3 100755 --- a/src/index.css +++ b/src/index.css @@ -26,6 +26,12 @@ body { -moz-osx-font-smoothing: grayscale; } +#root { + width: 100%; + height: 100%; + overflow-x: hidden; +} + code { font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace;