From 4dcba666aa3577efdc707ebf04201c0c0d65469d Mon Sep 17 00:00:00 2001 From: Asel Date: Sat, 13 Jun 2020 14:08:09 +0530 Subject: [PATCH 1/7] Integrating /proposal route and improved proposal editor page --- package-lock.json | 192 +++++++ package.json | 5 + .../insights/components/memberInfo.scss | 66 +-- src/user/organization/organization.js | 15 +- src/user/organization/organization.scss | 14 + .../ProposalEditor/EditorContent/DropZone.js | 96 ++++ .../EditorContent/EditorContent.js | 372 +++++++++++++- .../EditorContent/EditorContent.scss | 88 ++++ .../ProposalEditor/EditorContent/index.css | 470 ++++++++++++++++++ .../ProposalEditor/ProposalEditor.js | 1 + .../DashboardContent/DashboardContent.js | 246 +++++++-- .../DashboardContent/DashboardContent.scss | 10 + 12 files changed, 1495 insertions(+), 80 deletions(-) create mode 100644 src/user/proposals/ProposalEditor/EditorContent/DropZone.js create mode 100644 src/user/proposals/ProposalEditor/EditorContent/index.css diff --git a/package-lock.json b/package-lock.json index ce5a8b59..03e94f8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1005,11 +1005,87 @@ "resolved": "https://registry.npmjs.org/@date-io/core/-/core-1.3.13.tgz", "integrity": "sha512-AlEKV7TxjeK+jxWVKcCFrfYAk8spX9aCyiToFIiLPtfQbsjmRGLIhb5VZgptQcJdHtLXo7+m0DuurwFgUToQuA==" }, + "@emotion/cache": { + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", + "requires": { + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" + } + }, + "@emotion/core": { + "version": "10.0.28", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.0.28.tgz", + "integrity": "sha512-pH8UueKYO5jgg0Iq+AmCLxBsvuGtvlmiDCOuv8fGNYn3cowFpLN98L8zO56U0H1PjDIyAlXymgL3Wu7u7v6hbA==", + "requires": { + "@babel/runtime": "^7.5.5", + "@emotion/cache": "^10.0.27", + "@emotion/css": "^10.0.27", + "@emotion/serialize": "^0.11.15", + "@emotion/sheet": "0.9.4", + "@emotion/utils": "0.11.3" + } + }, + "@emotion/css": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz", + "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", + "requires": { + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3", + "babel-plugin-emotion": "^10.0.27" + } + }, "@emotion/hash": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" }, + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "requires": { + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" + } + }, + "@emotion/sheet": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", + "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==" + }, + "@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + }, + "@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" + }, "@hapi/address": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", @@ -2293,6 +2369,11 @@ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" }, + "attr-accept": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.1.0.tgz", + "integrity": "sha512-sLzVM3zCCmmDtDNhI0i96k6PUztkotSOXqE4kDGQt/6iDi5M+H0srjeF+QC6jN581l4X/Zq3Zu/tgcErEssavg==" + }, "autoprefixer": { "version": "9.7.3", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.3.tgz", @@ -2470,6 +2551,23 @@ "object.assign": "^4.1.0" } }, + "babel-plugin-emotion": { + "version": "10.0.33", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.0.33.tgz", + "integrity": "sha512-bxZbTTGz0AJQDHm8k6Rf3RQJ8tX2scsfsRyKVgAbiUPUNIRtlK+7JxP+TAd1kRLABFxe0CFm2VdK4ePkoA9FxQ==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/serialize": "^0.11.16", + "babel-plugin-macros": "^2.0.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^1.0.5", + "find-root": "^1.1.0", + "source-map": "^0.5.7" + } + }, "babel-plugin-istanbul": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", @@ -2548,6 +2646,11 @@ "resolved": "https://registry.npmjs.org/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.5.tgz", "integrity": "sha512-sGhfINU+AuMw9oFAdIn/nD5sem3pn/WgxAfDZ//Q3CnF+5uaho7C7shh2rKLk6sKE/XkfmyibghocwKdVjLIKg==" }, + "babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" + }, "babel-plugin-syntax-object-rest-spread": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz", @@ -6019,6 +6122,14 @@ "schema-utils": "^2.5.0" } }, + "file-selector": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.1.12.tgz", + "integrity": "sha512-Kx7RTzxyQipHuiqyZGf+Nz4vY9R1XGxuQl/hLoJwq+J4avk/9wxxgZyHKtbyIPJmbD4A66DWGYfyykWNpcYutQ==", + "requires": { + "tslib": "^1.9.0" + } + }, "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -6090,6 +6201,11 @@ "pkg-dir": "^3.0.0" } }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -8761,6 +8877,14 @@ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, + "linkify-it": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.2.tgz", + "integrity": "sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==", + "requires": { + "uc.micro": "^1.0.1" + } + }, "load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -9006,6 +9130,18 @@ "object-visit": "^1.0.0" } }, + "markdown-it": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-11.0.0.tgz", + "integrity": "sha512-+CvOnmbSubmQFSA9dKz1BRiaSMV7rhexl3sngKqFyXSagoA3fBdJQ8oZWtRy2knXdpDXaBw44euz37DeJQ9asg==", + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + }, "matchmediaquery": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.3.1.tgz", @@ -9029,6 +9165,11 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==" }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -11938,6 +12079,16 @@ "scheduler": "^0.18.0" } }, + "react-dropzone": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-11.0.1.tgz", + "integrity": "sha512-x/6wqRHaR8jsrNiu/boVMIPYuoxb83Vyfv77hO7/3ZRn8Pr+KH5onsCsB8MLBa3zdJl410C5FXPUINbu16XIzw==", + "requires": { + "attr-accept": "^2.0.0", + "file-selector": "^0.1.12", + "prop-types": "^15.7.2" + } + }, "react-error-overlay": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.4.tgz", @@ -11970,6 +12121,11 @@ "lottie-web": "^5.1.3" } }, + "react-markdown-editor-lite": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/react-markdown-editor-lite/-/react-markdown-editor-lite-1.1.4.tgz", + "integrity": "sha512-DnHa3e1CBax+34MKr75Bt9UPyC7PEItV16qGh59zU9YBxrISupOUwzN5oh6LLXp0uv8WrRdzyPLo3c7dHmNfKg==" + }, "react-overlays": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-2.1.0.tgz", @@ -12113,6 +12269,37 @@ "workbox-webpack-plugin": "4.3.1" } }, + "react-spinners": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.8.3.tgz", + "integrity": "sha512-fuYNjH0megp5FLuUqQXWM9mPgBXUjvYD6IkMOiwNGOOlI2UdOP1ZC3vejUAa3Y/q4qWJ6yx8rjfMjIBgEji+9A==", + "requires": { + "@emotion/core": "^10.0.15" + } + }, + "react-toastify": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-6.0.5.tgz", + "integrity": "sha512-1YXSb6Jr478c1TJEyVpxLHFvtmeXGMvdpZc0fke/7lK+MoLBC+NFgB74bq+C2SZe6LdK+K1voEURJoY88WqWvA==", + "requires": { + "classnames": "^2.2.6", + "prop-types": "^15.7.2", + "react-transition-group": "^4.4.1" + }, + "dependencies": { + "react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + } + } + }, "react-transition-group": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.3.0.tgz", @@ -14303,6 +14490,11 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, "uglify-js": { "version": "3.4.10", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz", diff --git a/package.json b/package.json index e3071a2b..746960a8 100644 --- a/package.json +++ b/package.json @@ -13,18 +13,23 @@ "axios": "^0.19.1", "boostrap": "^2.0.0", "jwt-decode": "^2.2.0", + "markdown-it": "^11.0.0", "node-sass": "^4.13.0", "react": "^16.12.0", "react-bootstrap": "^1.0.0-beta.16", "react-content-loader": "^5.0.4", "react-cookies": "^0.1.1", "react-dom": "^16.12.0", + "react-dropzone": "^11.0.1", "react-icons": "^3.9.0", "react-lottie": "^1.2.3", + "react-markdown-editor-lite": "^1.1.4", "react-redux": "^7.2.0", "react-responsive": "^8.0.3", "react-router-dom": "^5.1.2", "react-scripts": "3.3.0", + "react-spinners": "^0.8.3", + "react-toastify": "^6.0.5", "redux": "^4.0.5", "redux-thunk": "^2.3.0" }, diff --git a/src/user/dashboard/insights/components/memberInfo.scss b/src/user/dashboard/insights/components/memberInfo.scss index 97253cd6..79d2376c 100644 --- a/src/user/dashboard/insights/components/memberInfo.scss +++ b/src/user/dashboard/insights/components/memberInfo.scss @@ -19,7 +19,7 @@ .active_btn { width: 11vw; height: 5vh; - background: #1A73E8; + background: #1a73e8; border-radius: 100px; padding: 0.3em; margin-right: 1em; @@ -29,7 +29,7 @@ height: 5vh; background: rgb(250, 251, 252); border-radius: 100px; - color: #1A73E8; + color: #1a73e8; padding: 0.3em; margin-right: 1em; } @@ -37,8 +37,8 @@ .members_overview { width: 90vw; .search_bar { - background: #FFFFFF; - border: 1.5px solid #CCCCCC; + background: #ffffff; + border: 1.5px solid #cccccc; border-radius: 100px; width: 39.5%; padding: 0.4em; @@ -51,8 +51,8 @@ margin-top: 1em; .single_member { display: flex; - background: #FFFFFF; - border: 1px solid #CCCCCC; + background: #ffffff; + border: 1px solid #cccccc; box-shadow: 1px 2px 5px rgba(0, 0, 0, 0.1); padding-top: 0.7em; padding-left: 0.7em; @@ -68,7 +68,7 @@ height: 60px; background-blend-mode: normal; border-radius: 5px; - border: 1px solid #CCCCCC; + border: 1px solid #cccccc; margin-right: 0.7em; } .member_details { @@ -78,21 +78,21 @@ .row { width: 29vw; } - .member_name { - font-family: Inter; - font-style: normal; - font-weight: 600; - font-size: 1.2em; - line-height: 1.5em; - color: #1A73E8; - } - .hamburger { + .member_name { + font-family: Inter; + font-style: normal; + font-weight: 600; + font-size: 1.2em; + line-height: 1.5em; + color: #1a73e8; + } + .hamburger { .dotted_hamberger { clear: both; float: right; cursor: pointer; } - } + } } .member_designation { font-family: Inter; @@ -101,7 +101,7 @@ font-size: 0.9em; line-height: 0%; letter-spacing: 0.15em; - color: #90949C; + color: #90949c; margin-top: -0.5em; } @@ -111,13 +111,13 @@ font-weight: normal; font-size: 0.5em; line-height: 10px; - color: #90949C; + color: #90949c; margin-top: -0.7em; } } } } - input[type=text] { + input[type="text"] { padding: 0.5em; } } @@ -126,27 +126,27 @@ } } .list-group { - width: 14vw; + // width: 14vw; } .popover-body { width: 9vw; text-align: center; .overlay_list_btn { cursor: pointer; - background: transparent; - border-radius: 100px; - font-family: Inter; - font-style: normal; - font-weight: normal; - font-size: 1em; - line-height: 1.1em; - color: #EB5757; - border: 1px solid #EB5757; - box-sizing: border-box; - padding-bottom: 0.4em; + background: transparent; + border-radius: 100px; + font-family: Inter; + font-style: normal; + font-weight: normal; + font-size: 1em; + line-height: 1.1em; + color: #eb5757; + border: 1px solid #eb5757; + box-sizing: border-box; + padding-bottom: 0.4em; } .overlay_list_btn:hover { background: transparent; - color: #EB5757; + color: #eb5757; } } diff --git a/src/user/organization/organization.js b/src/user/organization/organization.js index ac8480bb..cc43976b 100644 --- a/src/user/organization/organization.js +++ b/src/user/organization/organization.js @@ -11,6 +11,8 @@ import topBarLoading from "../../placeholderLoading/topBarLoading/topBarLoading" import orgUpdatesLoading from "../../placeholderLoading/orgUpdatesLoading/orgUpdatesLoading"; import contactLoading from "../../placeholderLoading/contactLoading/contactLoading"; import cardLoading from "../../placeholderLoading/cardLoading/cardLoading"; +import { Button } from "react-bootstrap"; +import { Link } from "react-router-dom"; class Organization extends Component { constructor(props) { @@ -67,12 +69,21 @@ class Organization extends Component { )}
+ + + {this.state.isLoading ? (
{orgUpdatesLoading()}
) : (
- {" "} - {" "} +
)} diff --git a/src/user/organization/organization.scss b/src/user/organization/organization.scss index b1b5e0b0..43b07b17 100644 --- a/src/user/organization/organization.scss +++ b/src/user/organization/organization.scss @@ -31,6 +31,7 @@ .org-info { display: flex; flex-direction: row; + padding-right: 10px; .posts { flex-grow: 2; h2 { @@ -75,6 +76,19 @@ flex: 1; flex-grow: 3; } + + .proposal-btn { + height: 50px; + width: 90%; + margin-left: 40px; + font-family: Inter; + font-style: normal; + font-weight: 600; + font-size: 16px; + line-height: 27px; + + color: #ffffff; + } } } .orgupdatesloading { diff --git a/src/user/proposals/ProposalEditor/EditorContent/DropZone.js b/src/user/proposals/ProposalEditor/EditorContent/DropZone.js new file mode 100644 index 00000000..f205b8a7 --- /dev/null +++ b/src/user/proposals/ProposalEditor/EditorContent/DropZone.js @@ -0,0 +1,96 @@ +import React, { useMemo, useCallback, useState } from "react"; +import { useDropzone } from "react-dropzone"; +import { toast, ToastContainer } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; + +const baseStyle = { + flex: 1, + display: "flex", + flexDirection: "column", + alignItems: "center", + padding: "20px", + borderWidth: 2, + borderRadius: 2, + borderColor: "#eeeeee", + borderStyle: "dashed", + backgroundColor: "#fafafa", + color: "#bdbdbd", + outline: "none", + transition: "border .24s ease-in-out", + height: "160px", +}; + +const activeStyle = { + borderColor: "#2196f3", +}; + +const acceptStyle = { + borderColor: "#00e676", +}; + +const rejectStyle = { + borderColor: "#ff1744", +}; + +function StyledDropzone(props) { + const [proposalId, setProposalId] = useState(props.idContent); + + const onDrop = useCallback((acceptedFiles) => { + if (proposalId === "new") { + toast.error( + "Please save the proposal as a draft before attaching images" + ); + } else { + let formData = new FormData(); + formData.append("file", acceptedFiles[0]); + const URL = `http://localhost:5000/proposal/attach/${props.idContent}`; + + fetch(URL, { + method: "POST", + body: formData, + headers: { + Authorization: props.token, + }, + }) + .then((res) => { + toast.success("Image successfully attached to proposal!"); + }) + .catch((err) => { + console.log(err); + }); + } + }, []); + + const { + getRootProps, + getInputProps, + isDragActive, + isDragAccept, + isDragReject, + } = useDropzone({ onDrop, accept: "image/*" }); + + const style = useMemo( + () => ({ + ...baseStyle, + ...(isDragActive ? activeStyle : {}), + ...(isDragAccept ? acceptStyle : {}), + ...(isDragReject ? rejectStyle : {}), + }), + [isDragActive, isDragReject, isDragAccept] + ); + + return ( +
+
+ +

+ Drag 'n' drop some images here, or click to select an image. Files + dropped here would be attached to the proposal. +

+
+ +
+ ); +} + +export default StyledDropzone; diff --git a/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js b/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js index 4c04a860..945f8a06 100644 --- a/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js +++ b/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js @@ -1,12 +1,378 @@ import React, { Component } from "react"; +import { + Button, + Container, + Row, + Col, + Image, + ListGroup, + Form, +} from "react-bootstrap"; +import "./EditorContent.scss"; +import MdEditor from "react-markdown-editor-lite"; +import MarkdownIt from "markdown-it"; +import { withRouter } from "react-router-dom"; +import { BeatLoader } from "react-spinners"; +import { toast, ToastContainer } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; +import StyledDropzone from "./DropZone"; +import { Link } from "react-router-dom"; + +//Separately importing styles related to the markdown editor +import "./index.css"; + +const mdParser = new MarkdownIt({ + html: true, + linkify: true, + typographer: true, +}); + class EditorContent extends Component { constructor(props) { super(props); - this.state = {}; + this.state = { + currentText: "", + lastText: "", + + newProposal: false, + + //hard coding values for demo + token: + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZWRjYjE4ZjIxNWRhNzRjMThkM2YyNzQiLCJpYXQiOjE1OTE1MjE2Nzl9.q3g5Ah_rtjPIrH7z183fVmUBTv_A4OjEoL673zeG250", + userId: "5edcb18f215da74c18d3f274", + + proposalTitle: "", + proposalId: "", + markdownString: "", + proposalDescription: "", + + startSave: false, + isSaving: false, + lastSaved: new Date().toTimeString().substring(0, 8), + }; + } + + componentDidMount() { + //This means proposal is previosuly saved + if (this.props.location.state.proposalId !== "new") { + let idVar = setInterval(this.saveProposal, 20000); + this.setState( + { + idVar: idVar, + proposalId: this.props.location.state.proposalId, + }, + () => { + this.getData(); + } + ); + } + //New proposal + else { + this.setState({ + newProposal: true, + }); + } } + + //Obtain proposal data from the server + getData = () => { + console.log("getDtata called"); + fetch("http://localhost:5000/proposal/" + this.state.proposalId, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: this.state.token, + }, + }) + .then((res) => { + return res.json(); + }) + .then((resData) => { + console.log(resData); + this.setState({ + proposalTitle: resData.proposal.title, + markdownString: resData.proposal.content, + proposalDescription: resData.proposal.proposalDescription, + lastText: resData.proposal.content, + currentText: resData.proposal.content, + startSave: true, + }); + }); + }; + + //Update the content of the proposal + saveProposal = () => { + let { lastText, currentText } = this.state; + + if (lastText !== currentText) { + this.setState({ isSaving: true }); + setTimeout(() => { + fetch(`http://localhost:5000/proposal/${this.state.proposalId}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: this.state.token, + }, + body: JSON.stringify({ + title: this.state.proposalTitle, + description: this.state.proposalDescription, + content: this.state.currentText, + }), + }) + .then((res) => { + return res.json(); + }) + .then((resData) => { + this.setState({ + lastText: currentText, + isSaving: false, + lastSaved: new Date().toTimeString().substring(0, 8), + }); + }); + }, 2000); + } + }; + + createProposal = () => { + this.setState({ isSaving: true }); + setTimeout(() => { + fetch("http://localhost:5000/proposal", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: this.state.token, + }, + body: JSON.stringify({ + title: this.state.title, + content: this.state.currentText, + proposalStatus: "DRAFT", + creator: this.state.userId, + }), + }) + .then((res) => { + return res.json(); + }) + .then((resData) => { + this.setState( + { + newProposal: false, + proposalId: resData.proposal._id, + isSaving: false, + lastSaved: new Date().toTimeString().substring(0, 8), + }, + () => { + toast.success("Proposal Drafted Successfully!"); + let idVar = setInterval(this.saveProposal, 20000); + this.setState({ + idVar: idVar, + startSave: true, + }); + } + ); + }); + }, 2000); + }; + + submitProposal = () => { + fetch("http://localhost:5000/proposal/change/" + this.state.proposalId, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + Authorization: this.state.token, + }, + body: JSON.stringify({ + proposalStatus: "SUBMITTED", + }), + }).then((res) => { + setTimeout(() => { + this.props.history.push("/proposal"); + }, 3000); + toast.success( + "Proposal Successfully Submitted! Redirecting to dashboard" + ); + }); + }; + + handleEditorChange = ({ html, text }) => { + this.setState({ + draftEnabled: true, + currentText: html, + }); + }; + + handleDraftClick = () => { + if (this.state.newProposal) { + this.createProposal(); + } + }; + + onSubmitHandler = () => { + this.submitProposal(); + }; + + handleChange = (evt) => { + const value = evt.target.value; + + this.setState({ + ...this.state, + [evt.target.name]: value, + }); + }; + + handleDeleteProposal = () => { + fetch("http://localhost:5000/proposal/", { + method: "DELETE", + headers: { + "Content-Type": "application/json", + Authorization: this.state.token, + }, + body: JSON.stringify({ + proposalId: this.state.proposalId, + }), + }).then((res) => { + setTimeout(() => { + this.props.history.push("/proposal"); + }, 3000); + toast.error("Proposal Deleted Successfully. Redirecting to dashboard"); + }); + }; + + componentWillUnmount() { + clearInterval(this.state.idVar); + } + render() { - return
; + return ( +
+
+
+ Write your Proposal +
+
+ Proposal Title + + Short Description + + +
+
+
+ {this.state.newProposal ? ( + + ) : ( + + + + + + + )} + + +
+ {!this.state.newProposal ? ( + + ) : ( +
+ )} +
+
+
+
+ mdParser.render(text)} + onChange={this.handleEditorChange} + value={this.state.markdownString} + /> +
+ {this.state.startSave ? ( +
+ {this.state.isSaving ? ( +
+
+ +
+
+ Saving +
+
+ ) : ( +
+ Last saved at {this.state.lastSaved} +
+ )} +
+ ) : ( + + )} + +
+ ); } } -export default EditorContent; +export default withRouter(EditorContent); diff --git a/src/user/proposals/ProposalEditor/EditorContent/EditorContent.scss b/src/user/proposals/ProposalEditor/EditorContent/EditorContent.scss index e69de29b..345cd335 100644 --- a/src/user/proposals/ProposalEditor/EditorContent/EditorContent.scss +++ b/src/user/proposals/ProposalEditor/EditorContent/EditorContent.scss @@ -0,0 +1,88 @@ +.editor-content { + padding: 30px; + display: flex; + height: 100vh; + flex-direction: column; + .editor-toppanel { + flex-grow: 1; + display: flex; + flex-direction: row; + .editor-title { + flex-grow: 5; + width: 60%; + .form-container { + margin-top: 10px; + } + .title-text { + font-family: Inter; + font-style: normal; + font-weight: 600; + font-size: 36px; + line-height: 44px; + + color: #1d2129; + } + } + .editor-buttons { + flex-grow: 1; + text-align: right; + .option-btn { + background: #fff; + border-radius: 100px; + padding: 4px 20px; + color: #007bff; + margin: 0 10px; + height: 40px; + max-width: 170px; + cursor: pointer; + &:active { + background: #fff; + color: #007bff; + } + &:hover { + background: #fff; + color: #007bff; + } + .option-text { + font-family: Inter; + font-style: normal; + font-weight: normal; + font-size: 14px; + line-height: 19px; + /* identical to box height */ + } + } + } + } + .proposal-bottompanel { + flex-grow: 5; + display: flex; + } + + .last-saved { + margin: 10px; + font-family: Inter; + font-size: 12px; + font-weight: 400; + display: inline-block; + } + + .save-container { + display: flex; + flex-direction: row; + .container-outer { + order: 4; + .save-spinner { + display: inline-block; + margin: 10px 10px 10px 0px; + } + .save-text { + margin: 10px; + font-family: Inter; + font-size: 10px; + font-weight: 400; + display: inline inline-block; + } + } + } +} diff --git a/src/user/proposals/ProposalEditor/EditorContent/index.css b/src/user/proposals/ProposalEditor/EditorContent/index.css new file mode 100644 index 00000000..de804d4f --- /dev/null +++ b/src/user/proposals/ProposalEditor/EditorContent/index.css @@ -0,0 +1,470 @@ +@font-face { + font-family: rmel-iconfont; + src: url(data:application/vnd.ms-fontobject;base64,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); + src: url(data:font/ttf;base64,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) + format("truetype"); +} +.rmel-iconfont { + font-family: rmel-iconfont !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.rmel-icon-keyboard:before { + content: "\ed80"; +} +.rmel-icon-delete:before { + content: "\ed3c"; +} +.rmel-icon-code-block:before { + content: "\e941"; +} +.rmel-icon-code:before { + content: "\ed3b"; +} +.rmel-icon-visibility:before { + content: "\ed44"; +} +.rmel-icon-view-split:before { + content: "\ed45"; +} +.rmel-icon-link:before { + content: "\ed5f"; +} +.rmel-icon-redo:before { + content: "\ed60"; +} +.rmel-icon-undo:before { + content: "\ed61"; +} +.rmel-icon-bold:before { + content: "\ed6f"; +} +.rmel-icon-italic:before { + content: "\ed70"; +} +.rmel-icon-list-ordered:before { + content: "\ed71"; +} +.rmel-icon-list-unordered:before { + content: "\ed72"; +} +.rmel-icon-quote:before { + content: "\ed73"; +} +.rmel-icon-strikethrough:before { + content: "\ed74"; +} +.rmel-icon-underline:before { + content: "\ed75"; +} +.rmel-icon-wrap:before { + content: "\ed77"; +} +.rmel-icon-font-size:before { + content: "\ed78"; +} +.rmel-icon-grid:before { + content: "\ed8c"; +} +.rmel-icon-image:before { + content: "\ed8d"; +} +.rmel-icon-expand-less:before { + content: "\ed9f"; +} +.rmel-icon-expand-more:before { + content: "\eda0"; +} +.rmel-icon-fullscreen-exit:before { + content: "\eda1"; +} +.rmel-icon-fullscreen:before { + content: "\eda2"; +} +.rc-md-navigation { + min-height: 38px; + padding: 0 8px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + border-bottom: 1px solid #e0e0e0; + font-size: 16px; + background: #f5f5f5; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -webkit-flex-direction: row; + flex-direction: row; + -webkit-box-pack: justify; + -webkit-justify-content: space-between; + justify-content: space-between; +} +.rc-md-navigation.in-visible { + display: none; +} +.rc-md-navigation .navigation-nav { + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; + justify-content: center; + font-size: 14px; + color: #757575; +} +.rc-md-navigation .button-wrap, +.rc-md-navigation .navigation-nav { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -webkit-flex-direction: row; + flex-direction: row; +} +.rc-md-navigation .button-wrap { + -webkit-flex-wrap: wrap; + flex-wrap: wrap; +} +.rc-md-navigation .button-wrap .button { + min-width: 24px; + height: 40px; + margin-right: 5px; + display: inline-block; + cursor: pointer; + line-height: 28px; + text-align: center; + color: #757575; +} +.rc-md-navigation .button-wrap .button:hover { + color: #212121; +} +.rc-md-navigation .button-wrap .button.disabled { + color: #bdbdbd; + cursor: not-allowed; +} +.rc-md-navigation .button-wrap .rmel-iconfont { + font-size: 18px; +} +.rc-md-navigation li, +.rc-md-navigation ul { + list-style: none; + margin: 0; + padding: 0; +} +.rc-md-navigation .h1, +.rc-md-navigation .h2, +.rc-md-navigation .h3, +.rc-md-navigation .h4, +.rc-md-navigation .h5, +.rc-md-navigation .h6, +.rc-md-navigation h1, +.rc-md-navigation h2, +.rc-md-navigation h3, +.rc-md-navigation h4, +.rc-md-navigation h5, +.rc-md-navigation h6 { + font-family: inherit; + font-weight: 500; + color: inherit; + padding: 0; + margin: 0; + line-height: 1.1; +} +.rc-md-navigation h1 { + font-size: 34px; +} +.rc-md-navigation h2 { + font-size: 30px; +} +.rc-md-navigation h3 { + font-size: 24px; +} +.rc-md-navigation h4 { + font-size: 18px; +} +.rc-md-navigation h5 { + font-size: 14px; +} +.rc-md-navigation h6 { + font-size: 12px; +} +.rc-md-editor .tool-bar { + position: absolute; + z-index: 1; + right: 8px; + top: 8px; +} +.rc-md-editor .tool-bar .button { + min-width: 24px; + height: 28px; + margin-right: 5px; + display: inline-block; + cursor: pointer; + font-size: 14px; + line-height: 28px; + text-align: center; + color: #999; +} +.rc-md-editor .tool-bar .button:hover { + color: #333; +} +.rc-md-editor { + height: 100%; + min-height: 0; + padding-bottom: 1px; + position: relative; + border: 1px solid #e0e0e0; + background: #fff; + -webkit-box-sizing: border-box; + box-sizing: border-box; + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + flex-direction: column; +} +.rc-md-editor.full { + width: 100%; + height: 100% !important; + position: fixed; + left: 0; + top: 0; + z-index: 1000; +} +.rc-md-editor .editor-container { + -webkit-box-flex: 1; + -webkit-flex: 1; + flex: 1; + display: -webkit-box; + display: -webkit-flex; + display: flex; + width: 100%; + min-height: 0; + position: relative; +} +.rc-md-editor .editor-container > .section.in-visible { + display: none; +} +.rc-md-editor .editor-container > .section > .section-container { + padding: 15px; + padding-top: 10px; +} +.rc-md-editor .editor-container .sec-md { + -webkit-box-flex: 1; + -webkit-flex: 1; + flex: 1; + min-height: 0; + min-width: 0; +} +.rc-md-editor .editor-container .sec-md .input { + -webkit-box-sizing: border-box; + box-sizing: border-box; + width: 100%; + height: 100%; + overflow-y: scroll; + border: none; + resize: none; + outline: none; + min-height: 0; + background: #fff; + color: #333; + font-size: 14px; + line-height: 1.7; +} +.rc-md-editor .editor-container .sec-html { + -webkit-box-flex: 1; + -webkit-flex: 1; + flex: 1; + min-height: 0; + min-width: 0; +} +.rc-md-editor .editor-container .sec-html .html-wrap { + height: 100%; + -webkit-box-sizing: border-box; + box-sizing: border-box; + overflow: auto; +} +.custom-html-style { + color: #333; +} +.custom-html-style h1 { + font-size: 32px; + padding: 0; + border: none; + font-weight: 700; + margin: 32px 0; + line-height: 1.2; +} +.custom-html-style h2 { + font-size: 24px; + padding: 0 0; + border: none; + font-weight: 700; + margin: 24px 0; + line-height: 1.7; +} +.custom-html-style h3 { + font-size: 18px; + margin: 18px 0; + padding: 0 0; + line-height: 1.7; + border: none; +} +.custom-html-style p { + font-size: 14px; + line-height: 1.7; + margin: 8px 0; +} +.custom-html-style a { + color: #0052d9; +} +.custom-html-style a:hover { + text-decoration: none; +} +.custom-html-style strong { + font-weight: 700; +} +.custom-html-style ol, +.custom-html-style ul { + font-size: 14px; + line-height: 28px; + padding-left: 36px; +} +.custom-html-style li { + margin-bottom: 8px; + line-height: 1.7; +} +.custom-html-style hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #eee; +} +.custom-html-style pre { + display: block; + padding: 20px; + line-height: 28px; + word-break: break-word; +} +.custom-html-style code, +.custom-html-style pre { + background-color: #f5f5f5; + font-size: 14px; + border-radius: 0; + overflow-x: auto; +} +.custom-html-style code { + padding: 3px 0; + margin: 0; + word-break: normal; +} +.custom-html-style code:after, +.custom-html-style code:before { + letter-spacing: 0; +} +.custom-html-style blockquote { + position: relative; + margin: 16px 0; + padding: 5px 8px 5px 30px; + background: none repeat scroll 0 0 rgba(102, 128, 153, 0.05); + border: none; + color: #333; + border-left: 10px solid #d6dbdf; +} +.custom-html-style img, +.custom-html-style video { + max-width: 100%; +} +.custom-html-style table { + font-size: 14px; + line-height: 1.7; + max-width: 100%; + overflow: auto; + border: 1px solid #f6f6f6; + border-collapse: collapse; + border-spacing: 0; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.custom-html-style table td, +.custom-html-style table th { + word-break: break-all; + word-wrap: break-word; + white-space: normal; +} +.custom-html-style table tr { + border: 1px solid #efefef; +} +.custom-html-style table tr:nth-child(2n) { + background-color: transparent; +} +.custom-html-style table th { + text-align: center; + font-weight: 700; + border: 1px solid #efefef; + padding: 10px 6px; + background-color: #f5f7fa; + word-break: break-word; +} +.custom-html-style table td { + border: 1px solid #efefef; + text-align: left; + padding: 10px 15px; + word-break: break-word; + min-width: 60px; +} +.rc-md-editor .drop-wrap { + display: block; + position: absolute; + left: 0; + top: 28px; + z-index: 2; + min-width: 20px; + padding: 10px 0; + text-align: center; + background-color: #fff; + border: 1px solid #f1f1f1; + border-right-color: #ddd; + border-bottom-color: #ddd; +} +.rc-md-editor .drop-wrap.hidden { + display: none !important; +} +.rc-md-editor .header-list .list-item { + width: 100px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding: 8px 0; +} +.rc-md-editor .header-list .list-item:hover { + background: #f5f5f5; +} +.rc-md-editor .table-list.wrap { + position: relative; + margin: 0 10px; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.rc-md-editor .table-list.wrap .list-item { + position: absolute; + top: 0; + left: 0; + display: inline-block; + width: 20px; + height: 20px; + background-color: #e0e0e0; + border-radius: 3px; +} +.rc-md-editor .table-list.wrap .list-item.active { + background: #9e9e9e; +} diff --git a/src/user/proposals/ProposalEditor/ProposalEditor.js b/src/user/proposals/ProposalEditor/ProposalEditor.js index 04378eaf..abf80e7d 100644 --- a/src/user/proposals/ProposalEditor/ProposalEditor.js +++ b/src/user/proposals/ProposalEditor/ProposalEditor.js @@ -1,6 +1,7 @@ import React, { Component } from "react"; import Navigation from "../../dashboard/navigation/navigation"; import EditorContent from "./EditorContent/EditorContent"; +import "./ProposalEditor.scss"; class ProposalEditor extends Component { constructor(props) { diff --git a/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js b/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js index 9fd70fc8..d8bee80b 100644 --- a/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js +++ b/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js @@ -2,12 +2,119 @@ import React, { Component } from "react"; import { Button, Form, Col, Image } from "react-bootstrap"; import "./DashboardContent.scss"; import userIcon2 from "../../../../images/userIcon2.jpg"; +import { Link } from "react-router-dom"; class DashboardContent extends Component { constructor(props) { super(props); - this.state = {}; + this.state = { + token: + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZWRjYjE4ZjIxNWRhNzRjMThkM2YyNzQiLCJpYXQiOjE1OTE1MjE2Nzl9.q3g5Ah_rtjPIrH7z183fVmUBTv_A4OjEoL673zeG250", + userId: "5edcb18f215da74c18d3f274", + proposals: [], + displayItems: [], + }; } + + componentDidMount() { + this.getProposalsByUserId(); + } + + getProposalsByUserId() { + fetch(`http://localhost:5000/proposal/user/${this.state.userId}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: this.state.token, + }, + }) + .then((res) => { + return res.json(); + }) + .then((resData) => { + console.log(resData); + this.setState({ + proposals: resData.proposal, + displayItems: resData.proposal, + }); + }); + } + + handleSearchBarChange = (evt) => { + const value = evt.target.value.toLowerCase(); + const proposals = this.state.proposals; + let results = []; + + if (value.length === 0) { + this.setState({ + displayItems: proposals, + }); + } else { + proposals.forEach((item) => { + if (item.title.toLowerCase().includes(value)) { + results.push(item); + } + }); + + this.setState({ + displayItems: results, + }); + } + }; + + handleButtonClick = (name) => { + const proposals = this.state.proposals; + let results = []; + + switch (name) { + case "All": + this.setState({ + displayItems: proposals, + }); + break; + case "Accepted": + proposals.forEach((item) => { + if (item.proposalStatus === "ACCEPTED") { + results.push(item); + } + }); + this.setState({ + displayItems: results, + }); + break; + case "Submitted": + proposals.forEach((item) => { + if (item.proposalStatus === "SUBMITTED") { + results.push(item); + } + }); + this.setState({ + displayItems: results, + }); + break; + case "Draft": + proposals.forEach((item) => { + if (item.proposalStatus === "DRAFT") { + results.push(item); + } + }); + this.setState({ + displayItems: results, + }); + break; + case "Rejected": + proposals.forEach((item) => { + if (item.proposalStatus === "REJECTED") { + results.push(item); + } + }); + this.setState({ + displayItems: results, + }); + break; + } + }; + render() { return (
@@ -17,6 +124,7 @@ class DashboardContent extends Component { as="input" placeholder="search" className="searchbar" + onChange={this.handleSearchBarChange} />
@@ -25,22 +133,44 @@ class DashboardContent extends Component {
- - - - -
@@ -50,41 +180,73 @@ class DashboardContent extends Component {
-
-
-
- icon -
-
-

Sample Proposal

-

June 5, 2018 4:31 AM

+ {this.state.displayItems.map((proposalItem, index) => { + return ( +
+
+
+ icon +
+
+

{proposalItem.title}

+

{proposalItem.createdAt}

+
+ {proposalItem.proposalStatus === "DRAFT" ? ( + + ) : ( + + )} +
+
+
+ {proposalItem.proposalDescription} +
+
+ + + + +
+
- -
-
-
- ex sit ex laboris adipisicing enim eiusmod proident - exercitation ea fugiat in llit pariatur occaecat ut nostrud - ullamco ex official ex sit ex laboris adipisicing enim eiusmod - proident exercitation ea... -
-
- - -
-
-
+ ); + })}
diff --git a/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.scss b/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.scss index 2577b135..a9e787f9 100644 --- a/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.scss +++ b/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.scss @@ -112,6 +112,16 @@ height: 30px; cursor: default; } + .status-btn-submitted { + background-color: white; + padding: 4px 36px; + border: solid 1px #90949c; + border-radius: 100px; + color: #90949c; + margin: 0 5px; + height: 30px; + cursor: default; + } .dropdown-container { margin-left: auto; margin-right: 5px; From ca92134bb574f9eca6d072b0ac184537580a1ba2 Mon Sep 17 00:00:00 2001 From: Asel Date: Wed, 24 Jun 2020 15:18:50 +0530 Subject: [PATCH 2/7] Changing editor to tinymce --- package-lock.json | 87 +++++ package.json | 5 +- src/router.js | 2 +- .../DashboardContent/DashboardContent.js | 346 +++++++++++------- .../DiscussionComments/DiscussionComments.js | 50 ++- .../DiscussionContent/DiscussionContent.js | 197 +++++----- .../DiscussionContent/DiscussionContent.scss | 9 +- .../ProposalEditor/EditorContent/DropZone.js | 1 + .../EditorContent/EditorContent.js | 102 +++++- .../DashboardContent/DashboardContent.js | 26 +- 10 files changed, 584 insertions(+), 241 deletions(-) diff --git a/package-lock.json b/package-lock.json index 03e94f8a..077532a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1616,6 +1616,14 @@ "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-7.2.1.tgz", "integrity": "sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA==" }, + "@tinymce/tinymce-react": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@tinymce/tinymce-react/-/tinymce-react-3.6.0.tgz", + "integrity": "sha512-XSyAx9Md9+Ghl3UK0YtBQxaS2dCepqtOKTjYmBS4xTAzSu1UABd44WT84B8CUCd/bdT0fv1Pd51dSbpgJ8713w==", + "requires": { + "prop-types": "^15.6.2" + } + }, "@types/babel__core": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", @@ -1653,6 +1661,19 @@ "@babel/types": "^7.3.0" } }, + "@types/domhandler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/domhandler/-/domhandler-2.4.1.tgz", + "integrity": "sha512-cfBw6q6tT5sa1gSPFSRKzF/xxYrrmeiut7E0TxNBObiLSBTuFEHibcfEe3waQPEDbqBsq+ql/TOniw65EyDFMA==" + }, + "@types/domutils": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@types/domutils/-/domutils-1.7.2.tgz", + "integrity": "sha512-Nnwy1Ztwq42SSNSZSh9EXBJGrOZPR+PQ2sRT4VZy8hnsFXfCil7YlKO2hd2360HyrtFz2qwnKQ13ENrgXNxJbw==", + "requires": { + "@types/domhandler": "*" + } + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -1673,6 +1694,16 @@ "@types/node": "*" } }, + "@types/htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/@types/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-fCxmHS4ryCUCfV9+CJZY1UjkbR+6Al/EQdX5Jh03qBj9gdlPG5q+7uNoDgE/ZNXb3XNWSAQgqKIWnbRCbOyyWA==", + "requires": { + "@types/domhandler": "*", + "@types/domutils": "*", + "@types/node": "*" + } + }, "@types/istanbul-lib-coverage": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", @@ -2374,6 +2405,14 @@ "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.1.0.tgz", "integrity": "sha512-sLzVM3zCCmmDtDNhI0i96k6PUztkotSOXqE4kDGQt/6iDi5M+H0srjeF+QC6jN581l4X/Zq3Zu/tgcErEssavg==" }, + "autolinker": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-3.14.1.tgz", + "integrity": "sha512-yvsRHIaY51EYDml6MGlbqyJGfl4n7zezGYf+R7gvM8c5LNpRGc4SISkvgAswSS8SWxk/OrGCylKV9mJyVstz7w==", + "requires": { + "tslib": "^1.9.3" + } + }, "autoprefixer": { "version": "9.7.3", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.7.3.tgz", @@ -6909,6 +6948,16 @@ "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz", "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==" }, + "html-dom-parser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/html-dom-parser/-/html-dom-parser-0.3.0.tgz", + "integrity": "sha512-WDEYpO5gHGKuJbf0rwndGq7yUHJ4xboNj9l9mRGw5RsKFc3jfRozCsGAMu69zXxt4Ol8UkbqubKxu8ys0BLKtA==", + "requires": { + "@types/domhandler": "2.4.1", + "domhandler": "2.4.2", + "htmlparser2": "3.10.1" + } + }, "html-encoding-sniffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", @@ -6943,6 +6992,17 @@ } } }, + "html-react-parser": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-0.13.0.tgz", + "integrity": "sha512-hU94hE2p9xhMM61EOoiY3Kr+DfzH/uY7hGeVXQpGFRjgbYRUeyuSKORDNMIaY8IAcuHQ6Ov9pJ3x94Wvso/OmQ==", + "requires": { + "@types/htmlparser2": "3.10.1", + "html-dom-parser": "0.3.0", + "react-property": "1.0.1", + "style-to-object": "0.3.0" + } + }, "html-webpack-plugin": { "version": "4.0.0-beta.5", "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.5.tgz", @@ -7168,6 +7228,11 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" + }, "inquirer": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.3.tgz", @@ -12140,6 +12205,11 @@ "warning": "^4.0.3" } }, + "react-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/react-property/-/react-property-1.0.1.tgz", + "integrity": "sha512-1tKOwxFn3dXVomH6pM9IkLkq2Y8oh+fh/lYW3MJ/B03URswUTqttgckOlbxY2XHF3vPG6uanSc4dVsLW/wk3wQ==" + }, "react-redux": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.0.tgz", @@ -12505,6 +12575,15 @@ "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" }, + "remarkable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-2.0.1.tgz", + "integrity": "sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==", + "requires": { + "argparse": "^1.0.10", + "autolinker": "^3.11.0" + } + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -14041,6 +14120,14 @@ "schema-utils": "^2.0.1" } }, + "style-to-object": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz", + "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==", + "requires": { + "inline-style-parser": "0.1.1" + } + }, "stylehacks": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", diff --git a/package.json b/package.json index 746960a8..8f0f6106 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,10 @@ "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.4.0", "@testing-library/user-event": "^7.2.1", + "@tinymce/tinymce-react": "^3.6.0", "axios": "^0.19.1", "boostrap": "^2.0.0", + "html-react-parser": "^0.13.0", "jwt-decode": "^2.2.0", "markdown-it": "^11.0.0", "node-sass": "^4.13.0", @@ -31,7 +33,8 @@ "react-spinners": "^0.8.3", "react-toastify": "^6.0.5", "redux": "^4.0.5", - "redux-thunk": "^2.3.0" + "redux-thunk": "^2.3.0", + "remarkable": "^2.0.1" }, "proxy": "http://localhost:5000", "scripts": { diff --git a/src/router.js b/src/router.js index 92cdef44..d392c02c 100644 --- a/src/router.js +++ b/src/router.js @@ -43,7 +43,7 @@ const Router = () => ( /> { + return res.json(); + }) + .then((resData) => { + console.log(resData); + this.setState({ + proposals: resData.proposals, + displayItems: resData.proposals, + }); + }); + } + + getProposalsByUserId() { + fetch(`http://localhost:5000/proposal/user/${this.state.userId}`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: this.state.token, + }, + }) + .then((res) => { + return res.json(); + }) + .then((resData) => { + console.log(resData); + this.setState({ + proposals: resData.proposal, + displayItems: resData.proposal, + }); + }); + } + + handleSearchBarChange = (evt) => { + const value = evt.target.value.toLowerCase(); + const proposals = this.state.proposals; + let results = []; + + if (value.length === 0) { + this.setState({ + displayItems: proposals, + }); + } else { + proposals.forEach((item) => { + if (item.title.toLowerCase().includes(value)) { + results.push(item); + } + }); + + this.setState({ + displayItems: results, + }); + } + }; + + handleButtonClick = (name) => { + const proposals = this.state.proposals; + let results = []; + + switch (name) { + case "All": + this.setState({ + displayItems: proposals, + }); + break; + case "Accepted": + proposals.forEach((item) => { + if (item.proposalStatus === "ACCEPTED") { + results.push(item); + } + }); + this.setState({ + displayItems: results, + }); + break; + case "Submitted": + proposals.forEach((item) => { + if (item.proposalStatus === "SUBMITTED") { + results.push(item); + } + }); + this.setState({ + displayItems: results, + }); + break; + case "Draft": + proposals.forEach((item) => { + if (item.proposalStatus === "DRAFT") { + results.push(item); + } + }); + this.setState({ + displayItems: results, + }); + break; + case "Rejected": + proposals.forEach((item) => { + if (item.proposalStatus === "REJECTED") { + results.push(item); + } + }); + this.setState({ + displayItems: results, + }); + break; + } + }; + render() { return (
@@ -17,6 +148,7 @@ class DashboardContent extends Component { as="input" placeholder="search" className="searchbar" + onChange={this.handleSearchBarChange} />
@@ -25,150 +157,118 @@ class DashboardContent extends Component {
- - - - - - -
-
-
-
- -
-
-
-
-
- icon -
-
-

Admin panel in donut dashboard

-

June 5, 2018 4:31 AM

-
-
-
-
- ex sit ex laboris adipisicing enim eiusmod proident - exercitation ea fugiat in llit pariatur occaecat ut nostrud - ullamco ex official ex sit ex laboris adipisicing enim eiusmod - proident exercitation ea... -
-
- - -
-
-
-
-
-
- icon -
-
-

Admin panel in donut dashboard

-

June 5, 2018 4:31 AM

-
+ -
-
-
- ex sit ex laboris adipisicing enim eiusmod proident - exercitation ea fugiat in llit pariatur occaecat ut nostrud - ullamco ex official ex sit ex laboris adipisicing enim eiusmod - proident exercitation ea... -
-
- - -
-
-
-
-
-
- icon -
-
-

Admin panel in donut dashboard

-

June 5, 2018 4:31 AM

-
-
-
- ex sit ex laboris adipisicing enim eiusmod proident - exercitation ea fugiat in llit pariatur occaecat ut nostrud - ullamco ex official ex sit ex laboris adipisicing enim eiusmod - proident exercitation ea... -
-
- - -
-
+ +
+
+ {this.state.displayItems.map((proposalItem, index) => { + return ( +
+
+
+ icon +
+
+

{proposalItem.title}

+

{proposalItem.createdAt}

+
+ {proposalItem.proposalStatus === "DRAFT" ? ( + + ) : ( + + )} +
+
+
+ {proposalItem.proposalDescription} +
+
+ + + +
+
+
+ ); + })} +
+
); } diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js index cfa35155..aff24ec4 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js @@ -1,32 +1,74 @@ import React, { Component } from "react"; import userIcon2 from "../../../../../images/userIcon2.jpg"; -import { Form, ListGroup } from "react-bootstrap"; +import { Form, ListGroup, Button } from "react-bootstrap"; import "./DiscussionComments.scss"; class DiscussionComments extends Component { constructor(props) { super(props); - this.state = {}; + this.state = { + commentContent: "", + commentItems: this.props.commentItems, + }; } + handleComment = () => { + fetch("http://localhost:5000/proposal/comment", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: this.props.token, + }, + body: JSON.stringify({ + userId: this.props.userId, + proposalId: this.props.proposalId, + comment: this.state.commentContent, + }), + }); + + this.setState({ + commentContent: "", + }); + }; + + handleTextCHange = (e) => { + this.setState({ + commentContent: e.target.value, + }); + }; + render() { const comments = this.props.commentItems; return (
Comments
-
+
{comments}
-
+ +
diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js index 66248bb0..37765501 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js @@ -5,20 +5,97 @@ import DiscussionComments from "./DiscussionComments/DiscussionComments"; import eventImg from "../../../../svgs/event-img-1.svg"; import userIcon2 from "../../../../images/userIcon2.jpg"; import RequestChanges from "../DiscussionPopups/RequestChanges"; +import { withRouter } from "react-router-dom"; +import { Remarkable } from "remarkable"; +import parse from "html-react-parser"; +import { Editor } from "@tinymce/tinymce-react"; + +const md = new Remarkable({ + html: true, // Enable HTML tags in source + xhtmlOut: false, // Use '/' to close single tags (
) + breaks: false, // Convert '\n' in paragraphs into
+ langPrefix: "language-", // CSS language prefix for fenced blocks + + // Enable some language-neutral replacement + quotes beautification + typographer: false, + + // Double + single quotes replacement pairs, when typographer enabled, + // and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. + quotes: "“”‘’", + + // Highlighter function. Should return escaped HTML, + // or '' if the source string is not changed + highlight: function (/*str, lang*/) { + return ""; + }, +}); class DiscussionContent extends Component { constructor(props) { super(props); - this.state = { comments: [], showModal: false, selectedText: "" }; + this.state = { + comments: [], + showModal: false, + selectedText: "", + proposalId: "", + isAdmin: false, + proposalTitle: "", + markdownString: "", + proposalDescription: "", + commentList: [], + }; } + //Token would be passed down from the componentDidMount() { - this.processComments(); + const { proposalId, isAdmin, userId, token } = this.props.location.state; + + this.setState( + { + proposalId: proposalId, + isAdmin: isAdmin, + userId: userId, + token: token, + }, + () => { + console.log(this.state); + this.getData(); + } + ); } + + getData = () => { + console.log("getDtata called"); + fetch("http://localhost:5000/proposal/" + this.state.proposalId, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: this.state.token, + }, + }) + .then((res) => { + return res.json(); + }) + .then((resData) => { + console.log(resData); + this.setState( + { + proposalTitle: resData.proposal.title, + markdownString: resData.proposal.content, + proposalDescription: resData.proposal.proposalDescription, + commentList: resData.proposal.comments, + }, + () => { + this.processComments(); + } + ); + }); + }; + processComments = () => { let comments = []; - for (let i = 0; i < 6; i++) { + this.state.commentList.forEach((commentItem) => { comments.push(
@@ -31,20 +108,13 @@ class DiscussionContent extends Component { />
-
Devesh
-
- "Lorem ipsum dolor sit amet" -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do - eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut - enim ad minim veniam, quis nostrud exercitation -
+
{commentItem.userName}
+
{commentItem.comment}
); - } + }); this.setState({ comments: comments, }); @@ -100,7 +170,7 @@ class DiscussionContent extends Component {
- Proposal Title Here + {this.state.proposalTitle}
@@ -112,74 +182,25 @@ class DiscussionContent extends Component {
-

- Fugiat esse aliquip sint culpa. Nulla amet ipsum non commodo - veniam velit officia dolor laborum et aliquip ad velit veniam. - Consequat mollit consequat adipisicing duis consectetur duis non - fugiat et in elit consectetur sint. Mollit id aliqua commodo - duis sint non. Officia sunt consectetur et officia officia ad - officia aliquip qui enim aliquip officia minim. Minim consequat - duis deserunt aliqua qui consectetur tempor ex aliquip occaecat - ad veniam consectetur. Dolor et laboris sit esse laborum ex - deserunt nisi magna eiusmod. Mollit non ipsum laboris nulla - commodo enim elit magna amet. Quis officia incididunt aute elit - veniam ullamco ea elit reprehenderit. Pariatur exercitation ut - quis occaecat esse consectetur eu eiusmod ut et exercitation. - Nisi pariatur eu deserunt aliqua cillum dolore. Dolore duis - laboris occaecat incididunt minim aliqua. -

-

- Heading Irure mollit mollit proident amet sunt ea deserunt do - anim proident mollit. Aliquip fugiat quis ipsum est nisi ut - magna excepteur aliquip reprehenderit occaecat. Ea enim officia - labore consectetur et ad. Mollit ut duis nulla amet dolor minim - laborum amet cillum velit. Incididunt elit quis ipsum velit esse - eu adipisicing sint voluptate ea ipsum. Ullamco pariatur - incididunt tempor qui voluptate id deserunt tempor. Consectetur - mollit aute consequat ut non amet fugiat eiusmod. Cupidatat - velit ea eu veniam proident irure ullamco dolor aliquip nisi - minim. Nisi consequat sit ea anim duis in id mollit ipsum aute - mollit commodo excepteur occaecat. Aliqua magna sunt in et duis - veniam. Cillum in sunt sint officia. Dolor aliqua irure dolor - adipisicing et culpa. Heading Cupidatat pariatur exercitation - enim adipisicing qui labore officia cupidatat. Proident amet - minim cupidatat proident velit in ea sint velit. Duis - adipisicing excepteur cupidatat consequat ex non cupidatat ea - non. Commodo ad anim. Cupidatat pariatur exercitation enim - adipisicing qui labore officia cupidatat. Proident amet minim - cupidatat proident velit in ea sint velit. Duis adipisicing - excepteur cupidatat consequat ex non cupidatat ea non. Commodo - ad anim.Cupidatat pariatur exercitation enim adipisicing qui - labore officia cupidatat. Proident amet minim cupidatat proident - velit in ea sint velit. Duis adipisicing excepteur cupidatat - consequat ex non cupidatat ea non. Commodo ad anim. -

-

- Heading Irure mollit mollit proident amet sunt ea deserunt do - anim proident mollit. Aliquip fugiat quis ipsum est nisi ut - magna excepteur aliquip reprehenderit occaecat. Ea enim officia - labore consectetur et ad. Mollit ut duis nulla amet dolor minim - laborum amet cillum velit. Incididunt elit quis ipsum velit esse - eu adipisicing sint voluptate ea ipsum. Ullamco pariatur - incididunt tempor qui voluptate id deserunt tempor. Consectetur - mollit aute consequat ut non amet fugiat eiusmod. Cupidatat - velit ea eu veniam proident irure ullamco dolor aliquip nisi - minim. Nisi consequat sit ea anim duis in id mollit ipsum aute - mollit commodo excepteur occaecat. Aliqua magna sunt in et duis - veniam. Cillum in sunt sint officia. Dolor aliqua irure dolor - adipisicing et culpa. Heading Cupidatat pariatur exercitation - enim adipisicing qui labore officia cupidatat. Proident amet - minim cupidatat proident velit in ea sint velit. Duis - adipisicing excepteur cupidatat consequat ex non cupidatat ea - non. Commodo ad anim. Cupidatat pariatur exercitation enim - adipisicing qui labore officia cupidatat. Proident amet minim - cupidatat proident velit in ea sint velit. Duis adipisicing - excepteur cupidatat consequat ex non cupidatat ea non. Commodo - ad anim.Cupidatat pariatur exercitation enim adipisicing qui - labore officia cupidatat. Proident amet minim cupidatat proident - velit in ea sint velit. Duis adipisicing excepteur cupidatat - consequat ex non cupidatat ea non. Commodo ad anim. -

+ {/*

{parse(md.render(this.state.markdownString))}

*/} +
Attached Images
@@ -190,10 +211,16 @@ class DiscussionContent extends Component {
- +
{ this.handleClose(); }} @@ -206,4 +233,4 @@ class DiscussionContent extends Component { } } -export default DiscussionContent; +export default withRouter(DiscussionContent); diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.scss b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.scss index 6ac75b44..413e5a20 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.scss +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.scss @@ -59,8 +59,7 @@ max-height: 80vh; .proposal-text { - overflow: auto; - flex-grow: 4; + flex: 4; font-family: Inter; font-style: normal; font-weight: normal; @@ -70,8 +69,8 @@ color: #1d2129; } .attached-images { - padding: 10px 10px 0px 0px; - flex-grow: 1; + padding: 0px 10px 0px 0px; + flex: 1; .images-title { margin-top: 10px; font-family: Inter; @@ -83,7 +82,7 @@ color: #000000; } .image-item { - max-height: 10em; + max-height: 8em; margin-right: 10px; margin-left: 10px; } diff --git a/src/user/proposals/ProposalEditor/EditorContent/DropZone.js b/src/user/proposals/ProposalEditor/EditorContent/DropZone.js index f205b8a7..1dbde1bd 100644 --- a/src/user/proposals/ProposalEditor/EditorContent/DropZone.js +++ b/src/user/proposals/ProposalEditor/EditorContent/DropZone.js @@ -41,6 +41,7 @@ function StyledDropzone(props) { "Please save the proposal as a draft before attaching images" ); } else { + console.log(props); let formData = new FormData(); formData.append("file", acceptedFiles[0]); const URL = `http://localhost:5000/proposal/attach/${props.idContent}`; diff --git a/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js b/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js index 945f8a06..1420d2bd 100644 --- a/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js +++ b/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js @@ -1,13 +1,5 @@ import React, { Component } from "react"; -import { - Button, - Container, - Row, - Col, - Image, - ListGroup, - Form, -} from "react-bootstrap"; +import { Button, Form } from "react-bootstrap"; import "./EditorContent.scss"; import MdEditor from "react-markdown-editor-lite"; import MarkdownIt from "markdown-it"; @@ -17,6 +9,7 @@ import { toast, ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; import StyledDropzone from "./DropZone"; import { Link } from "react-router-dom"; +import { Editor } from "@tinymce/tinymce-react"; //Separately importing styles related to the markdown editor import "./index.css"; @@ -76,7 +69,6 @@ class EditorContent extends Component { //Obtain proposal data from the server getData = () => { - console.log("getDtata called"); fetch("http://localhost:5000/proposal/" + this.state.proposalId, { method: "GET", headers: { @@ -240,6 +232,14 @@ class EditorContent extends Component { componentWillUnmount() { clearInterval(this.state.idVar); } + handleTinyEditorChange = (content, editor) => { + console.log("Content was updated:", content); + + this.setState({ + draftEnabled: true, + currentText: content, + }); + }; render() { return ( @@ -311,7 +311,7 @@ class EditorContent extends Component {
{!this.state.newProposal ? ( ) : ( @@ -321,11 +321,83 @@ class EditorContent extends Component {
- mdParser.render(text)} - onChange={this.handleEditorChange} + +
{this.state.startSave ? ( diff --git a/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js b/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js index d8bee80b..f9576441 100644 --- a/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js +++ b/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js @@ -234,14 +234,26 @@ class DashboardContent extends Component { Edit - + +
From f421b31800044add006250acdbe8b424304a182f Mon Sep 17 00:00:00 2001 From: Asel Date: Sat, 27 Jun 2020 16:27:58 +0530 Subject: [PATCH 3/7] Integration of notifications and minor improvements --- package-lock.json | 432 ++++++++++++++++-- package.json | 3 +- .../DiscussionComments/DiscussionComments.js | 6 +- .../DiscussionContent/DiscussionContent.js | 135 ++++-- .../EditorContent/EditorContent.js | 25 +- .../DashboardRightPanel.js | 7 +- .../DashboardRightPanel.scss | 6 +- .../Notifications/Notifications.js | 153 +++++++ .../OtherIdeas.scss | 4 +- .../OtherIdeas/OtherIdeas.js | 119 ----- .../Utils/notifications.js | 0 .../DashboardRightPanel/Utils/socket.js | 3 + 12 files changed, 676 insertions(+), 217 deletions(-) create mode 100644 src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js rename src/user/proposals/UserProposalDashboard/DashboardRightPanel/{OtherIdeas => Notifications}/OtherIdeas.scss (95%) delete mode 100644 src/user/proposals/UserProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.js create mode 100644 src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/notifications.js create mode 100644 src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/socket.js diff --git a/package-lock.json b/package-lock.json index c44c351d..159d1760 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1843,6 +1843,19 @@ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, + "@types/domhandler": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/domhandler/-/domhandler-2.4.1.tgz", + "integrity": "sha512-cfBw6q6tT5sa1gSPFSRKzF/xxYrrmeiut7E0TxNBObiLSBTuFEHibcfEe3waQPEDbqBsq+ql/TOniw65EyDFMA==" + }, + "@types/domutils": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@types/domutils/-/domutils-1.7.2.tgz", + "integrity": "sha512-Nnwy1Ztwq42SSNSZSh9EXBJGrOZPR+PQ2sRT4VZy8hnsFXfCil7YlKO2hd2360HyrtFz2qwnKQ13ENrgXNxJbw==", + "requires": { + "@types/domhandler": "*" + } + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -2309,6 +2322,11 @@ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, + "a11y-focus-store": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/a11y-focus-store/-/a11y-focus-store-1.0.0.tgz", + "integrity": "sha1-rlJWHLhq5sKQTBpKvy5YIL9TBbA=" + }, "abab": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz", @@ -2451,6 +2469,11 @@ "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" }, + "animation-bus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/animation-bus/-/animation-bus-0.2.0.tgz", + "integrity": "sha1-Q4VMLJRj+4LGZO/w4ZuXMwgRUPo=" + }, "ansi-colors": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", @@ -2520,6 +2543,14 @@ "sprintf-js": "~1.0.2" } }, + "aria-hidden": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.1.1.tgz", + "integrity": "sha512-M7zYxCcOQPOaxGHoMTKUFD2UNcVFTp9ycrdStLcTPLf8zgTXC3+YcGe+UuzSh5X1BX/0/PtS8xTNy4xyH/6xtw==", + "requires": { + "tslib": "^1.0.0" + } + }, "aria-query": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.0.tgz", @@ -2707,14 +2738,6 @@ "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.1.0.tgz", "integrity": "sha512-sLzVM3zCCmmDtDNhI0i96k6PUztkotSOXqE4kDGQt/6iDi5M+H0srjeF+QC6jN581l4X/Zq3Zu/tgcErEssavg==" }, - "autolinker": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-3.14.1.tgz", - "integrity": "sha512-yvsRHIaY51EYDml6MGlbqyJGfl4n7zezGYf+R7gvM8c5LNpRGc4SISkvgAswSS8SWxk/OrGCylKV9mJyVstz7w==", - "requires": { - "tslib": "^1.9.3" - } - }, "autoprefixer": { "version": "9.8.0", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.0.tgz", @@ -2868,6 +2891,13 @@ "escape-string-regexp": "^1.0.5", "find-root": "^1.1.0", "source-map": "^0.5.7" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } } }, "babel-plugin-istanbul": { @@ -3387,6 +3417,11 @@ "resolved": "https://registry.npmjs.org/boostrap/-/boostrap-2.0.0.tgz", "integrity": "sha512-JEeFMOweKeGXEM9rt95eaVISOkluG9aKcl0jQCETOVH9jynCZxuBZe2oWgcWJpj5wqYWZl625SnW7OgHT2Ineg==" }, + "bowser": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.9.4.tgz", + "integrity": "sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4270,6 +4305,52 @@ "sha.js": "^2.4.8" } }, + "cross-env": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz", + "integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==", + "requires": { + "cross-spawn": "^7.0.1" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + } + } + }, "cross-spawn": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", @@ -4356,6 +4437,15 @@ } } }, + "css-in-js-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz", + "integrity": "sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA==", + "requires": { + "hyphenate-style-name": "^1.0.2", + "isobject": "^3.0.1" + } + }, "css-loader": { "version": "3.4.2", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.4.2.tgz", @@ -5069,6 +5159,14 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "requires": { + "iconv-lite": "~0.4.13" + } + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -6041,6 +6139,35 @@ "bser": "2.1.1" } }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + } + } + }, "figgy-pudding": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", @@ -6071,6 +6198,14 @@ "schema-utils": "^2.5.0" } }, + "file-selector": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.1.12.tgz", + "integrity": "sha512-Kx7RTzxyQipHuiqyZGf+Nz4vY9R1XGxuQl/hLoJwq+J4avk/9wxxgZyHKtbyIPJmbD4A66DWGYfyykWNpcYutQ==", + "requires": { + "tslib": "^1.9.0" + } + }, "filesize": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.0.1.tgz", @@ -6183,6 +6318,11 @@ "readable-stream": "^2.3.6" } }, + "focus-lock": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/focus-lock/-/focus-lock-0.7.0.tgz", + "integrity": "sha512-LI7v2mH02R55SekHYdv9pRHR9RajVNyIJ2N5IEkWbg7FT5ZmJ9Hw4mWxHeEUcd+dJo0QmzztHvDvWcc7prVFsw==" + }, "follow-redirects": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz", @@ -6295,6 +6435,11 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fscreen": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fscreen/-/fscreen-1.0.2.tgz", + "integrity": "sha1-xMUdltgZ11oZ1yjg30Rfm+m7mE8=" + }, "fsevents": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", @@ -6355,11 +6500,21 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, + "get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==" + }, "get-own-enumerable-property-symbols": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz", "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==" }, + "get-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-prefix/-/get-prefix-1.0.0.tgz", + "integrity": "sha1-DTBUSKTjF2+cJ3F1sU4W2+b7oLU=" + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -6386,6 +6541,15 @@ "assert-plus": "^1.0.0" } }, + "glam": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/glam/-/glam-5.0.1.tgz", + "integrity": "sha512-NCnYcPpefXJMH30LaUfKKP3BkpipI9jkeOvzMZAd76cuDxfKmQRBvgQ1LxXRj9IRZVAwl0K3WQvbw+tiyK2pcw==", + "requires": { + "fbjs": "^0.8.16", + "inline-style-prefixer": "^3.0.8" + } + }, "glob": { "version": "7.1.6", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", @@ -7044,6 +7208,15 @@ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==" }, + "inline-style-prefixer": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-3.0.8.tgz", + "integrity": "sha1-hVG45bTVcyROZqNLBPfTIHaitTQ=", + "requires": { + "bowser": "^1.7.3", + "css-in-js-utils": "^2.0.0" + } + }, "inquirer": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.2.0.tgz", @@ -7464,6 +7637,15 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -8973,6 +9155,11 @@ "through2": "^2.0.0" } }, + "mitt": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.1.3.tgz", + "integrity": "sha512-mUDCnVNsAi+eD6qA0HkRkwYczbLHJ49z17BGe2PYRhZL4wpZUFZGJHU7/5tmvohoma+Hdn0Vh/oJTiPEmgSruA==" + }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -9117,6 +9304,15 @@ "tslib": "^1.10.0" } }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node-forge": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", @@ -11129,6 +11325,11 @@ "performance-now": "^2.1.0" } }, + "raf-schd": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-2.1.2.tgz", + "integrity": "sha512-Orl0IEvMtUCgPddgSxtxreK77UiQz4nPYJy9RggVzu4mKsZkQWiAaG1y9HlYWdvm9xtN348xRaT37qkvL/+A+g==" + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -11219,6 +11420,14 @@ "warning": "^4.0.3" } }, + "react-clientside-effect": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/react-clientside-effect/-/react-clientside-effect-1.2.2.tgz", + "integrity": "sha512-nRmoyxeok5PBO6ytPvSjKp9xwXg9xagoTK1mMjwnQxqM9Hd7MNPl+LS1bOSOe+CV2+4fnEquc7H/S8QD3q697A==", + "requires": { + "@babel/runtime": "^7.0.0" + } + }, "react-content-loader": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/react-content-loader/-/react-content-loader-5.0.4.tgz", @@ -11523,6 +11732,41 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz", "integrity": "sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA==" }, + "react-focus-lock": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/react-focus-lock/-/react-focus-lock-2.4.0.tgz", + "integrity": "sha512-mue/boxdfNhfxnQcZtEBvqwZ5XQxk0uRoAMwLGl8j6XolFV3UIlt6iGFBGqRdJsvVHhtyKC5i8fkLnBidxCTbA==", + "requires": { + "@babel/runtime": "^7.0.0", + "focus-lock": "^0.7.0", + "prop-types": "^15.6.2", + "react-clientside-effect": "^1.2.2", + "use-callback-ref": "^1.2.1", + "use-sidecar": "^1.0.1" + } + }, + "react-focus-on": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/react-focus-on/-/react-focus-on-3.4.1.tgz", + "integrity": "sha512-KGRIl0iAu+1k1dcX7eQCXF5ZR/nl+XyXN5Ukw/OY80vLaK2b6vDzNqnX0HdYbY5xSUhIRUvMWEzSsdEyPjvk/Q==", + "requires": { + "aria-hidden": "^1.1.1", + "react-focus-lock": "^2.3.1", + "react-remove-scroll": "^2.3.0", + "react-style-singleton": "^2.1.0", + "use-callback-ref": "^1.2.3", + "use-sidecar": "^1.0.1" + } + }, + "react-full-screen": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/react-full-screen/-/react-full-screen-0.2.4.tgz", + "integrity": "sha512-K6V87g/uopQnnebg6/jM7VL3FcurgCIQU4nTkzknbjGOT9XOOxr3XVwRweI8QPn1TFRZH7j5OpHanUdk5uYlBQ==", + "requires": { + "@types/react": "*", + "fscreen": "^1.0.1" + } + }, "react-icons": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.10.0.tgz", @@ -11538,6 +11782,64 @@ } } }, + "react-images": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/react-images/-/react-images-1.1.7.tgz", + "integrity": "sha512-9paR4bdP/SPTbJ/8cLa6+7+pcq8PGN4/8UjTfztQKBRzGxH0BtHrB7oj/7As2RmYMkOsVIMNfDaWzZZK4faIRA==", + "requires": { + "a11y-focus-store": "^1.0.0", + "cross-env": "^7.0.2", + "glam": "^5.0.1", + "html-react-parser": "^0.10.3", + "raf-schd": "^2.1.2", + "react-focus-on": "^3.3.0", + "react-full-screen": "^0.2.4", + "react-transition-group": "^2.9.0", + "react-view-pager": "^0.6.0" + }, + "dependencies": { + "dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, + "html-dom-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/html-dom-parser/-/html-dom-parser-0.2.3.tgz", + "integrity": "sha512-GdzE63/U0IQEvcpAz0cUdYx2zQx0Ai+HWvE9TXEgwP27+SymUzKa7iB4DhjYpf2IdNLfTTOBuMS5nxeWOosSMQ==", + "requires": { + "@types/domhandler": "2.4.1", + "domhandler": "2.4.2", + "htmlparser2": "3.10.1" + } + }, + "html-react-parser": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-0.10.5.tgz", + "integrity": "sha512-rtMWZ7KZjd9sO8jyIX7am0vGCIL45tCmctTnassT/BrTGeTaAZ4nQyqoGcx2v+vB8CAY+Q5PZiiV6eOiowq8dQ==", + "requires": { + "@types/domhandler": "2.4.1", + "html-dom-parser": "0.2.3", + "react-property": "1.0.1", + "style-to-object": "0.3.0" + } + }, + "react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "requires": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + } + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -11562,6 +11864,23 @@ "resolved": "https://registry.npmjs.org/react-markdown-editor-lite/-/react-markdown-editor-lite-1.1.4.tgz", "integrity": "sha512-DnHa3e1CBax+34MKr75Bt9UPyC7PEItV16qGh59zU9YBxrISupOUwzN5oh6LLXp0uv8WrRdzyPLo3c7dHmNfKg==" }, + "react-motion": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/react-motion/-/react-motion-0.5.2.tgz", + "integrity": "sha512-9q3YAvHoUiWlP3cK0v+w1N5Z23HXMj4IF4YuvjvWegWqNPfLXsOBE/V7UvQGpXxHFKRQQcNcVQE31g9SB/6qgQ==", + "requires": { + "performance-now": "^0.2.0", + "prop-types": "^15.5.8", + "raf": "^3.1.0" + }, + "dependencies": { + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" + } + } + }, "react-overlays": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-3.2.0.tgz", @@ -11594,6 +11913,27 @@ "react-is": "^16.9.0" } }, + "react-remove-scroll": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.3.0.tgz", + "integrity": "sha512-UqVimLeAe+5EHXKfsca081hAkzg3WuDmoT9cayjBegd6UZVhlTEchleNp9J4TMGkb/ftLve7ARB5Wph+HJ7A5g==", + "requires": { + "react-remove-scroll-bar": "^2.1.0", + "react-style-singleton": "^2.1.0", + "tslib": "^1.0.0", + "use-callback-ref": "^1.2.3", + "use-sidecar": "^1.0.1" + } + }, + "react-remove-scroll-bar": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.1.0.tgz", + "integrity": "sha512-5X5Y5YIPjIPrAoMJxf6Pfa7RLNGCgwZ95TdnVPgPuMftRfO8DaC7F4KP1b5eiO8hHbe7u+wZNDbYN5WUTpv7+g==", + "requires": { + "react-style-singleton": "^2.1.0", + "tslib": "^1.0.0" + } + }, "react-responsive": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-8.1.0.tgz", @@ -11716,16 +12056,6 @@ } } }, - "react-toastify": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-6.0.5.tgz", - "integrity": "sha512-1YXSb6Jr478c1TJEyVpxLHFvtmeXGMvdpZc0fke/7lK+MoLBC+NFgB74bq+C2SZe6LdK+K1voEURJoY88WqWvA==", - "requires": { - "classnames": "^2.2.6", - "prop-types": "^15.7.2", - "react-transition-group": "^4.4.1" - } - }, "react-spinners": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/react-spinners/-/react-spinners-0.8.3.tgz", @@ -11734,6 +12064,16 @@ "@emotion/core": "^10.0.15" } }, + "react-style-singleton": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.1.0.tgz", + "integrity": "sha512-DH4ED+YABC1dhvSDYGGreAHmfuTXj6+ezT3CmHoqIEfxNgEYfIMoOtmbRp42JsUst3IPqBTDL+8r4TF7EWhIHw==", + "requires": { + "get-nonce": "^1.0.0", + "invariant": "^2.2.4", + "tslib": "^1.0.0" + } + }, "react-toastify": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-6.0.5.tgz", @@ -11768,6 +12108,19 @@ "prop-types": "^15.6.2" } }, + "react-view-pager": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-view-pager/-/react-view-pager-0.6.0.tgz", + "integrity": "sha512-nV6VTLyHmv4T9QszZVD3sRn3EcUKgb2NhSdz9kjTIpzE+SwOl4mfcQtqUwc6St3EnMtus805zVJ8OcSjFEqhpg==", + "requires": { + "animation-bus": "^0.2.0", + "get-prefix": "^1.0.0", + "mitt": "1.1.3", + "react-motion": "^0.5.0", + "resize-observer-polyfill": "1.5.0", + "tabbable": "1.1.2" + } + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", @@ -11960,15 +12313,6 @@ "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" }, - "remarkable": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-2.0.1.tgz", - "integrity": "sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==", - "requires": { - "argparse": "^1.0.10", - "autolinker": "^3.11.0" - } - }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -12091,6 +12435,11 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" }, + "resize-observer-polyfill": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.0.tgz", + "integrity": "sha512-M2AelyJDVR/oLnToJLtuDJRBBWUGUvvGigj1411hXhAdyFWqMaqHp7TixW3FpiLuVaikIcR1QL+zqoJoZlOgpg==" + }, "resolve": { "version": "1.17.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", @@ -13421,6 +13770,11 @@ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, + "tabbable": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-1.1.2.tgz", + "integrity": "sha512-77oqsKEPrxIwgRcXUwipkj9W5ItO97L6eUT1Ar7vh+El16Zm4M6V+YU1cbipHEa6q0Yjw8O3Hoh8oRgatV5s7A==" + }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -13915,6 +14269,16 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, + "ua-parser-js": { + "version": "0.7.21", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz", + "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==" + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, "uncontrollable": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.1.1.tgz", @@ -14096,6 +14460,20 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, + "use-callback-ref": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.2.4.tgz", + "integrity": "sha512-rXpsyvOnqdScyied4Uglsp14qzag1JIemLeTWGKbwpotWht57hbP78aNT+Q4wdFKQfQibbUX4fb6Qb4y11aVOQ==" + }, + "use-sidecar": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.0.2.tgz", + "integrity": "sha512-287RZny6m5KNMTb/Kq9gmjafi7lQL0YHO1lYolU6+tY1h9+Z3uCtkJJ3OSOq3INwYf2hBryCcDh4520AhJibMA==", + "requires": { + "detect-node": "^2.0.4", + "tslib": "^1.9.3" + } + }, "util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", diff --git a/package.json b/package.json index c8e2626b..92342149 100644 --- a/package.json +++ b/package.json @@ -24,14 +24,15 @@ "react-dom": "^16.12.0", "react-dropzone": "^11.0.1", "react-icons": "^3.9.0", + "react-images": "^1.1.7", "react-lottie": "^1.2.3", "react-markdown-editor-lite": "^1.1.4", "react-redux": "^7.2.0", "react-responsive": "^8.0.3", "react-router-dom": "^5.1.2", "react-scripts": "^3.4.0", - "react-toastify": "^6.0.5", "react-spinners": "^0.8.3", + "react-toastify": "^6.0.5", "redux": "^4.0.5", "redux-thunk": "^2.3.0", "socket.io-client": "^2.3.0" diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js index aff24ec4..ca35cfb2 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js @@ -12,7 +12,7 @@ class DiscussionComments extends Component { }; } - handleComment = () => { + handleComment = (text) => { fetch("http://localhost:5000/proposal/comment", { method: "POST", headers: { @@ -23,9 +23,13 @@ class DiscussionComments extends Component { userId: this.props.userId, proposalId: this.props.proposalId, comment: this.state.commentContent, + isAuthor: this.props.isAuthor, + author: this.props.author, }), }); + this.props.handleComment(this.state.commentContent); + this.setState({ commentContent: "", }); diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js index 37765501..055315ef 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js @@ -1,34 +1,13 @@ import React, { Component } from "react"; import "./DiscussionContent.scss"; -import { Button, Container, Row, Col, Image, ListGroup } from "react-bootstrap"; +import { Button, Badge, Image, ListGroup } from "react-bootstrap"; import DiscussionComments from "./DiscussionComments/DiscussionComments"; import eventImg from "../../../../svgs/event-img-1.svg"; import userIcon2 from "../../../../images/userIcon2.jpg"; import RequestChanges from "../DiscussionPopups/RequestChanges"; -import { withRouter } from "react-router-dom"; -import { Remarkable } from "remarkable"; -import parse from "html-react-parser"; +import { withRouter, Link } from "react-router-dom"; import { Editor } from "@tinymce/tinymce-react"; - -const md = new Remarkable({ - html: true, // Enable HTML tags in source - xhtmlOut: false, // Use '/' to close single tags (
) - breaks: false, // Convert '\n' in paragraphs into
- langPrefix: "language-", // CSS language prefix for fenced blocks - - // Enable some language-neutral replacement + quotes beautification - typographer: false, - - // Double + single quotes replacement pairs, when typographer enabled, - // and smartquotes on. Set doubles to '«»' for Russian, '„“' for German. - quotes: "“”‘’", - - // Highlighter function. Should return escaped HTML, - // or '' if the source string is not changed - highlight: function (/*str, lang*/) { - return ""; - }, -}); +import Carousel, { Modal, ModalGateway } from "react-images"; class DiscussionContent extends Component { constructor(props) { @@ -43,6 +22,11 @@ class DiscussionContent extends Component { markdownString: "", proposalDescription: "", commentList: [], + author: "", + images: [{ source: "../../../../images/userIcon2.jpg" }], + imageModalOpen: false, + proposalState: "", + variant: "danger", }; } @@ -77,13 +61,32 @@ class DiscussionContent extends Component { return res.json(); }) .then((resData) => { - console.log(resData); + const images = []; + resData.proposal.attachments.forEach((item, index) => { + images.push({ source: item.fileLink }); + }); + + let variant; + + switch (resData.proposal.proposalStatus) { + case "DRAFT": + variant = "danger"; + break; + case "SUBMITTED": + variant = "secondary"; + break; + } + this.setState( { proposalTitle: resData.proposal.title, markdownString: resData.proposal.content, proposalDescription: resData.proposal.proposalDescription, commentList: resData.proposal.comments, + author: resData.proposal.creator, + proposalState: resData.proposal.proposalStatus, + variant: variant, + images: images, }, () => { this.processComments(); @@ -120,7 +123,12 @@ class DiscussionContent extends Component { }); }; + toggleModal = () => { + this.setState((state) => ({ imageModalOpen: !state.imageModalOpen })); + }; + handleTextSelction = () => { + console.log("text selection called"); if (window.getSelection().toString().length > 0) { this.setState( { @@ -166,28 +174,44 @@ class DiscussionContent extends Component { }; render() { + const { imageModalOpen, images } = this.state; return (
- {this.state.proposalTitle} + + {this.state.proposalTitle}{" "} +
+ + {this.state.proposalState} + +
+
+
- + + +
- {/*

{parse(md.render(this.state.markdownString))}

*/}
Attached Images
- - - - +
+ {images.map((item, index) => { + return ( +
+ +
+ ); + })} +
+ + + {imageModalOpen ? ( + + + + ) : null} +
@@ -217,6 +279,9 @@ class DiscussionContent extends Component { userId={this.state.userId} token={this.state.token} getData={this.getData} + isAuthor={this.state.author === this.state.userId} + author={this.state.author} + handleComment={this.handleComment} />
{ - console.log("Content was updated:", content); - this.setState({ draftEnabled: true, currentText: content, @@ -327,7 +325,7 @@ class EditorContent extends Component { initialValue="

This is the initial content of the editor

" init={{ height: "100%", - width: "50%", + width: "100%", menubar: false, plugins: [ "advlist autolink lists link image charmap print preview anchor", @@ -382,23 +380,6 @@ class EditorContent extends Component { }} onEditorChange={this.handleTinyEditorChange} /> -
{this.state.startSave ? (
diff --git a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/DashboardRightPanel.js b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/DashboardRightPanel.js index 106355b4..d815fd99 100644 --- a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/DashboardRightPanel.js +++ b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/DashboardRightPanel.js @@ -1,7 +1,7 @@ import React, { Component } from "react"; import "./DashboardRightPanel.scss"; import Comments from "./Comments/Comments"; -import OtherIdeas from "./OtherIdeas/OtherIdeas"; +import Notifications from "./Notifications/Notifications"; class DashboardRightPanel extends Component { constructor(props) { @@ -11,11 +11,8 @@ class DashboardRightPanel extends Component { render() { return (
-
- -
- +
); diff --git a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/DashboardRightPanel.scss b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/DashboardRightPanel.scss index 133ebce0..159796a9 100644 --- a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/DashboardRightPanel.scss +++ b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/DashboardRightPanel.scss @@ -1,12 +1,8 @@ .panel { display: flex; - flex-direction: column; - .panel-comments { - flex-grow: 1; - } .panel-ideas { margin-top: 10px; - flex-grow: 1; + height: 100%; } } diff --git a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js new file mode 100644 index 00000000..7f29d8c5 --- /dev/null +++ b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js @@ -0,0 +1,153 @@ +import React, { Component } from "react"; +import "./OtherIdeas.scss"; +import { ListGroup, Image } from "react-bootstrap"; +import userIcon2 from "../../../../../images/userIcon2.jpg"; +import socket from "../Utils/socket"; +import notifications from "../../../../dashboard/notifications/notifications"; + +class Notifications extends Component { + constructor(props) { + super(props); + this.state = { + socket: socket, + token: + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZWRjYjE4ZjIxNWRhNzRjMThkM2YyNzQiLCJpYXQiOjE1OTE1MjE2Nzl9.q3g5Ah_rtjPIrH7z183fVmUBTv_A4OjEoL673zeG250", + userId: "5edcb18f215da74c18d3f274", + notifications: [], + }; + } + + componentDidMount() { + this.fetchNotifications(); + + this.state.socket.on("new proposal created", (data) => { + data.newNotification = true; + data.createdAt = new Date(); + this.setState({ + notifications: [...this.state.notifications, data], + }); + }); + + this.state.socket.on("proposal deleted", (data) => { + data.newNotification = true; + data.createdAt = new Date(); + this.setState({ + notifications: [...this.state.notifications, data], + }); + }); + } + + fetchNotifications = () => { + fetch("http://localhost:5000/notification/proposal/all", { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: this.state.token, + }, + }) + .then((res) => { + return res.json(); + }) + .then((resData) => { + this.setState( + { + notifications: [ + ...this.state.notifications, + ...resData.notifications, + ], + }, + () => { + this.fetchUserNotifications(); + } + ); + }); + }; + + fetchUserNotifications = () => { + fetch("http://localhost:5000/proposal/notifications", { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: this.state.token, + }, + body: JSON.stringify({ + userId: this.state.userId, + }), + }) + .then((res) => { + return res.json(); + }) + .then((resData) => { + this.setState( + { + notifications: [ + ...this.state.notifications, + ...resData.notifications, + ], + }, + () => { + this.organizaNotifications(); + } + ); + }); + }; + + organizaNotifications = () => { + let notifications = this.state.notifications; + console.log(notifications); + + notifications.sort((a, b) => { + return new Date(b.createdAt) - new Date(a.createdAt); + }); + + this.setState({ + Notifications: notifications, + }); + }; + + render() { + const notifications = this.state.notifications; + return ( +
+
Notifications
+
+ + {notifications.map((notification, index) => { + return ( + +
+
+ icon +
+
+
+ {notification.heading} +
+
+
+ {notification.content} +
+
+
+
+ ); + })} +
+
+
+ ); + } +} + +export default Notifications; diff --git a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.scss b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/OtherIdeas.scss similarity index 95% rename from src/user/proposals/UserProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.scss rename to src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/OtherIdeas.scss index 6058404f..9f1c105c 100644 --- a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.scss +++ b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/OtherIdeas.scss @@ -11,10 +11,10 @@ } .ideas-container { border: solid 1px #dfe9f1; - overflow: auto; + min-height: 90vh; border-radius: 5px; margin: 5px; - max-height: 300px; + .idea-item { display: flex; padding: none; diff --git a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.js b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.js deleted file mode 100644 index a64b31b3..00000000 --- a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.js +++ /dev/null @@ -1,119 +0,0 @@ -import React, { Component } from "react"; -import "./OtherIdeas.scss"; -import { ListGroup, Image } from "react-bootstrap"; -import userIcon2 from "../../../../../images/userIcon2.jpg"; - -class OtherIdeas extends Component { - constructor(props) { - super(props); - this.state = {}; - } - render() { - return ( -
-
Other Ideas
-
- - -
-
- icon -
-
-
We got into GSoC 2020
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna -
-
-
-
- -
-
- icon -
-
-
We got into GSoC 2020
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna -
-
-
-
- -
-
- icon -
-
-
We got into GSoC 2020
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna -
-
-
-
- -
-
- icon -
-
-
We got into GSoC 2020
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna -
-
-
-
- -
-
- icon -
-
-
We got into GSoC 2020
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna -
-
-
-
-
-
-
- ); - } -} - -export default OtherIdeas; diff --git a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/notifications.js b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/notifications.js new file mode 100644 index 00000000..e69de29b diff --git a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/socket.js b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/socket.js new file mode 100644 index 00000000..766eac17 --- /dev/null +++ b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/socket.js @@ -0,0 +1,3 @@ +import io from "socket.io-client"; +const socket = io("http://localhost:8810"); +export default socket; From e38f2791743fe49970ebf7af2d8d45d6ab01cf0a Mon Sep 17 00:00:00 2001 From: Asel Date: Wed, 1 Jul 2020 12:24:19 +0530 Subject: [PATCH 4/7] Issues with redux --- src/actions/proposalActions.js | 41 +++++ src/actions/types.js | 10 +- src/reducers/index.js | 30 ++-- src/reducers/proposalReducer.js | 29 ++++ .../DiscussionComments/DiscussionComments.js | 60 ++++++- .../DiscussionComments.scss | 22 ++- .../DiscussionContent/DiscussionContent.js | 46 +----- .../DiscussionContent/DiscussionContent.scss | 9 +- .../EditorContent/EditorContent.js | 146 +++++++++++------- 9 files changed, 261 insertions(+), 132 deletions(-) create mode 100644 src/actions/proposalActions.js create mode 100644 src/reducers/proposalReducer.js diff --git a/src/actions/proposalActions.js b/src/actions/proposalActions.js new file mode 100644 index 00000000..c39f962e --- /dev/null +++ b/src/actions/proposalActions.js @@ -0,0 +1,41 @@ +import axios from "axios"; +import { errorHandler } from "../utils/errorHandler"; +import { setRequestStatus } from "../utils/setRequestStatus"; +import { CREATE_PROPOSAL, GET_PROPOSAL } from "../actions/types"; + +// CREATE PROPOSAL +export const createProposal = (proposalInfo) => async (dispatch) => { + try { + console.log("proposalInfo", proposalInfo); + const res = await axios.post("/proposal", proposalInfo); + dispatch(setRequestStatus(false)); + if (res.status === 201) { + dispatch(setRequestStatus(true)); + console.log("proposal created in ACTION", res.data); + dispatch({ + type: CREATE_PROPOSAL, + payload: res.data.proposal || res.data.msg, + }); + } + } catch (error) { + dispatch(errorHandler(error)); + } +}; + +// GET PROPOSAL DATA +export const getProposal = (proposalId) => async (dispatch) => { + try { + const res = await axios.get("/proposal/" + proposalId); + dispatch(setRequestStatus(false)); + if (res.status === 200) { + dispatch(setRequestStatus(true)); + console.log("proposal data fetched in action", res.data); + dispatch({ + type: GET_PROPOSAL, + payload: res.data.proposal || res.data.msg, + }); + } + } catch (error) { + dispatch(errorHandler(error)); + } +}; diff --git a/src/actions/types.js b/src/actions/types.js index ca25eeac..4b16547a 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -1,6 +1,6 @@ -export const GET_CURRENT_USER = "GET_CURRENT_USER"; -export const SET_CURRENT_USER = "SET_CURRENT_USER"; -export const RESPONSE_MSG = "RESPONSE_MSG"; +export const GET_CURRENT_USER = "GET_CURRENT_USER"; +export const SET_CURRENT_USER = "SET_CURRENT_USER"; +export const RESPONSE_MSG = "RESPONSE_MSG"; export const GET_ERRORS = "GET_ERRORS"; export const SET_ERROR = "SET_ERROR"; export const SET_STATUS = "SET_STATUS"; @@ -26,4 +26,6 @@ export const GET_USER_PROJECTS = "GET_USER_PROJECTS"; export const GET_ALL_EVENTS = "GET_ALL_EVENTS"; export const GET_ALL_PROJECTS = "GET_ALL_PROJECTS"; export const GET_ALL_POSTS = "GET_ALL_POSTS"; -export const GET_USER_POSTS = "GET_USER_POSTS"; \ No newline at end of file +export const GET_USER_POSTS = "GET_USER_POSTS"; +export const CREATE_PROPOSAL = "CREATE_PROPOSAL"; +export const GET_PROPOSAL = "GET_PROPOSAL"; diff --git a/src/reducers/index.js b/src/reducers/index.js index 360c5d2b..826f2205 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -1,15 +1,16 @@ -import { combineReducers } from 'redux'; -import authReducers from './authReducer'; -import postReducers from './postReducer'; -import userReducers from './userReducer'; -import errorReducer from './errorReducer'; -import requestStatus from './requestStatus'; -import notificationReducer from './notificationReducer' -import dashboardReducer from './dashboardReducer' -import insightReducer from './insightReducer'; -import orgReducer from './orgReducer'; -import eventReducer from './eventReducer'; -import projectReducer from './projectReducer'; +import { combineReducers } from "redux"; +import authReducers from "./authReducer"; +import postReducers from "./postReducer"; +import userReducers from "./userReducer"; +import errorReducer from "./errorReducer"; +import requestStatus from "./requestStatus"; +import notificationReducer from "./notificationReducer"; +import dashboardReducer from "./dashboardReducer"; +import insightReducer from "./insightReducer"; +import orgReducer from "./orgReducer"; +import eventReducer from "./eventReducer"; +import projectReducer from "./projectReducer"; +import proposalReducer from "./proposalReducer"; const rootReducer = combineReducers({ auth: authReducers, @@ -22,7 +23,8 @@ const rootReducer = combineReducers({ org: orgReducer, event: eventReducer, project: projectReducer, - status: requestStatus + status: requestStatus, + proposal: proposalReducer, }); -export default rootReducer; \ No newline at end of file +export default rootReducer; diff --git a/src/reducers/proposalReducer.js b/src/reducers/proposalReducer.js new file mode 100644 index 00000000..a3945561 --- /dev/null +++ b/src/reducers/proposalReducer.js @@ -0,0 +1,29 @@ +import { CREATE_PROPOSAL, GET_PROPOSAL } from "../actions/types"; + +const initialState = { + createdProposal: {}, + fetchedProposal: {}, + proposalIsFetched: false, +}; + +export default (state = initialState, action) => { + switch (action.type) { + case CREATE_PROPOSAL: { + console.log("in reducer CREATE_PROPOSAL switch case"); + return { + ...state, + createdProposal: action.payload, + }; + } + case GET_PROPOSAL: { + console.log("in reducer"); + return { + ...state, + fetchedProposal: action.payload, + }; + } + default: { + return state; + } + } +}; diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js index ca35cfb2..54be6cc8 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js @@ -2,6 +2,7 @@ import React, { Component } from "react"; import userIcon2 from "../../../../../images/userIcon2.jpg"; import { Form, ListGroup, Button } from "react-bootstrap"; import "./DiscussionComments.scss"; +import Carousel, { Modal, ModalGateway } from "react-images"; class DiscussionComments extends Component { constructor(props) { @@ -9,6 +10,7 @@ class DiscussionComments extends Component { this.state = { commentContent: "", commentItems: this.props.commentItems, + imageModalOpen: false, }; } @@ -41,13 +43,17 @@ class DiscussionComments extends Component { }); }; + toggleModal = () => { + this.setState((state) => ({ imageModalOpen: !state.imageModalOpen })); + }; + render() { const comments = this.props.commentItems; return (
Comments
-
+
{comments}
@@ -56,7 +62,7 @@ class DiscussionComments extends Component { style={{ display: "inline-block", marginRight: "10px", - width: "80%", + width: "70%", }} >
+
+
Attached Images
+
+ {this.props.images.map((item, index) => { + return ( +
+ +
+ ); + })} +
+ + + {this.state.imageModalOpen ? ( + + + + ) : null} + +
); } diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.scss b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.scss index 881d97d1..396e9af1 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.scss +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.scss @@ -1,13 +1,16 @@ .commentbox { + display: flex; + flex-direction: column; + .comments { + flex: 2; .comment-title { - margin-top: 10px; font-family: Inter; font-style: normal; font-weight: 600; font-size: 22px; line-height: 27px; - + margin-top: 0px; color: #000000; } .comments-containers { @@ -15,7 +18,7 @@ overflow: auto; border-radius: 5px; margin: 5px 5px -1px 5px; - max-height: 73vh; + height: 300px; .comment-item { display: flex; @@ -81,4 +84,17 @@ } } } + .images { + flex: 1; + + .images-title { + font-family: Inter; + font-style: normal; + font-weight: 600; + font-size: 22px; + line-height: 27px; + margin-top: 0px; + color: #000000; + } + } } diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js index 055315ef..bffed11b 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js @@ -226,51 +226,6 @@ class DiscussionContent extends Component { onEditorChange={this.handleTinyEditorChange} />
-
-
Attached Images
-
- {images.map((item, index) => { - return ( -
- -
- ); - })} -
- - - {imageModalOpen ? ( - - - - ) : null} - -
{ - this.getData(); + setTimeout(() => { + this.props.getProposal(this.props.location.state.proposalId); + }); } ); } @@ -69,27 +80,29 @@ class EditorContent extends Component { //Obtain proposal data from the server getData = () => { - fetch("http://localhost:5000/proposal/" + this.state.proposalId, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, - }, - }) - .then((res) => { - return res.json(); - }) - .then((resData) => { - console.log(resData); - this.setState({ - proposalTitle: resData.proposal.title, - markdownString: resData.proposal.content, - proposalDescription: resData.proposal.proposalDescription, - lastText: resData.proposal.content, - currentText: resData.proposal.content, - startSave: true, - }); - }); + this.props.getProposal(this.props.location.state.proposalId); + + // fetch("http://localhost:5000/proposal/" + this.state.proposalId, { + // method: "GET", + // headers: { + // "Content-Type": "application/json", + // Authorization: this.state.token, + // }, + // }) + // .then((res) => { + // return res.json(); + // }) + // .then((resData) => { + // console.log(resData); + // this.setState({ + // proposalTitle: resData.proposal.title, + // markdownString: resData.proposal.content, + // proposalDescription: resData.proposal.proposalDescription, + // lastText: resData.proposal.content, + // currentText: resData.proposal.content, + // startSave: true, + // }); + // }); }; //Update the content of the proposal @@ -128,40 +141,49 @@ class EditorContent extends Component { createProposal = () => { this.setState({ isSaving: true }); setTimeout(() => { - fetch("http://localhost:5000/proposal", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, - }, - body: JSON.stringify({ - title: this.state.proposalTitle, - content: this.state.currentText, - proposalStatus: "DRAFT", - creator: this.state.userId, - }), - }) - .then((res) => { - return res.json(); - }) - .then((resData) => { - this.setState( - { - newProposal: false, - proposalId: resData.proposal._id, - isSaving: false, - lastSaved: new Date().toTimeString().substring(0, 8), - }, - () => { - toast.success("Proposal Drafted Successfully!"); - let idVar = setInterval(this.saveProposal, 20000); - this.setState({ - idVar: idVar, - startSave: true, - }); - } - ); - }); + let proposalInfo = { + title: this.state.proposalTitle, + content: this.state.currentText, + proposalStatus: "DRAFT", + creator: localStorage.getItem("userId"), + }; + + this.props.createProposal(proposalInfo); + + // fetch("http://localhost:5000/proposal", { + // method: "POST", + // headers: { + // "Content-Type": "application/json", + // Authorization: this.state.token, + // }, + // body: JSON.stringify({ + // title: this.state.proposalTitle, + // content: this.state.currentText, + // proposalStatus: "DRAFT", + // creator: this.state.userId, + // }), + // }) + // .then((res) => { + // return res.json(); + // }) + // .then((resData) => { + // this.setState( + // { + // newProposal: false, + // proposalId: resData.proposal._id, + // isSaving: false, + // lastSaved: new Date().toTimeString().substring(0, 8), + // }, + // () => { + // toast.success("Proposal Drafted Successfully!"); + // let idVar = setInterval(this.saveProposal, 20000); + // this.setState({ + // idVar: idVar, + // startSave: true, + // }); + // } + // ); + // }); }, 2000); }; @@ -253,7 +275,7 @@ class EditorContent extends Component { name="proposalTitle" className="searchbar" onChange={this.handleChange} - value={this.state.proposalTitle} + value={this.props.proposalTitle} /> Short Description ({ + createdProposal: state.createdProposal, + fetchedProposal: state.fetchedProposal, + proposalIsFetched: state.proposalIsFetched, +}); + +export default connect(mapStateToProps, { createProposal, getProposal })( + withRouter(EditorContent) +); From 03d3f4f6d1b6cbff39d33f0321723060c04b79c6 Mon Sep 17 00:00:00 2001 From: Asel Date: Thu, 2 Jul 2020 20:12:32 +0530 Subject: [PATCH 5/7] integrating redux for state management and other requested changes --- .vscode/launch.json | 15 + src/actions/notificationAction.js | 62 ++-- src/actions/proposalActions.js | 122 +++++++- src/actions/types.js | 7 +- src/reducers/notificationReducer.js | 34 ++- src/reducers/proposalReducer.js | 39 ++- src/router.js | 11 - .../AdminProposalDashboard.js | 32 -- .../AdminProposalDashboard.scss | 16 - .../DashboardContent/DashboardContent.js | 277 ------------------ .../DashboardContent/DashboardContent.scss | 184 ------------ .../DashboardRightPanel/Comments/Comments.js | 72 ----- .../Comments/Comments.scss | 69 ----- .../DashboardRightPanel.js | 25 -- .../DashboardRightPanel.scss | 12 - .../OtherIdeas/OtherIdeas.js | 119 -------- .../OtherIdeas/OtherIdeas.scss | 52 ---- .../DiscussionComments/DiscussionComments.js | 70 ++--- .../DiscussionComments.scss | 33 +++ .../DiscussionContent/DiscussionContent.js | 89 +++--- .../ProposalEditor/EditorContent/DropZone.js | 3 +- .../EditorContent/EditorContent.js | 243 ++++++--------- .../DashboardContent/DashboardContent.js | 93 +++--- .../Notifications/Notifications.js | 115 ++++---- 24 files changed, 528 insertions(+), 1266 deletions(-) create mode 100644 .vscode/launch.json delete mode 100644 src/user/proposals/AdminProposalDashboard/AdminProposalDashboard.js delete mode 100644 src/user/proposals/AdminProposalDashboard/AdminProposalDashboard.scss delete mode 100644 src/user/proposals/AdminProposalDashboard/DashboardContent/DashboardContent.js delete mode 100644 src/user/proposals/AdminProposalDashboard/DashboardContent/DashboardContent.scss delete mode 100644 src/user/proposals/AdminProposalDashboard/DashboardRightPanel/Comments/Comments.js delete mode 100644 src/user/proposals/AdminProposalDashboard/DashboardRightPanel/Comments/Comments.scss delete mode 100644 src/user/proposals/AdminProposalDashboard/DashboardRightPanel/DashboardRightPanel.js delete mode 100644 src/user/proposals/AdminProposalDashboard/DashboardRightPanel/DashboardRightPanel.scss delete mode 100644 src/user/proposals/AdminProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.js delete mode 100644 src/user/proposals/AdminProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.scss diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..7a9dfa04 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "pwa-chrome", + "request": "launch", + "name": "Launch Chrome against localhost", + "url": "http://localhost:8080", + "webRoot": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/src/actions/notificationAction.js b/src/actions/notificationAction.js index 7059e299..f2a7c2a2 100644 --- a/src/actions/notificationAction.js +++ b/src/actions/notificationAction.js @@ -1,41 +1,63 @@ -import { GET_PLATFORM_NOTIFICATIONS, GET_USER_NOTIFICATIONS } from './types' -import axios from 'axios' -import { errorHandler } from '../utils/errorHandler'; -import { setRequestStatus } from '../utils/setRequestStatus'; +import { + GET_PLATFORM_NOTIFICATIONS, + GET_USER_NOTIFICATIONS, + GET_PROPOSAL_NOTIFICATIONS, +} from "./types"; +import axios from "axios"; +import { errorHandler } from "../utils/errorHandler"; +import { setRequestStatus } from "../utils/setRequestStatus"; // GET NOTIFICATIONS FOR WHOLE PLATFORM AS WELL AS FOR A USER export const getAllNotifications = () => async (dispatch) => { try { - const res = await axios.get('/notification/org/all') - dispatch(setRequestStatus(false)) + const res = await axios.get("/notification/org/all"); + dispatch(setRequestStatus(false)); if (res.status === 200) { - dispatch(setRequestStatus(true)) - console.log('Whole platform notification ', res.data.notifications) + dispatch(setRequestStatus(true)); + console.log("Whole platform notification ", res.data.notifications); dispatch({ type: GET_PLATFORM_NOTIFICATIONS, - payload: res.data.notifications - }) + payload: res.data.notifications, + }); } } catch (error) { - dispatch(errorHandler(error)) + dispatch(errorHandler(error)); } -} +}; // GET NOTIFICATIONS FOR A USER export const getUserNotification = () => async (dispatch) => { try { - const res = await axios.get('/notification/user/all') - dispatch(setRequestStatus(false)) + const res = await axios.get("/notification/user/all"); + dispatch(setRequestStatus(false)); if (res.status === 200) { - dispatch(setRequestStatus(true)) - console.log('User notification ', res.data.notifications) + dispatch(setRequestStatus(true)); + console.log("User notification ", res.data.notifications); dispatch({ type: GET_USER_NOTIFICATIONS, - payload: res.data.notifications - }) + payload: res.data.notifications, + }); } } catch (error) { - dispatch(errorHandler(error)) + dispatch(errorHandler(error)); } -} +}; + +// GET PROPOSAL NOTIFICATIONS +export const getProposalNotifications = () => async (dispatch) => { + try { + const res = await axios.get("/notification/proposal/all"); + dispatch(setRequestStatus(false)); + if (res.status === 200) { + dispatch(setRequestStatus(true)); + console.log("Proposal notification ", res.data.notifications); + dispatch({ + type: GET_PROPOSAL_NOTIFICATIONS, + payload: res.data.notifications, + }); + } + } catch (error) { + dispatch(errorHandler(error)); + } +}; diff --git a/src/actions/proposalActions.js b/src/actions/proposalActions.js index c39f962e..fb783acc 100644 --- a/src/actions/proposalActions.js +++ b/src/actions/proposalActions.js @@ -1,12 +1,17 @@ import axios from "axios"; import { errorHandler } from "../utils/errorHandler"; import { setRequestStatus } from "../utils/setRequestStatus"; -import { CREATE_PROPOSAL, GET_PROPOSAL } from "../actions/types"; +import { + CREATE_PROPOSAL, + GET_PROPOSAL, + GET_USER_PROPOSAL_NOTIFICATIONS, + GET_ALL_PROPOSALS, + GET_USER_PROPOSALS, +} from "../actions/types"; // CREATE PROPOSAL export const createProposal = (proposalInfo) => async (dispatch) => { try { - console.log("proposalInfo", proposalInfo); const res = await axios.post("/proposal", proposalInfo); dispatch(setRequestStatus(false)); if (res.status === 201) { @@ -39,3 +44,116 @@ export const getProposal = (proposalId) => async (dispatch) => { dispatch(errorHandler(error)); } }; + +// SAVE PROPOSAL DATA +export const saveProposal = (proposalData) => async (dispatch) => { + try { + const res = await axios.patch( + "/proposal/" + proposalData.proposalId, + proposalData + ); + dispatch(setRequestStatus(false)); + if (res.status === 200) { + dispatch(setRequestStatus(true)); + } + } catch (error) { + dispatch(errorHandler(error)); + } +}; + +// SUBMIT PROPOSAL +export const submitProposal = (proposalData) => async (dispatch) => { + console.log(proposalData); + try { + const res = await axios.patch( + "/proposal/change/" + proposalData.proposalId, + proposalData + ); + dispatch(setRequestStatus(false)); + if (res.status === 200) { + dispatch(setRequestStatus(true)); + } + } catch (error) { + dispatch(errorHandler(error)); + } +}; + +// DELETE PROPOSAL +export const deleteProposal = (proposalId) => async (dispatch) => { + try { + const res = await axios.delete("/proposal", { + headers: {}, + data: { proposalId: proposalId }, + }); + dispatch(setRequestStatus(false)); + if (res.status === 200) { + dispatch(setRequestStatus(true)); + } + } catch (error) { + dispatch(errorHandler(error)); + } +}; + +// COMMENT ON PROPOSAL +export const commentProposal = (commentData) => async (dispatch) => { + try { + const res = await axios.post("/proposal/comment", commentData); + dispatch(setRequestStatus(false)); + if (res.status === 200) { + dispatch(setRequestStatus(true)); + } + } catch (error) { + dispatch(errorHandler(error)); + } +}; + +// GET USER RELATED PROPOSAL NOTIFICATIONS +export const getUserProposalNotifications = (data) => async (dispatch) => { + try { + const res = await axios.post("/proposal/notifications", data); + console.log(res); + if (res.status === 200) { + dispatch(setRequestStatus(true)); + dispatch({ + type: GET_USER_PROPOSAL_NOTIFICATIONS, + payload: res.data.proposal || res.data.msg, + }); + } + } catch (error) { + dispatch(errorHandler(error)); + } +}; + +// GET ALL PROPOSALS +export const getAllProposals = () => async (dispatch) => { + try { + const res = await axios.post("/proposal/all"); + dispatch(setRequestStatus(false)); + if (res.status === 200) { + dispatch(setRequestStatus(true)); + dispatch({ + type: GET_ALL_PROPOSALS, + payload: res.data.proposals || res.data.msg, + }); + } + } catch (error) { + dispatch(errorHandler(error)); + } +}; + +// GET PROPOSALS BY USER ID +export const getProposalsByUser = (userId) => async (dispatch) => { + try { + const res = await axios.get(`/proposal/user/${userId}`); + dispatch(setRequestStatus(false)); + if (res.status === 200) { + dispatch(setRequestStatus(true)); + dispatch({ + type: GET_USER_PROPOSALS, + payload: res.data.proposal || res.data.msg, + }); + } + } catch (error) { + dispatch(errorHandler(error)); + } +}; diff --git a/src/actions/types.js b/src/actions/types.js index 4b16547a..0ce698b2 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -6,7 +6,9 @@ export const SET_ERROR = "SET_ERROR"; export const SET_STATUS = "SET_STATUS"; export const GET_PLATFORM_NOTIFICATIONS = "GET_PLATFORM_NOTIFICATIONS"; export const GET_USER_NOTIFICATIONS = "GET_USER_NOTIFICATIONS"; -export const GET_ALL_NOTIFICATIONS = "GET_ALL_NOTIFICATIONS"; +export const GET_PROPOSAL_NOTIFICATIONS = "GET_PROPOSAL_NOTIFICATIONS"; +export const GET_USER_PROPOSAL_NOTIFICATIONS = + "GET_USER_PROPOSAL_NOTIFICATIONS"; export const SET_ADMIN = "SET_ADMIN"; export const GET_ALL_UPCOMING_EVENTS = "GET_ALL_UPCOMING_EVENTS"; export const GET_ALL_MEMBERS = "GET_ALL_MEMBERS"; @@ -29,3 +31,6 @@ export const GET_ALL_POSTS = "GET_ALL_POSTS"; export const GET_USER_POSTS = "GET_USER_POSTS"; export const CREATE_PROPOSAL = "CREATE_PROPOSAL"; export const GET_PROPOSAL = "GET_PROPOSAL"; +export const GET_ALL_PROPOSALS = "GET_ALL_PROPOSALS"; +export const EXIT = "EXIT"; +export const GET_USER_PROPOSALS = "GET USER PROPOSALS"; diff --git a/src/reducers/notificationReducer.js b/src/reducers/notificationReducer.js index e6a2f32b..5942c936 100644 --- a/src/reducers/notificationReducer.js +++ b/src/reducers/notificationReducer.js @@ -1,26 +1,40 @@ -import { GET_PLATFORM_NOTIFICATIONS, GET_USER_NOTIFICATIONS } from "../actions/types" +import { + GET_PLATFORM_NOTIFICATIONS, + GET_USER_NOTIFICATIONS, + GET_PROPOSAL_NOTIFICATIONS, +} from "../actions/types"; const initialState = { platformNotifications: [], - userNotifications: [] -} + userNotifications: [], + proposalNotifications: [], +}; export default (state = initialState, action) => { - switch(action.type) { + switch (action.type) { case GET_PLATFORM_NOTIFICATIONS: { return { ...state, - platformNotifications: [action.payload, ...state.platformNotifications][0] - } + platformNotifications: [ + action.payload, + ...state.platformNotifications, + ][0], + }; } case GET_USER_NOTIFICATIONS: { return { ...state, - userNotifications: [action.payload, ...state.userNotifications][0] - } + userNotifications: [action.payload, ...state.userNotifications][0], + }; + } + case GET_PROPOSAL_NOTIFICATIONS: { + return { + ...state, + proposalNotifications: [action.payload, ...state.userNotifications][0], + }; } default: { - return state + return state; } } -} \ No newline at end of file +}; diff --git a/src/reducers/proposalReducer.js b/src/reducers/proposalReducer.js index a3945561..1f673384 100644 --- a/src/reducers/proposalReducer.js +++ b/src/reducers/proposalReducer.js @@ -1,27 +1,60 @@ -import { CREATE_PROPOSAL, GET_PROPOSAL } from "../actions/types"; +import { + CREATE_PROPOSAL, + GET_PROPOSAL, + EXIT, + GET_USER_PROPOSAL_NOTIFICATIONS, + GET_ALL_PROPOSALS, + GET_USER_PROPOSALS, +} from "../actions/types"; const initialState = { createdProposal: {}, fetchedProposal: {}, proposalIsFetched: false, + userNotifications: [], + allProposals: [], + userProposals: [], }; export default (state = initialState, action) => { switch (action.type) { case CREATE_PROPOSAL: { - console.log("in reducer CREATE_PROPOSAL switch case"); return { ...state, createdProposal: action.payload, }; } case GET_PROPOSAL: { - console.log("in reducer"); return { ...state, fetchedProposal: action.payload, }; } + case GET_USER_PROPOSAL_NOTIFICATIONS: { + return { + ...state, + userNotification: action.payload, + }; + } + case GET_ALL_PROPOSALS: { + return { + ...state, + allProposals: action.payload, + }; + } + case GET_USER_PROPOSALS: { + return { + ...state, + userProposals: action.payload, + }; + } + case EXIT: { + return { + ...state, + createdProposal: {}, + fetchedProposal: {}, + }; + } default: { return state; } diff --git a/src/router.js b/src/router.js index d392c02c..a4d5b1cb 100644 --- a/src/router.js +++ b/src/router.js @@ -13,7 +13,6 @@ import PrivateRoute from "./common/PrivateRoute"; import Maintenance from "./maintenance/maintenance"; import Events from "./user/events/events"; import UserProposalDashboard from "./user/proposals/UserProposalDashboard/UserProposalDashboard"; -import AdminProposalDashboard from "./user/proposals/AdminProposalDashboard/AdminProposalDashboard"; import ProposalDiscussion from "./user/proposals/ProposalDiscussion/ProposalDiscussion"; import ProposalEditor from "./user/proposals/ProposalEditor/ProposalEditor"; import Admin from "./user/Admin/Admin"; @@ -36,21 +35,11 @@ const Router = () => ( - - diff --git a/src/user/proposals/AdminProposalDashboard/AdminProposalDashboard.js b/src/user/proposals/AdminProposalDashboard/AdminProposalDashboard.js deleted file mode 100644 index 9b1f0f51..00000000 --- a/src/user/proposals/AdminProposalDashboard/AdminProposalDashboard.js +++ /dev/null @@ -1,32 +0,0 @@ -import React, { Component } from "react"; -import "./AdminProposalDashboard.scss"; -import Navigation from "../../dashboard/navigation/navigation"; -import DashboardContent from "./DashboardContent/DashboardContent"; -import DashboardRightPanel from "./DashboardRightPanel/DashboardRightPanel"; - -class UserProposalDashboard extends Component { - constructor(props) { - super(props); - this.state = { - dashboard: true, - isLoading: true, - }; - } - render() { - return ( -
-
- -
-
- -
-
- -
-
- ); - } -} - -export default UserProposalDashboard; diff --git a/src/user/proposals/AdminProposalDashboard/AdminProposalDashboard.scss b/src/user/proposals/AdminProposalDashboard/AdminProposalDashboard.scss deleted file mode 100644 index 86e9c195..00000000 --- a/src/user/proposals/AdminProposalDashboard/AdminProposalDashboard.scss +++ /dev/null @@ -1,16 +0,0 @@ -.dashboard { - display: flex; - min-height: 100vh; - height: auto; - font-family: Muli, sans-serif; - .dashboard__navigation { - flex: 1; - border-right: solid 1px #dfe9f1; - } - .dashboard__content { - flex: 4; - } - .dashboard__rightpanel { - flex: 1.5; - } -} diff --git a/src/user/proposals/AdminProposalDashboard/DashboardContent/DashboardContent.js b/src/user/proposals/AdminProposalDashboard/DashboardContent/DashboardContent.js deleted file mode 100644 index 95446d27..00000000 --- a/src/user/proposals/AdminProposalDashboard/DashboardContent/DashboardContent.js +++ /dev/null @@ -1,277 +0,0 @@ -import React, { Component } from "react"; -import { Button, Form, Col, Image } from "react-bootstrap"; -import "./DashboardContent.scss"; -import userIcon2 from "../../../../images/userIcon2.jpg"; -import { Link } from "react-router-dom"; - -class DashboardContent extends Component { - constructor(props) { - super(props); - this.state = { - token: - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZWVlZWY5OTdhZTUyZDJlN2NjNmFhZjEiLCJpYXQiOjE1OTI3MTcyMTB9.ZmIn4pIuwWygI_YJrBo8CIhpIhmwZmAE5wsoDhVcpE8", - userId: "5eeeef997ae52d2e7cc6aaf1", - proposals: [], - displayItems: [], - }; - } - - componentDidMount() { - this.getProposalsByUserId(); - this.getAllProposals(); - } - - getAllProposals() { - fetch(`http://localhost:5000/proposal/all`, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, - }, - body: JSON.stringify({ - userId: this.state.userId, - }), - }) - .then((res) => { - return res.json(); - }) - .then((resData) => { - console.log(resData); - this.setState({ - proposals: resData.proposals, - displayItems: resData.proposals, - }); - }); - } - - getProposalsByUserId() { - fetch(`http://localhost:5000/proposal/user/${this.state.userId}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, - }, - }) - .then((res) => { - return res.json(); - }) - .then((resData) => { - console.log(resData); - this.setState({ - proposals: resData.proposal, - displayItems: resData.proposal, - }); - }); - } - - handleSearchBarChange = (evt) => { - const value = evt.target.value.toLowerCase(); - const proposals = this.state.proposals; - let results = []; - - if (value.length === 0) { - this.setState({ - displayItems: proposals, - }); - } else { - proposals.forEach((item) => { - if (item.title.toLowerCase().includes(value)) { - results.push(item); - } - }); - - this.setState({ - displayItems: results, - }); - } - }; - - handleButtonClick = (name) => { - const proposals = this.state.proposals; - let results = []; - - switch (name) { - case "All": - this.setState({ - displayItems: proposals, - }); - break; - case "Accepted": - proposals.forEach((item) => { - if (item.proposalStatus === "ACCEPTED") { - results.push(item); - } - }); - this.setState({ - displayItems: results, - }); - break; - case "Submitted": - proposals.forEach((item) => { - if (item.proposalStatus === "SUBMITTED") { - results.push(item); - } - }); - this.setState({ - displayItems: results, - }); - break; - case "Draft": - proposals.forEach((item) => { - if (item.proposalStatus === "DRAFT") { - results.push(item); - } - }); - this.setState({ - displayItems: results, - }); - break; - case "Rejected": - proposals.forEach((item) => { - if (item.proposalStatus === "REJECTED") { - results.push(item); - } - }); - this.setState({ - displayItems: results, - }); - break; - } - }; - - render() { - return ( -
-
-
- - -
- Proposals -
-
-
-
- - - - - - - - -
-
-
-
- -
-
- {this.state.displayItems.map((proposalItem, index) => { - return ( -
-
-
- icon -
-
-

{proposalItem.title}

-

{proposalItem.createdAt}

-
- {proposalItem.proposalStatus === "DRAFT" ? ( - - ) : ( - - )} -
-
-
- {proposalItem.proposalDescription} -
-
- - - -
-
-
- ); - })} -
-
-
- ); - } -} - -export default DashboardContent; diff --git a/src/user/proposals/AdminProposalDashboard/DashboardContent/DashboardContent.scss b/src/user/proposals/AdminProposalDashboard/DashboardContent/DashboardContent.scss deleted file mode 100644 index adc0732c..00000000 --- a/src/user/proposals/AdminProposalDashboard/DashboardContent/DashboardContent.scss +++ /dev/null @@ -1,184 +0,0 @@ -.dashboard-content { - padding: 30px; - display: flex; - height: 100vh; - flex-direction: column; - - .searchbar-container { - flex-grow: 0.5; - .searchbar { - border-radius: 25px; - } - .dashboard-title { - margin-top: 15px; - .title-text { - font-family: Inter; - font-style: normal; - font-weight: 600; - font-size: 36px; - line-height: 44px; - color: #000000; - } - } - .button-container { - .posts { - .category { - text-align: left; - margin-left: 0px; - margin-top: 20px; - .category-btn { - background-color: white; - font-family: Inter; - font-style: normal; - font-weight: 500; - font-size: 18px; - line-height: 22px; - - &:hover { - background-color: #1a73e8; - color: white; - } - - &:focus { - background-color: #1a73e8; - color: white; - } - } - } - } - } - } - .proposal-container { - margin-top: 20px; - flex-grow: 5; - .proposals { - .single-proposal { - display: inline-block; - counter-increment: item-counter; - width: 100%; - margin-bottom: 15px; - border: solid 1px #dfe9f1; - box-shadow: 1px 2px 5px rgba(0, 0, 0, 0.1); - border-radius: 5px; - .user-info { - display: flex; - padding: 8px; - .image { - width: 38px; - height: 38px; - img { - width: 100%; - height: 100%; - border-radius: 2px; - } - } - .img-desc { - margin-left: 10px; - h2 { - font-family: Inter; - font-style: normal; - font-weight: 600; - font-size: 18px; - line-height: 22px; - margin: 3px; - /* identical to box height */ - } - small { - font-family: Inter; - font-style: normal; - font-weight: normal; - font-size: 12px; - line-height: 15px; - color: #90949c; - margin: 0; - } - .proposal-date { - font-family: Inter; - font-style: normal; - font-weight: normal; - font-size: 12px; - line-height: 15px; - - color: #90949c; - } - } - .status-btn-draft { - background-color: white; - padding: 4px 36px; - border: solid 1px #eb5757; - border-radius: 100px; - color: #eb5757; - margin: 0 5px; - height: 30px; - cursor: default; - } - .status-btn-submitted { - background-color: white; - padding: 4px 36px; - border: solid 1px #90949c; - border-radius: 100px; - color: #90949c; - margin: 0 5px; - height: 30px; - cursor: default; - } - .status-btn-accepted { - background-color: white; - padding: 4px 36px; - border: solid 1px #27ae60; - border-radius: 100px; - color: #27ae60; - margin: 0 5px; - height: 30px; - cursor: default; - } - .dropdown-container { - margin-left: auto; - margin-right: 5px; - } - } - .proposal-content { - display: flex; - .proposal-details { - flex: 3; - font-family: Inter; - font-style: normal; - font-weight: normal; - font-size: 14px; - line-height: 17px; - padding: 10px; - - color: #1d2129; - } - .proposal-options { - flex: 1.5; - text-align: center; - padding: 20px; - .option-btn { - background-color: white; - color: #007bff; - padding: 4px 40px; - border: solid 1px #1a73e8; - border-radius: 100px; - margin: 0 10px; - height: 30px; - cursor: pointer; - &.active { - background: #007bff; - color: white; - } - .option-text { - font-family: Inter; - font-style: normal; - font-weight: 500; - font-size: 14px; - line-height: 22px; - /* identical to box height */ - } - } - } - } - } - } - } -} diff --git a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/Comments/Comments.js b/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/Comments/Comments.js deleted file mode 100644 index 3430f1aa..00000000 --- a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/Comments/Comments.js +++ /dev/null @@ -1,72 +0,0 @@ -import React, { Component } from "react"; -import "./Comments.scss"; -import { ListGroup, Image } from "react-bootstrap"; -import userIcon2 from "../../../../../images/userIcon2.jpg"; - -class Comments extends Component { - constructor(props) { - super(props); - this.state = {}; - } - render() { - return ( -
-
Comments
-
- - -
-
- icon -
-
-
Devesh
-
- "Lorem ipsum dolor sit amet" -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna - aliqua. Ut enim ad minim veniam, quis nostrud exercitation -
-
-
-
-
- - -
-
- icon -
-
-
Devesh
-
- "Lorem ipsum dolor sit amet" -
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna - aliqua. Ut enim ad minim veniam, quis nostrud exercitation -
-
-
-
-
-
-
- ); - } -} - -export default Comments; diff --git a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/Comments/Comments.scss b/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/Comments/Comments.scss deleted file mode 100644 index 88c79fca..00000000 --- a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/Comments/Comments.scss +++ /dev/null @@ -1,69 +0,0 @@ -.comments { - .comment-title { - margin-top: 10px; - font-family: Inter; - font-style: normal; - font-weight: 600; - font-size: 22px; - line-height: 27px; - - color: #000000; - } - .comments-container { - border: solid 1px #dfe9f1; - overflow: auto; - border-radius: 5px; - margin: 5px; - max-height: 300px; - .comment-item { - display: flex; - padding: none; - .image-container { - flex: 1; - .user-image { - width: 30px; - height: 30px; - } - } - .comment-container { - flex: 6; - border: solid 1px #dfe9f1; - overflow: auto; - border-radius: 5px; - padding: 3px; - .commenting-user { - font-family: Inter; - font-style: normal; - font-weight: 600; - font-size: 14px; - line-height: 150%; - /* or 21px */ - - color: #000000; - } - .commented-section { - margin-top: 2px; - font-family: Inter; - font-style: normal; - font-weight: normal; - font-size: 14px; - line-height: 150%; - /* or 21px */ - - color: rgba(29, 33, 41, 0.5); - } - .comment-text { - margin-top: 2px; - font-family: Inter; - font-style: normal; - font-weight: normal; - font-size: 14px; - - /* or 21px */ - - color: rgba(21, 21, 21, 0.91); - } - } - } - } -} diff --git a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/DashboardRightPanel.js b/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/DashboardRightPanel.js deleted file mode 100644 index 106355b4..00000000 --- a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/DashboardRightPanel.js +++ /dev/null @@ -1,25 +0,0 @@ -import React, { Component } from "react"; -import "./DashboardRightPanel.scss"; -import Comments from "./Comments/Comments"; -import OtherIdeas from "./OtherIdeas/OtherIdeas"; - -class DashboardRightPanel extends Component { - constructor(props) { - super(props); - this.state = {}; - } - render() { - return ( -
-
- -
-
- -
-
- ); - } -} - -export default DashboardRightPanel; diff --git a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/DashboardRightPanel.scss b/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/DashboardRightPanel.scss deleted file mode 100644 index 133ebce0..00000000 --- a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/DashboardRightPanel.scss +++ /dev/null @@ -1,12 +0,0 @@ -.panel { - display: flex; - flex-direction: column; - - .panel-comments { - flex-grow: 1; - } - .panel-ideas { - margin-top: 10px; - flex-grow: 1; - } -} diff --git a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.js b/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.js deleted file mode 100644 index a64b31b3..00000000 --- a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.js +++ /dev/null @@ -1,119 +0,0 @@ -import React, { Component } from "react"; -import "./OtherIdeas.scss"; -import { ListGroup, Image } from "react-bootstrap"; -import userIcon2 from "../../../../../images/userIcon2.jpg"; - -class OtherIdeas extends Component { - constructor(props) { - super(props); - this.state = {}; - } - render() { - return ( -
-
Other Ideas
-
- - -
-
- icon -
-
-
We got into GSoC 2020
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna -
-
-
-
- -
-
- icon -
-
-
We got into GSoC 2020
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna -
-
-
-
- -
-
- icon -
-
-
We got into GSoC 2020
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna -
-
-
-
- -
-
- icon -
-
-
We got into GSoC 2020
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna -
-
-
-
- -
-
- icon -
-
-
We got into GSoC 2020
-
- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed - do eiusmod tempor incididunt ut labore et dolore magna -
-
-
-
-
-
-
- ); - } -} - -export default OtherIdeas; diff --git a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.scss b/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.scss deleted file mode 100644 index 6058404f..00000000 --- a/src/user/proposals/AdminProposalDashboard/DashboardRightPanel/OtherIdeas/OtherIdeas.scss +++ /dev/null @@ -1,52 +0,0 @@ -.ideas { - .ideas-title { - margin-top: 10px; - font-family: Inter; - font-style: normal; - font-weight: 600; - font-size: 22px; - line-height: 27px; - - color: #000000; - } - .ideas-container { - border: solid 1px #dfe9f1; - overflow: auto; - border-radius: 5px; - margin: 5px; - max-height: 300px; - .idea-item { - display: flex; - padding: none; - .image-container { - flex: 1; - .user-image { - width: 30px; - height: 30px; - } - } - .idea-container { - flex: 6; - .idea-title { - font-family: Inter; - font-style: normal; - font-weight: 600; - font-size: 14px; - line-height: 21px; - /* identical to box height, or 150% */ - - color: #000000; - } - .idea-description { - font-family: Inter; - font-style: normal; - font-weight: normal; - font-size: 12px; - line-height: 15px; - - color: rgba(29, 33, 41, 0.5); - } - } - } - } -} diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js index 54be6cc8..0db5d7a0 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js @@ -1,8 +1,9 @@ import React, { Component } from "react"; -import userIcon2 from "../../../../../images/userIcon2.jpg"; import { Form, ListGroup, Button } from "react-bootstrap"; import "./DiscussionComments.scss"; import Carousel, { Modal, ModalGateway } from "react-images"; +import { connect } from "react-redux"; +import { commentProposal } from "../../../../../actions/proposalActions"; class DiscussionComments extends Component { constructor(props) { @@ -15,23 +16,15 @@ class DiscussionComments extends Component { } handleComment = (text) => { - fetch("http://localhost:5000/proposal/comment", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: this.props.token, - }, - body: JSON.stringify({ - userId: this.props.userId, - proposalId: this.props.proposalId, - comment: this.state.commentContent, - isAuthor: this.props.isAuthor, - author: this.props.author, - }), - }); - + const commentData = { + userId: this.props.userId, + proposalId: this.props.proposalId, + comment: this.state.commentContent, + isAuthor: this.props.isAuthor, + author: this.props.author, + }; + this.props.commentProposal(commentData); this.props.handleComment(this.state.commentContent); - this.setState({ commentContent: "", }); @@ -58,24 +51,19 @@ class DiscussionComments extends Component {
-
+ @@ -84,38 +72,14 @@ class DiscussionComments extends Component {
Attached Images
-
+
{this.props.images.map((item, index) => { return ( -
+
); @@ -135,4 +99,4 @@ class DiscussionComments extends Component { } } -export default DiscussionComments; +export default connect(null, { commentProposal })(DiscussionComments); diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.scss b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.scss index 396e9af1..64ce7a5d 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.scss +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.scss @@ -82,6 +82,17 @@ .textinput { border-radius: 25px; } + + .textinput-container { + .form-text { + display: inline-block; + margin-right: 10px; + width: 70%; + } + .form-button { + width: 25%; + } + } } } .images { @@ -96,5 +107,27 @@ margin-top: 0px; color: #000000; } + .gallery { + overflow: hidden; + margin-left: 2; + margin-right: 2; + padding: 12px; + border: 1px solid #dfe9f1; + height: 100%; + .gallery-item { + box-sizing: border-box; + float: left; + margin: 2px; + margin-right: 10px; + overflow: hidden; + padding-bottom: 16%; + position: relative; + width: calc(25% - 4px); + .image-item { + max-width: 100%; + position: absolute; + } + } + } } } diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js index bffed11b..7463f400 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionContent.js @@ -2,12 +2,12 @@ import React, { Component } from "react"; import "./DiscussionContent.scss"; import { Button, Badge, Image, ListGroup } from "react-bootstrap"; import DiscussionComments from "./DiscussionComments/DiscussionComments"; -import eventImg from "../../../../svgs/event-img-1.svg"; import userIcon2 from "../../../../images/userIcon2.jpg"; import RequestChanges from "../DiscussionPopups/RequestChanges"; import { withRouter, Link } from "react-router-dom"; import { Editor } from "@tinymce/tinymce-react"; -import Carousel, { Modal, ModalGateway } from "react-images"; +import { connect } from "react-redux"; +import { getProposal } from "../../../../actions/proposalActions"; class DiscussionContent extends Component { constructor(props) { @@ -42,58 +42,45 @@ class DiscussionContent extends Component { token: token, }, () => { - console.log(this.state); - this.getData(); + this.props.getProposal(this.state.proposalId); } ); } - getData = () => { - console.log("getDtata called"); - fetch("http://localhost:5000/proposal/" + this.state.proposalId, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, - }, - }) - .then((res) => { - return res.json(); - }) - .then((resData) => { - const images = []; - resData.proposal.attachments.forEach((item, index) => { - images.push({ source: item.fileLink }); - }); + componentWillReceiveProps(nextProps) { + const { fetchedProposal } = nextProps; + const images = []; + let variant = ""; - let variant; + fetchedProposal.attachments.forEach((item, index) => { + images.push({ source: item.fileLink }); + }); - switch (resData.proposal.proposalStatus) { - case "DRAFT": - variant = "danger"; - break; - case "SUBMITTED": - variant = "secondary"; - break; - } + switch (fetchedProposal.proposalStatus) { + case "DRAFT": + variant = "danger"; + break; + case "SUBMITTED": + variant = "secondary"; + break; + } - this.setState( - { - proposalTitle: resData.proposal.title, - markdownString: resData.proposal.content, - proposalDescription: resData.proposal.proposalDescription, - commentList: resData.proposal.comments, - author: resData.proposal.creator, - proposalState: resData.proposal.proposalStatus, - variant: variant, - images: images, - }, - () => { - this.processComments(); - } - ); - }); - }; + this.setState( + { + proposalTitle: fetchedProposal.title, + markdownString: fetchedProposal.content, + proposalDescription: fetchedProposal.proposalDescription, + commentList: fetchedProposal.comments, + author: fetchedProposal.creator, + proposalState: fetchedProposal.proposalStatus, + + images: images, + }, + () => { + this.processComments(); + } + ); + } processComments = () => { let comments = []; @@ -254,4 +241,10 @@ class DiscussionContent extends Component { } } -export default withRouter(DiscussionContent); +const mapStateToProps = (state) => ({ + fetchedProposal: state.proposal.fetchedProposal, +}); + +export default connect(mapStateToProps, { getProposal })( + withRouter(DiscussionContent) +); diff --git a/src/user/proposals/ProposalEditor/EditorContent/DropZone.js b/src/user/proposals/ProposalEditor/EditorContent/DropZone.js index 1dbde1bd..6ede4ec0 100644 --- a/src/user/proposals/ProposalEditor/EditorContent/DropZone.js +++ b/src/user/proposals/ProposalEditor/EditorContent/DropZone.js @@ -41,7 +41,6 @@ function StyledDropzone(props) { "Please save the proposal as a draft before attaching images" ); } else { - console.log(props); let formData = new FormData(); formData.append("file", acceptedFiles[0]); const URL = `http://localhost:5000/proposal/attach/${props.idContent}`; @@ -50,7 +49,7 @@ function StyledDropzone(props) { method: "POST", body: formData, headers: { - Authorization: props.token, + Authorization: localStorage.getItem("jwtToken"), }, }) .then((res) => { diff --git a/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js b/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js index d4c10d00..c01c2fbd 100644 --- a/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js +++ b/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js @@ -1,8 +1,6 @@ import React, { Component } from "react"; import { Button, Form, Badge } from "react-bootstrap"; import "./EditorContent.scss"; -import MdEditor from "react-markdown-editor-lite"; -import MarkdownIt from "markdown-it"; import { withRouter } from "react-router-dom"; import { BeatLoader } from "react-spinners"; import { toast, ToastContainer } from "react-toastify"; @@ -14,36 +12,26 @@ import { connect } from "react-redux"; import { createProposal, getProposal, + saveProposal, + submitProposal, + deleteProposal, } from "../../../../actions/proposalActions"; //Separately importing styles related to the markdown editor import "./index.css"; -const mdParser = new MarkdownIt({ - html: true, - linkify: true, - typographer: true, -}); - class EditorContent extends Component { constructor(props) { super(props); this.state = { currentText: "", lastText: "", - newProposal: false, - - //hard coding values for demo - token: - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZWRjYjE4ZjIxNWRhNzRjMThkM2YyNzQiLCJpYXQiOjE1OTE1MjE2Nzl9.q3g5Ah_rtjPIrH7z183fVmUBTv_A4OjEoL673zeG250", - userId: "5edcb18f215da74c18d3f274", - proposalTitle: "", proposalId: "", + proposalStatus: "DRAFT", markdownString: "", proposalDescription: "", - startSave: false, isSaving: false, lastSaved: new Date().toTimeString().substring(0, 8), @@ -51,7 +39,34 @@ class EditorContent extends Component { } componentWillReceiveProps(nextProps) { - console.log("Proposals nextProps ", nextProps); + const { fetchedProposal, createdProposal } = nextProps; + + if (Object.keys(fetchedProposal).length !== 0) { + this.setState({ + proposalTitle: fetchedProposal.title, + proposalDescription: fetchedProposal.proposalDescription, + markdownString: fetchedProposal.content, + proposalId: fetchedProposal._id, + proposalStatus: fetchedProposal.proposalStatus, + }); + } + if (Object.keys(createProposal).length !== 0) { + this.setState( + { + isSaving: false, + newProposal: false, + proposalId: createdProposal._id, + lastSaved: new Date().toTimeString().substring(0, 8), + }, + () => { + let idVar = setInterval(this.saveProposal, 20000); + this.setState({ + idVar: idVar, + startSave: true, + }); + } + ); + } } componentDidMount() { @@ -62,6 +77,7 @@ class EditorContent extends Component { { idVar: idVar, proposalId: this.props.location.state.proposalId, + startSave: true, }, () => { setTimeout(() => { @@ -78,62 +94,24 @@ class EditorContent extends Component { } } - //Obtain proposal data from the server - getData = () => { - this.props.getProposal(this.props.location.state.proposalId); - - // fetch("http://localhost:5000/proposal/" + this.state.proposalId, { - // method: "GET", - // headers: { - // "Content-Type": "application/json", - // Authorization: this.state.token, - // }, - // }) - // .then((res) => { - // return res.json(); - // }) - // .then((resData) => { - // console.log(resData); - // this.setState({ - // proposalTitle: resData.proposal.title, - // markdownString: resData.proposal.content, - // proposalDescription: resData.proposal.proposalDescription, - // lastText: resData.proposal.content, - // currentText: resData.proposal.content, - // startSave: true, - // }); - // }); - }; - //Update the content of the proposal saveProposal = () => { let { lastText, currentText } = this.state; if (lastText !== currentText) { this.setState({ isSaving: true }); + let proposalInfo = { + title: this.state.proposalTitle, + description: this.state.proposalDescription, + content: this.state.currentText, + proposalId: this.state.proposalId, + }; + setTimeout(() => { - fetch(`http://localhost:5000/proposal/${this.state.proposalId}`, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, - }, - body: JSON.stringify({ - title: this.state.proposalTitle, - description: this.state.proposalDescription, - content: this.state.currentText, - }), - }) - .then((res) => { - return res.json(); - }) - .then((resData) => { - this.setState({ - lastText: currentText, - isSaving: false, - lastSaved: new Date().toTimeString().substring(0, 8), - }); - }); + this.props.saveProposal(proposalInfo); + this.setState({ + isSaving: false, + }); }, 2000); } }; @@ -146,65 +124,30 @@ class EditorContent extends Component { content: this.state.currentText, proposalStatus: "DRAFT", creator: localStorage.getItem("userId"), + description: this.state.proposalDescription, }; this.props.createProposal(proposalInfo); - // fetch("http://localhost:5000/proposal", { - // method: "POST", - // headers: { - // "Content-Type": "application/json", - // Authorization: this.state.token, - // }, - // body: JSON.stringify({ - // title: this.state.proposalTitle, - // content: this.state.currentText, - // proposalStatus: "DRAFT", - // creator: this.state.userId, - // }), - // }) - // .then((res) => { - // return res.json(); - // }) - // .then((resData) => { - // this.setState( - // { - // newProposal: false, - // proposalId: resData.proposal._id, - // isSaving: false, - // lastSaved: new Date().toTimeString().substring(0, 8), - // }, - // () => { - // toast.success("Proposal Drafted Successfully!"); - // let idVar = setInterval(this.saveProposal, 20000); - // this.setState({ - // idVar: idVar, - // startSave: true, - // }); - // } - // ); - // }); + let idVar = setInterval(this.saveProposal, 20000); + this.setState({ + idVar: idVar, + startSave: true, + newProposal: false, + }); }, 2000); }; submitProposal = () => { - fetch("http://localhost:5000/proposal/change/" + this.state.proposalId, { - method: "PATCH", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, - }, - body: JSON.stringify({ - proposalStatus: "SUBMITTED", - }), - }).then((res) => { - setTimeout(() => { - this.props.history.push("/proposal"); - }, 3000); - toast.success( - "Proposal Successfully Submitted! Redirecting to dashboard" - ); - }); + const proposalData = { + proposalId: this.state.proposalId, + proposalStatus: "SUBMITTED", + }; + this.props.submitProposal(proposalData); + setTimeout(() => { + this.props.history.push("/proposal"); + }, 3000); + toast.success("Proposal Successfully Submitted! Redirecting to dashboard"); }; handleEditorChange = ({ html, text }) => { @@ -234,26 +177,17 @@ class EditorContent extends Component { }; handleDeleteProposal = () => { - fetch("http://localhost:5000/proposal/", { - method: "DELETE", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, - }, - body: JSON.stringify({ - proposalId: this.state.proposalId, - }), - }).then((res) => { - setTimeout(() => { - this.props.history.push("/proposal"); - }, 3000); - toast.error("Proposal Deleted Successfully. Redirecting to dashboard"); - }); + this.props.deleteProposal(this.state.proposalId); + setTimeout(() => { + this.props.history.push("/proposal"); + }, 3000); + toast.error("Proposal Deleted Successfully. Redirecting to dashboard"); }; componentWillUnmount() { clearInterval(this.state.idVar); } + handleTinyEditorChange = (content, editor) => { this.setState({ draftEnabled: true, @@ -275,7 +209,7 @@ class EditorContent extends Component { name="proposalTitle" className="searchbar" onChange={this.handleChange} - value={this.props.proposalTitle} + value={this.state.proposalTitle} /> Short Description )} - - + {this.state.proposalStatus === "DRAFT" ? ( + + ) : null} +
{!this.state.newProposal ? ( ) : (
@@ -451,11 +384,15 @@ class EditorContent extends Component { } const mapStateToProps = (state) => ({ - createdProposal: state.createdProposal, - fetchedProposal: state.fetchedProposal, - proposalIsFetched: state.proposalIsFetched, + createdProposal: state.proposal.createdProposal, + fetchedProposal: state.proposal.fetchedProposal, + proposalIsFetched: state.proposal.proposalIsFetched, }); -export default connect(mapStateToProps, { createProposal, getProposal })( - withRouter(EditorContent) -); +export default connect(mapStateToProps, { + createProposal, + getProposal, + saveProposal, + submitProposal, + deleteProposal, +})(withRouter(EditorContent)); diff --git a/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js b/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js index f9576441..86348ffe 100644 --- a/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js +++ b/src/user/proposals/UserProposalDashboard/DashboardContent/DashboardContent.js @@ -3,41 +3,37 @@ import { Button, Form, Col, Image } from "react-bootstrap"; import "./DashboardContent.scss"; import userIcon2 from "../../../../images/userIcon2.jpg"; import { Link } from "react-router-dom"; +import { connect } from "react-redux"; +import { + getProposalsByUser, + getAllProposals, +} from "../../../../actions/proposalActions"; class DashboardContent extends Component { constructor(props) { super(props); this.state = { - token: - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZWRjYjE4ZjIxNWRhNzRjMThkM2YyNzQiLCJpYXQiOjE1OTE1MjE2Nzl9.q3g5Ah_rtjPIrH7z183fVmUBTv_A4OjEoL673zeG250", - userId: "5edcb18f215da74c18d3f274", + userId: localStorage.getItem("userId"), proposals: [], displayItems: [], + allProposals: [], + userProposals: [], }; } componentDidMount() { - this.getProposalsByUserId(); + this.props.getAllProposals(); + this.props.getProposalsByUser(this.state.userId); } - getProposalsByUserId() { - fetch(`http://localhost:5000/proposal/user/${this.state.userId}`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, - }, - }) - .then((res) => { - return res.json(); - }) - .then((resData) => { - console.log(resData); - this.setState({ - proposals: resData.proposal, - displayItems: resData.proposal, - }); - }); + componentWillReceiveProps(nextProps) { + const { allProposals, userProposals } = nextProps; + + this.setState({ + allProposals: allProposals, + userProposals: userProposals, + displayItems: allProposals, + }); } handleSearchBarChange = (evt) => { @@ -63,13 +59,15 @@ class DashboardContent extends Component { }; handleButtonClick = (name) => { - const proposals = this.state.proposals; + const proposals = this.state.userProposals; + const allProposals = this.state.allProposals; + let results = []; switch (name) { case "All": this.setState({ - displayItems: proposals, + displayItems: allProposals, }); break; case "Accepted": @@ -139,7 +137,7 @@ class DashboardContent extends Component { className="category-btn" onClick={() => this.handleButtonClick("All")} > - All + All Proposals - + + + ) : null} @@ -266,4 +267,12 @@ class DashboardContent extends Component { } } -export default DashboardContent; +const mapStateToProps = (state) => ({ + allProposals: state.proposal.allProposals, + userProposals: state.proposal.userProposals, +}); + +export default connect(mapStateToProps, { + getProposalsByUser, + getAllProposals, +})(DashboardContent); diff --git a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js index 7f29d8c5..d3b1a60a 100644 --- a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js +++ b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js @@ -3,26 +3,30 @@ import "./OtherIdeas.scss"; import { ListGroup, Image } from "react-bootstrap"; import userIcon2 from "../../../../../images/userIcon2.jpg"; import socket from "../Utils/socket"; -import notifications from "../../../../dashboard/notifications/notifications"; +import { connect } from "react-redux"; +import { getUserProposalNotifications } from "../../../../../actions/proposalActions"; +import { getProposalNotifications } from "../../../../../actions/notificationAction"; class Notifications extends Component { constructor(props) { super(props); this.state = { socket: socket, - token: - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZWRjYjE4ZjIxNWRhNzRjMThkM2YyNzQiLCJpYXQiOjE1OTE1MjE2Nzl9.q3g5Ah_rtjPIrH7z183fVmUBTv_A4OjEoL673zeG250", - userId: "5edcb18f215da74c18d3f274", notifications: [], }; } componentDidMount() { - this.fetchNotifications(); + const data = { + userId: localStorage.getItem("userId"), + }; + + this.props.getProposalNotifications(); + this.props.getUserProposalNotifications(data); this.state.socket.on("new proposal created", (data) => { data.newNotification = true; - data.createdAt = new Date(); + data.createdAt = new Date().toString().substring(0, 24); this.setState({ notifications: [...this.state.notifications, data], }); @@ -30,71 +34,45 @@ class Notifications extends Component { this.state.socket.on("proposal deleted", (data) => { data.newNotification = true; - data.createdAt = new Date(); + data.createdAt = new Date().toString().substring(0, 24); this.setState({ notifications: [...this.state.notifications, data], }); }); - } - fetchNotifications = () => { - fetch("http://localhost:5000/notification/proposal/all", { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, - }, - }) - .then((res) => { - return res.json(); - }) - .then((resData) => { - this.setState( - { - notifications: [ - ...this.state.notifications, - ...resData.notifications, - ], - }, - () => { - this.fetchUserNotifications(); - } - ); + this.state.socket.on("proposal submitted", (data) => { + data.newNotification = true; + data.createdAt = new Date().toString().substring(0, 24); + this.setState({ + notifications: [...this.state.notifications, data], }); - }; + }); + } - fetchUserNotifications = () => { - fetch("http://localhost:5000/proposal/notifications", { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: this.state.token, + componentWillReceiveProps(nextProps) { + nextProps.proposalNotifications.forEach((notification, index) => { + let createdTime = new Date(notification.createdAt) + .toString() + .substring(0, 24); + notification.createdAt = createdTime.toString(); + }); + + this.setState( + { + notifications: [ + ...this.state.notifications, + ...nextProps.proposalNotifications, + ...nextProps.userProposalNotifications, + ], }, - body: JSON.stringify({ - userId: this.state.userId, - }), - }) - .then((res) => { - return res.json(); - }) - .then((resData) => { - this.setState( - { - notifications: [ - ...this.state.notifications, - ...resData.notifications, - ], - }, - () => { - this.organizaNotifications(); - } - ); - }); - }; + () => { + this.organizaNotifications(); + } + ); + } organizaNotifications = () => { let notifications = this.state.notifications; - console.log(notifications); notifications.sort((a, b) => { return new Date(b.createdAt) - new Date(a.createdAt); @@ -106,7 +84,7 @@ class Notifications extends Component { }; render() { - const notifications = this.state.notifications; + const notifications = [...this.state.notifications]; return (
Notifications
@@ -134,7 +112,10 @@ class Notifications extends Component {
{notification.heading}
-
+ +
+ {notification.createdAt} +
{notification.content}
@@ -150,4 +131,12 @@ class Notifications extends Component { } } -export default Notifications; +const mapStateToProps = (state) => ({ + proposalNotifications: state.notification.proposalNotifications, + userProposalNotifications: state.proposal.userNotifications, +}); + +export default connect(mapStateToProps, { + getUserProposalNotifications, + getProposalNotifications, +})(Notifications); From ac04c77a5d91dfd57e447cdca0bae6e4e759f69b Mon Sep 17 00:00:00 2001 From: Asel Date: Fri, 3 Jul 2020 16:58:03 +0530 Subject: [PATCH 6/7] Requested changes --- .vscode/launch.json | 15 --------------- src/user/organization/organization.js | 2 ++ .../DiscussionComments/DiscussionComments.js | 10 ++++++---- .../ProposalEditor/EditorContent/EditorContent.js | 2 +- .../Notifications/Notifications.js | 2 +- .../DashboardRightPanel/Utils/socket.js | 3 --- 6 files changed, 10 insertions(+), 24 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/socket.js diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 7a9dfa04..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "pwa-chrome", - "request": "launch", - "name": "Launch Chrome against localhost", - "url": "http://localhost:8080", - "webRoot": "${workspaceFolder}" - } - ] -} \ No newline at end of file diff --git a/src/user/organization/organization.js b/src/user/organization/organization.js index d8e74572..5dd8c664 100644 --- a/src/user/organization/organization.js +++ b/src/user/organization/organization.js @@ -13,6 +13,8 @@ import contactLoading from "../../placeholderLoading/contactLoading/contactLoadi import cardLoading from "../../placeholderLoading/cardLoading/cardLoading"; import { connect } from "react-redux"; import { getOrgProfile } from "../../actions/orgAction"; +import { Link } from "react-router-dom"; +import { Button } from "react-bootstrap"; class Organization extends Component { constructor(props) { diff --git a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js index 0db5d7a0..81c02670 100644 --- a/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js +++ b/src/user/proposals/ProposalDiscussion/DiscussionContent/DiscussionComments/DiscussionComments.js @@ -16,12 +16,14 @@ class DiscussionComments extends Component { } handleComment = (text) => { + const { userId, proposalId, isAuthor, author } = this.props; + const commentData = { - userId: this.props.userId, - proposalId: this.props.proposalId, + userId: userId, + proposalId: proposalId, comment: this.state.commentContent, - isAuthor: this.props.isAuthor, - author: this.props.author, + isAuthor: isAuthor, + author: author, }; this.props.commentProposal(commentData); this.props.handleComment(this.state.commentContent); diff --git a/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js b/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js index c01c2fbd..64521ec0 100644 --- a/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js +++ b/src/user/proposals/ProposalEditor/EditorContent/EditorContent.js @@ -124,7 +124,7 @@ class EditorContent extends Component { content: this.state.currentText, proposalStatus: "DRAFT", creator: localStorage.getItem("userId"), - description: this.state.proposalDescription, + proposalDescription: this.state.proposalDescription, }; this.props.createProposal(proposalInfo); diff --git a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js index d3b1a60a..422c39fb 100644 --- a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js +++ b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Notifications/Notifications.js @@ -2,7 +2,7 @@ import React, { Component } from "react"; import "./OtherIdeas.scss"; import { ListGroup, Image } from "react-bootstrap"; import userIcon2 from "../../../../../images/userIcon2.jpg"; -import socket from "../Utils/socket"; +import socket from "../../../../dashboard/utils/socket"; import { connect } from "react-redux"; import { getUserProposalNotifications } from "../../../../../actions/proposalActions"; import { getProposalNotifications } from "../../../../../actions/notificationAction"; diff --git a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/socket.js b/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/socket.js deleted file mode 100644 index 766eac17..00000000 --- a/src/user/proposals/UserProposalDashboard/DashboardRightPanel/Utils/socket.js +++ /dev/null @@ -1,3 +0,0 @@ -import io from "socket.io-client"; -const socket = io("http://localhost:8810"); -export default socket; From 21228dd1c08d4dfde2d5da965e230e9650681711 Mon Sep 17 00:00:00 2001 From: Asel Date: Fri, 3 Jul 2020 20:34:22 +0530 Subject: [PATCH 7/7] removing edits caused in memberInfo.scss --- .../insights/components/memberInfo.scss | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/user/dashboard/insights/components/memberInfo.scss b/src/user/dashboard/insights/components/memberInfo.scss index c2d3dbf7..5065ef06 100644 --- a/src/user/dashboard/insights/components/memberInfo.scss +++ b/src/user/dashboard/insights/components/memberInfo.scss @@ -19,7 +19,7 @@ .active_btn { width: 11vw; height: 5vh; - background: #1a73e8; + background: #1A73E8; border-radius: 100px; padding: 0.3em; margin-right: 1em; @@ -29,7 +29,7 @@ height: 5vh; background: rgb(250, 251, 252); border-radius: 100px; - color: #1a73e8; + color: #1A73E8; padding: 0.3em; margin-right: 1em; } @@ -37,8 +37,8 @@ .members_overview { width: 90vw; .search_bar { - background: #ffffff; - border: 1.5px solid #cccccc; + background: #FFFFFF; + border: 1.5px solid #CCCCCC; border-radius: 100px; width: 39.5%; padding: 0.4em; @@ -61,8 +61,8 @@ margin-top: 1em; .single_member { display: flex; - background: #ffffff; - border: 1px solid #cccccc; + background: #FFFFFF; + border: 1px solid #CCCCCC; box-shadow: 1px 2px 5px rgba(0, 0, 0, 0.1); padding-top: 0.7em; padding-left: 0.7em; @@ -78,7 +78,7 @@ height: 60px; background-blend-mode: normal; border-radius: 5px; - border: 1px solid #cccccc; + border: 1px solid #CCCCCC; margin-right: 0.7em; } .member_details { @@ -88,21 +88,21 @@ .row { width: 29vw; } - .member_name { - font-family: Inter; - font-style: normal; - font-weight: 600; - font-size: 1.2em; - line-height: 1.5em; - color: #1a73e8; - } - .hamburger { + .member_name { + font-family: Inter; + font-style: normal; + font-weight: 600; + font-size: 1.2em; + line-height: 1.5em; + color: #1A73E8; + } + .hamburger { .dotted_hamberger { clear: both; float: right; cursor: pointer; } - } + } } .member_designation { font-family: Inter; @@ -111,7 +111,7 @@ font-size: 0.9em; line-height: 0%; letter-spacing: 0.15em; - color: #90949c; + color: #90949C; margin-top: -0.5em; } @@ -121,13 +121,13 @@ font-weight: normal; font-size: 0.5em; line-height: 10px; - color: #90949c; + color: #90949C; margin-top: -0.7em; } } } } - input[type="text"] { + input[type=text] { padding: 0.5em; } } @@ -143,20 +143,20 @@ text-align: center; .overlay_list_btn { cursor: pointer; - background: transparent; - border-radius: 100px; - font-family: Inter; - font-style: normal; - font-weight: normal; - font-size: 1em; - line-height: 1.1em; - color: #eb5757; - border: 1px solid #eb5757; - box-sizing: border-box; - padding-bottom: 0.4em; + background: transparent; + border-radius: 100px; + font-family: Inter; + font-style: normal; + font-weight: normal; + font-size: 1em; + line-height: 1.1em; + color: #EB5757; + border: 1px solid #EB5757; + box-sizing: border-box; + padding-bottom: 0.4em; } .overlay_list_btn:hover { background: transparent; - color: #eb5757; + color: #EB5757; } -} +} \ No newline at end of file