diff --git a/.env.sample b/.env.sample index c4f419fc4..89a12e8c7 100644 --- a/.env.sample +++ b/.env.sample @@ -1,4 +1,5 @@ VITE_BACKEND_URL= VITE_FRONTEND_URL= VITE_DISCORD_INVITE_URL= -VITE_RAZORPAY_KEY_ID= \ No newline at end of file +VITE_RAZORPAY_KEY_ID= +VITE_DISCORD_AUTH_URL= \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 28bf96b06..74c81fa67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@chakra-ui/react": "^2.6.1", "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", + "@types/react-star-ratings": "^2.3.3", "@types/react-tabs": "^5.0.5", "axios": "^1.3.4", "file-saver": "^2.0.5", @@ -32,7 +33,9 @@ "react-router-dom": "^6.9.0", "react-select": "^5.7.7", "react-spinners": "^0.13.8", + "react-star-ratings": "^2.3.0", "react-tabs": "^6.0.1", + "react-tag-input-component": "^2.0.2", "react-tooltip": "^5.18.1", "recharts": "^2.10.2", "sass": "^1.62.1", @@ -2101,16 +2104,21 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", "dependencies": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/runtime/node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/@babel/template": { "version": "7.22.15", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", @@ -3331,21 +3339,21 @@ } }, "node_modules/@emotion/babel-plugin": { - "version": "11.10.6", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", - "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/serialize": "^1.1.1", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", "source-map": "^0.5.7", - "stylis": "4.1.3" + "stylis": "4.2.0" } }, "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { @@ -3360,47 +3368,47 @@ } }, "node_modules/@emotion/cache": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", - "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", + "version": "11.13.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", + "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", "dependencies": { - "@emotion/memoize": "^0.8.0", - "@emotion/sheet": "^1.2.1", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "stylis": "4.1.3" + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" } }, "node_modules/@emotion/hash": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" }, "node_modules/@emotion/is-prop-valid": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", - "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", "dependencies": { - "@emotion/memoize": "^0.8.0" + "@emotion/memoize": "^0.9.0" } }, "node_modules/@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" }, "node_modules/@emotion/react": { - "version": "11.10.6", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz", - "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==", + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.10.6", - "@emotion/cache": "^11.10.5", - "@emotion/serialize": "^1.1.1", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, "peerDependencies": { @@ -3413,33 +3421,33 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", + "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", "dependencies": { - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/unitless": "^0.8.0", - "@emotion/utils": "^1.2.0", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.1", "csstype": "^3.0.2" } }, "node_modules/@emotion/sheet": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", - "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" }, "node_modules/@emotion/styled": { - "version": "11.10.6", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz", - "integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", + "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.10.6", - "@emotion/is-prop-valid": "^1.2.0", - "@emotion/serialize": "^1.1.1", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", - "@emotion/utils": "^1.2.0" + "@emotion/babel-plugin": "^11.12.0", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0" }, "peerDependencies": { "@emotion/react": "^11.0.0-rc.0", @@ -3452,27 +3460,27 @@ } }, "node_modules/@emotion/unitless": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", - "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", + "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==" }, "node_modules/@emotion/weak-memoize": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" }, "node_modules/@esbuild/android-arm": { "version": "0.18.20", @@ -4056,9 +4064,9 @@ } }, "node_modules/@popperjs/core": { - "version": "2.11.7", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", - "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==", + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -4409,9 +4417,9 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" }, "node_modules/@types/raf": { "version": "3.4.3", @@ -4447,6 +4455,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-star-ratings": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/react-star-ratings/-/react-star-ratings-2.3.3.tgz", + "integrity": "sha512-8vLqJG1uRA2SmYBBMPWpv6QWHLvZ/a3XmELCIf4xh4VFXT7QkkrcthiLSMjQ4ibDiUtYYpyLB0JoR1lBHSHA2A==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-tabs": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/@types/react-tabs/-/react-tabs-5.0.5.tgz", @@ -4457,9 +4473,9 @@ } }, "node_modules/@types/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", "dependencies": { "@types/react": "*" } @@ -5577,9 +5593,9 @@ } }, "node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/d3-array": { "version": "3.2.4", @@ -8929,6 +8945,29 @@ "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/react-star-ratings": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-star-ratings/-/react-star-ratings-2.3.0.tgz", + "integrity": "sha512-34Z/oFNDRRn4ZcX7F3t9ccnpo7SQ32gD/vsusQOBc6B6vlqaGR6tke1/Yx3jTDjemKRSmXqhKgpPTR7/JAXq6A==", + "dependencies": { + "classnames": "^2.2.1", + "prop-types": "^15.6.0", + "react": "^16.1.0" + } + }, + "node_modules/react-star-ratings/node_modules/react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", @@ -8963,6 +9002,15 @@ "react": "^18.0.0" } }, + "node_modules/react-tag-input-component": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-tag-input-component/-/react-tag-input-component-2.0.2.tgz", + "integrity": "sha512-dydI9luVwwv9vrjE5u1TTnkcOVkOVL6mhFti8r6hLi78V2F2EKWQOLptURz79UYbDHLSk6tnbvGl8FE+sMpADg==", + "peerDependencies": { + "react": "^16 || ^17 || ^18", + "react-dom": "^16 || ^17 || ^18" + } + }, "node_modules/react-tooltip": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.18.1.tgz", @@ -9082,7 +9130,8 @@ "node_modules/regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "optional": true }, "node_modules/regenerator-transform": { "version": "0.15.2", @@ -9711,9 +9760,9 @@ } }, "node_modules/stylis": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", - "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, "node_modules/supports-color": { "version": "5.5.0", @@ -12001,11 +12050,18 @@ "dev": true }, "@babel/runtime": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz", - "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==", + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", "requires": { - "regenerator-runtime": "^0.13.11" + "regenerator-runtime": "^0.14.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + } } }, "@babel/template": { @@ -12933,21 +12989,21 @@ "requires": {} }, "@emotion/babel-plugin": { - "version": "11.10.6", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz", - "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", "requires": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/serialize": "^1.1.1", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", "find-root": "^1.1.0", "source-map": "^0.5.7", - "stylis": "4.1.3" + "stylis": "4.2.0" }, "dependencies": { "escape-string-regexp": { @@ -12958,100 +13014,100 @@ } }, "@emotion/cache": { - "version": "11.10.5", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.10.5.tgz", - "integrity": "sha512-dGYHWyzTdmK+f2+EnIGBpkz1lKc4Zbj2KHd4cX3Wi8/OWr5pKslNjc3yABKH4adRGCvSX4VDC0i04mrrq0aiRA==", + "version": "11.13.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", + "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", "requires": { - "@emotion/memoize": "^0.8.0", - "@emotion/sheet": "^1.2.1", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", - "stylis": "4.1.3" + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" } }, "@emotion/hash": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.0.tgz", - "integrity": "sha512-14FtKiHhy2QoPIzdTcvh//8OyBlknNs2nXRwIhG904opCby3l+9Xaf/wuPvICBF0rc1ZCNBd3nKe9cd2mecVkQ==" + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" }, "@emotion/is-prop-valid": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz", - "integrity": "sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", "requires": { - "@emotion/memoize": "^0.8.0" + "@emotion/memoize": "^0.9.0" } }, "@emotion/memoize": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz", - "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" }, "@emotion/react": { - "version": "11.10.6", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz", - "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==", + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", "requires": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.10.6", - "@emotion/cache": "^11.10.5", - "@emotion/serialize": "^1.1.1", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", - "@emotion/utils": "^1.2.0", - "@emotion/weak-memoize": "^0.3.0", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" } }, "@emotion/serialize": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.1.tgz", - "integrity": "sha512-Zl/0LFggN7+L1liljxXdsVSVlg6E/Z/olVWpfxUTxOAmi8NU7YoeWeLfi1RmnB2TATHoaWwIBRoL+FvAJiTUQA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", + "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", "requires": { - "@emotion/hash": "^0.9.0", - "@emotion/memoize": "^0.8.0", - "@emotion/unitless": "^0.8.0", - "@emotion/utils": "^1.2.0", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.1", "csstype": "^3.0.2" } }, "@emotion/sheet": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.1.tgz", - "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" }, "@emotion/styled": { - "version": "11.10.6", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz", - "integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", + "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", "requires": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.10.6", - "@emotion/is-prop-valid": "^1.2.0", - "@emotion/serialize": "^1.1.1", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0", - "@emotion/utils": "^1.2.0" + "@emotion/babel-plugin": "^11.12.0", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0" } }, "@emotion/unitless": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.0.tgz", - "integrity": "sha512-VINS5vEYAscRl2ZUDiT3uMPlrFQupiKgHz5AA4bCH1miKBg4qtwkim1qPmJj/4WG6TreYMY111rEFsjupcOKHw==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" }, "@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz", - "integrity": "sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", "requires": {} }, "@emotion/utils": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.0.tgz", - "integrity": "sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==" + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", + "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==" }, "@emotion/weak-memoize": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", - "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" }, "@esbuild/android-arm": { "version": "0.18.20", @@ -13374,9 +13430,9 @@ } }, "@popperjs/core": { - "version": "2.11.7", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", - "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==" + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" }, "@remix-run/router": { "version": "1.10.0", @@ -13717,9 +13773,9 @@ "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" }, "@types/raf": { "version": "3.4.3", @@ -13755,6 +13811,14 @@ "@types/react": "*" } }, + "@types/react-star-ratings": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/react-star-ratings/-/react-star-ratings-2.3.3.tgz", + "integrity": "sha512-8vLqJG1uRA2SmYBBMPWpv6QWHLvZ/a3XmELCIf4xh4VFXT7QkkrcthiLSMjQ4ibDiUtYYpyLB0JoR1lBHSHA2A==", + "requires": { + "@types/react": "*" + } + }, "@types/react-tabs": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/@types/react-tabs/-/react-tabs-5.0.5.tgz", @@ -13764,9 +13828,9 @@ } }, "@types/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", "requires": { "@types/react": "*" } @@ -14574,9 +14638,9 @@ "dev": true }, "csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "d3-array": { "version": "3.2.4", @@ -17024,6 +17088,28 @@ "integrity": "sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==", "requires": {} }, + "react-star-ratings": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-star-ratings/-/react-star-ratings-2.3.0.tgz", + "integrity": "sha512-34Z/oFNDRRn4ZcX7F3t9ccnpo7SQ32gD/vsusQOBc6B6vlqaGR6tke1/Yx3jTDjemKRSmXqhKgpPTR7/JAXq6A==", + "requires": { + "classnames": "^2.2.1", + "prop-types": "^15.6.0", + "react": "^16.1.0" + }, + "dependencies": { + "react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + } + } + }, "react-style-singleton": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz", @@ -17043,6 +17129,12 @@ "prop-types": "^15.5.0" } }, + "react-tag-input-component": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-tag-input-component/-/react-tag-input-component-2.0.2.tgz", + "integrity": "sha512-dydI9luVwwv9vrjE5u1TTnkcOVkOVL6mhFti8r6hLi78V2F2EKWQOLptURz79UYbDHLSk6tnbvGl8FE+sMpADg==", + "requires": {} + }, "react-tooltip": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.18.1.tgz", @@ -17133,7 +17225,8 @@ "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "optional": true }, "regenerator-transform": { "version": "0.15.2", @@ -17569,9 +17662,9 @@ "dev": true }, "stylis": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz", - "integrity": "sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" }, "supports-color": { "version": "5.5.0", diff --git a/package.json b/package.json index 227d05c07..bc980676d 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@chakra-ui/react": "^2.6.1", "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", + "@types/react-star-ratings": "^2.3.3", "@types/react-tabs": "^5.0.5", "axios": "^1.3.4", "file-saver": "^2.0.5", @@ -35,7 +36,9 @@ "react-router-dom": "^6.9.0", "react-select": "^5.7.7", "react-spinners": "^0.13.8", + "react-star-ratings": "^2.3.0", "react-tabs": "^6.0.1", + "react-tag-input-component": "^2.0.2", "react-tooltip": "^5.18.1", "recharts": "^2.10.2", "sass": "^1.62.1", diff --git a/src/App.css b/src/App.css index 1d7cb588f..843de3003 100644 --- a/src/App.css +++ b/src/App.css @@ -15,6 +15,14 @@ -webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-tap-highlight-color: transparent; } +.rti--container { + width: 250px; + max-height: 100px; + overflow: scroll; +} +.rti--container .rti--input { + width: 100%; +} .css-13cymwt-control, .css-t3ipsp-control { diff --git a/src/App.tsx b/src/App.tsx index a5c709691..bd297dce5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,10 +6,6 @@ import { Navigate } from "react-router-dom"; import AuthRoutes from "./components/AuthRoutes"; -import Onboarding from "./modules/Common/Authentication/pages/Onboarding"; -import Login from "./modules/Common/Authentication/pages/Login"; -import ForgotPassword from "./modules/Common/Authentication/pages/ForgotPassword"; - import PrivateRoutes from "./components/PrivateRoutes"; import DashboardRootLayout from "./modules/Dashboard/layouts/DashboardRootLayout"; import NotFound from "./components/NotFound"; @@ -47,6 +43,12 @@ import Donation from "./modules/Public/Donation/Donation"; import Refund from "./modules/Public/Donation/pages/Refund"; import DonationSuccess from "./modules/Public/Donation/pages/DonationSuccess"; import OpenGrad from "./modules/Dashboard/modules/OpenGrad"; +import UserInterest from "./modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest"; +import LcMeetupIfo from "./modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup"; +import OrganizationSetting from "./modules/Dashboard/modules/Settings/pages/Organization/Organization"; +import SettingsHome from "./modules/Dashboard/modules/Settings/pages/Settings/SettingsHome"; +import LcReportAttendee from "./modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcAttendeeReport"; +import LcAdmin from "./modules/Dashboard/modules/LearningCircle/pages/LcAdmin/LcAdmin"; const Profile = lazy( () => import("./modules/Dashboard/modules/Profile/pages/Profile") @@ -291,12 +293,29 @@ function App() { element: , children: [ { path: "register/:role", element: }, - { path: "register/", element: }, + { + path: "register/", + children: [ + { + path: "", + element: + } + ] + }, + { path: "login", element: }, { path: "forgot-password", element: }, { path: "reset-password", element: } ] }, + { + path: "/register/interests", + element: + }, + { + path: "/register/organization", + element: + }, { path: "/signin", element: @@ -348,6 +367,15 @@ function App() { /> ) }, + { + path: "lc-meetup-verification", + element: ( + } + /> + ) + }, { path: "campus-details", element: ( @@ -683,6 +711,14 @@ function App() { path: "learning-circle", element: }, + { + path: "learning-circle/meetup/:id", + element: + }, + { + path: "learning-circle/meetup/:id/attendee-report", + element: + }, { path: "learning-circle/details/:id", element: @@ -721,6 +757,14 @@ function App() { path: "settings", element: , children: [ + { + path: "", + element: + }, + { + path: "organization", + element: + }, { path: "account", element: diff --git a/src/modules/Common/Authentication/assets/interests/creative.svg b/src/modules/Common/Authentication/assets/interests/creative.svg new file mode 100644 index 000000000..e700e2c18 --- /dev/null +++ b/src/modules/Common/Authentication/assets/interests/creative.svg @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/modules/Common/Authentication/assets/interests/makers.svg b/src/modules/Common/Authentication/assets/interests/makers.svg new file mode 100644 index 000000000..4dca1abdc --- /dev/null +++ b/src/modules/Common/Authentication/assets/interests/makers.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/modules/Common/Authentication/assets/interests/management.svg b/src/modules/Common/Authentication/assets/interests/management.svg new file mode 100644 index 000000000..d22b33537 --- /dev/null +++ b/src/modules/Common/Authentication/assets/interests/management.svg @@ -0,0 +1,342 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/modules/Common/Authentication/assets/interests/others.svg b/src/modules/Common/Authentication/assets/interests/others.svg new file mode 100644 index 000000000..e4678fac3 --- /dev/null +++ b/src/modules/Common/Authentication/assets/interests/others.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/modules/Common/Authentication/assets/interests/software.svg b/src/modules/Common/Authentication/assets/interests/software.svg new file mode 100644 index 000000000..f410c6c1a --- /dev/null +++ b/src/modules/Common/Authentication/assets/interests/software.svg @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/modules/Common/Authentication/pages/Onboarding.tsx b/src/modules/Common/Authentication/pages/Onboarding.tsx index ce6c5d71a..4c515e9d5 100644 --- a/src/modules/Common/Authentication/pages/Onboarding.tsx +++ b/src/modules/Common/Authentication/pages/Onboarding.tsx @@ -433,7 +433,6 @@ const Onboarding = (props: Props) => { setDefaultCommunity([ { value: foundCommunity.id, label: foundCommunity.title } ]); - console.log(defaultCommunity); } } }, [communityAPI]); @@ -1065,9 +1064,6 @@ const Onboarding = (props: Props) => { : null } onChange={OnChangeValue => { - console.log( - OnChangeValue - ); formik.setFieldValue( "community", OnChangeValue.map( diff --git a/src/modules/Common/Authentication/pages/Onboarding/AccountCreation/AccountCreation.tsx b/src/modules/Common/Authentication/pages/Onboarding/AccountCreation/AccountCreation.tsx index 1693863df..4e07133c0 100644 --- a/src/modules/Common/Authentication/pages/Onboarding/AccountCreation/AccountCreation.tsx +++ b/src/modules/Common/Authentication/pages/Onboarding/AccountCreation/AccountCreation.tsx @@ -3,31 +3,20 @@ import { HiEye, HiEyeSlash } from "react-icons/hi2"; import OnboardingTemplate from "../../../components/OnboardingTeamplate/OnboardingTemplate"; import OnboardingHeader from "../../../components/OnboardingHeader/OnboardingHeader"; -import { - getDWMSDetails, - getRoles, - validate -} from "../../../services/newOnboardingApis"; +import { getDWMSDetails } from "../../../services/newOnboardingApis"; import { Form, Formik } from "formik"; import * as z from "yup"; import { FormikTextInputWithoutLabel as SimpleInput } from "@/MuLearnComponents/FormikComponents/FormikComponents"; import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useState } from "react"; -// import { useToast } from "@chakra-ui/react"; import { useNavigate, useParams } from "react-router-dom"; -import Select from "react-select"; import makeAnimated from "react-select/animated"; -import { getCommunities } from "../../../services/onboardingApis"; import { BiSupport } from "react-icons/bi"; import { isDev } from "@/MuLearnServices/common_functions"; -import roleOptions from "../RolePage/data/roleOptions"; -import muBrand from "/src/modules/Common/Authentication/assets/µLearn.png"; import { submitUserData } from "../../../services/newOnboardingApis"; import toast from "react-hot-toast"; -const animatedComponents = makeAnimated(); - type DWMSData = { email: string; fullName: string; @@ -77,29 +66,17 @@ const scheme = z.object({ export default function AccountCreation() { let { role } = useParams(); - const [popUP, setPopUp] = useState(role ? false : true); - // const toast = useToast(); const navigate = useNavigate(); - const [roles, setRoles] = useState([{ id: "", title: "" }]); const urlParams = new URLSearchParams(window.location.search); const param = urlParams.get("param"); const referralId = urlParams.get("referral_id"); - const [selectedRoleId, setSelectedRoleId] = useState(""); - const [selectedRole, setSelectedRole] = useState(""); - - //ref to community selector for resetting - temporary fix - const community_select_ref = useRef(); const [isLoading, setIsLoading] = useState(false); const [isVisible, setVisible] = useState(false); - const [isVisibleC, setVisibleC] = useState(false); const [dwmsData, setDWMSData] = useState(); const [isTncChecked, setTncChecked] = useState(false); - const [communitiesList, setCommunitiesList] = useState([ - { id: "", title: "" } - ]); const [initialValues, setInitialValues] = useState({ email: "", fullName: "", @@ -108,6 +85,7 @@ export default function AccountCreation() { muid: "", communities: [] }); + const ruri = window.location.href.split("=")[1]; role = role === "student" || role === "mentor" || role === "enabler" @@ -117,19 +95,6 @@ export default function AccountCreation() { useEffect(() => { if (isLoading) return; setIsLoading(true); - getCommunities({ - setCommunityAPI: setCommunitiesList, - setIsLoading: setIsLoading - }); - getRoles().then((res: any) => { - setRoles(res); - setIsLoading(false); - setSelectedRoleId( - res.find((role: any) => role.title.toLowerCase() === role) - ?.id || "" - ); - // setSelectedRole(role); - }); if (param) { getDWMSDetails(param, (data: any) => { setDWMSData({ @@ -155,16 +120,12 @@ export default function AccountCreation() { setIsLoading(false); }, []); - // console.log(roles.find(e => e.title.toLowerCase() === role)?.id); const onsubmit = async (values: any, actions: any) => { if (!isTncChecked) { toast.error("Please accept the terms and conditions"); return; } - - // console.log(values); - const userData: { user: { full_name: any; @@ -188,32 +149,10 @@ export default function AccountCreation() { } }; - // if (values.lastName) { - // userData.user.last_name = values.lastName; - // } - - if (values.muid) { - userData.referral = { muid: values.muid }; - } else if (referralId) { - userData.referral = { muid: referralId }; - } - if (dwmsData && dwmsData.gender) { userData.gender = dwmsData.gender; } - if (values.communities) { - userData.communities = values.communities; - } - - if (role) { - userData.role = roles.find(e => e.title.toLowerCase() === role)?.id; - } - - if (selectedRoleId) { - userData.role = selectedRoleId; - } - if (param) { userData.integration = { param: param, @@ -225,24 +164,19 @@ export default function AccountCreation() { userData.dob = dwmsData.dob; } - const isSuccess = await validate({ - userData: userData, - setIsSubmitting: setIsLoading - // toast: toast // Make sure to pass the toast parameter correctly + submitUserData({ + setIsLoading: setIsLoading, + userData: userData + }).then(res => { + if (res) { + navigate( + ruri + ? `/register/interests/?ruri=${ruri}` + : "/register/interests" + ); + } }); - - if (isSuccess && selectedRole.toLowerCase() !== "other") { - navigate("/register/about", { state: userData }); - } else if (isSuccess && selectedRole.toLowerCase() === "other") { - submitUserData({ - setIsLoading: setIsLoading, - userData: userData, - // toast: toast, - navigate: navigate - }); - } }; - // console.log(selectedRole, role); return ( @@ -258,51 +192,6 @@ export default function AccountCreation() { > {formik => (
- {popUP && ( -
-
- mulearn -

What describes you the most!

-

- Choose the role that best fits your - profile. -

-
- {roleOptions.map((roleOption: any) => { - let classname = `${ - styles.rolePageCard - } ${ - selectedRole === - roleOption.value && - styles.active - }`; - return ( -
{ - let rolId = roles.find( - role => - role.title === - roleOption.value - )?.id; - setSelectedRoleId( - rolId || "" - ); - setSelectedRole( - roleOption.value - ); - setPopUp(false); - }} - > - {roleOption.icon} -

{roleOption.title}

-
- ); - })} -
-
-
- )}
@@ -391,196 +280,7 @@ export default function AccountCreation() { )}
- {/*
- -
*/} -
- - {/*
- -
- -
-
*/} - {/*
-
-
- -
- - -
-
-
- -
- -
-
*/} - {/*
- - {selectedRole.toLowerCase() !== "other" - ? isLoading - ? "Validating..." - : "Next Step" - : isLoading - ? "Validating..." - : "Submit"} + {isLoading ? "Validating..." : "Register"}
@@ -642,7 +336,15 @@ export default function AccountCreation() {

Already have an account?{" "} - Sign In + + Sign In +

diff --git a/src/modules/Common/Authentication/pages/Onboarding/CollegePage/CollegePage.module.css b/src/modules/Common/Authentication/pages/Onboarding/CollegePage/CollegePage.module.css index 2f16e3978..6f649a823 100644 --- a/src/modules/Common/Authentication/pages/Onboarding/CollegePage/CollegePage.module.css +++ b/src/modules/Common/Authentication/pages/Onboarding/CollegePage/CollegePage.module.css @@ -8,6 +8,22 @@ } .wrapper form { width: 20rem; + /* background: rgba(238, 242, 255, 1); + border-radius: 10px; + padding: 20px; */ +} +.input_field { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px; + /* background: #eaeaea; */ + background: #dddddd30; + font-size: 14px; + border-radius: 10px; + margin-top: 20px; + color: rgb(86, 86, 255); + font-weight: 600; } .inputBox { width: 100%; @@ -32,6 +48,8 @@ display: flex; justify-content: center; align-items: center; + margin-top: 20px; + gap: 10px; } .submit button { width: 100%; diff --git a/src/modules/Common/Authentication/pages/Onboarding/CollegePage/CollegePage.tsx b/src/modules/Common/Authentication/pages/Onboarding/CollegePage/CollegePage.tsx index d19c7f946..717600e19 100644 --- a/src/modules/Common/Authentication/pages/Onboarding/CollegePage/CollegePage.tsx +++ b/src/modules/Common/Authentication/pages/Onboarding/CollegePage/CollegePage.tsx @@ -6,28 +6,30 @@ import { FormikTextInputWithoutLabel as SimpleInput } from "@/MuLearnComponents/ import { useEffect, useState } from "react"; import { getColleges, - getDepartments, - getRoles, - submitUserData + getCompanies, + getDepartments } from "../../../services/newOnboardingApis"; import ReactSelect from "react-select"; import { useLocation, useNavigate } from "react-router-dom"; +import OnboardingTemplate from "../../../components/OnboardingTeamplate/OnboardingTemplate"; +import OnboardingHeader from "../../../components/OnboardingHeader/OnboardingHeader"; +import { Switch } from "@chakra-ui/react"; +import { selectOrganization } from "../../../services/onboardingApis"; const inputObject = { - college: "College Name", + organization: "Organization", department: "Department", graduationYear: "Graduation Year" }; const scheme = z.object({ - college: z + organization: z .string() - .required(`${inputObject.college} is Required`) - .min(3, `${inputObject.college} must be at least 3 characters`) - .max(100, `${inputObject.college} must be at most 100 characters`), + .required(`${inputObject.organization} is Required`) + .min(3, `${inputObject.organization} must be at least 3 characters`) + .max(100, `${inputObject.organization} must be at most 100 characters`), department: z .string() - .required(`${inputObject.department} is Required`) .min(2, `${inputObject.department} must be at least 2 characters`) .max(100, `${inputObject.department} must be at most 100 characters`), graduationYear: z @@ -44,22 +46,14 @@ const scheme = z.object({ }) }); -export default function CollegePage({ - selectedRole -}: { - selectedRole: string; -}) { +export default function CollegePage() { const navigate = useNavigate(); - - const location = useLocation(); - let userData: any = location.state as Object; - const [isloading, setIsLoading] = useState(true); const [colleges, setColleges] = useState([{ id: "", title: "" }]); const [departments, setDepartments] = useState([{ id: "", title: "" }]); - const [roles, setRoles] = useState([{ id: "", title: "" }]); - - const [selectedCollege, setSelectedCollege] = useState({ + const [isCollege, setIsCollege] = useState(true); + const [companies, setCompanies] = useState([{ id: "", title: "" }]); + const [selectedOrganization, setSelectedOrganization] = useState({ id: "", title: "" }); @@ -68,10 +62,7 @@ export default function CollegePage({ title: "" }); - const getRoleTitle = (id: string) => { - const slice = roles.filter(val => val.id === id); - if (slice[0]) return slice[0].title; - }; + const ruri = window.location.href.split("=")[1]; const CustomFilter = ( { label, value }: { label: string; value: string }, @@ -79,198 +70,230 @@ export default function CollegePage({ ): boolean => { if (value === "Others") return true; // Always show "Others" option if (!string) return true; - return label.toLowerCase().startsWith(string.toLowerCase()); + return label.toLowerCase().includes(string.toLowerCase()); }; useEffect(() => { - if (userData === undefined || userData === null) { - navigate("/register", { replace: true }); - } else { - getColleges({ - setIsLoading: setIsLoading, - setColleges: setColleges - }); - getDepartments({ - setIsLoading: setIsLoading, - setDepartments: setDepartments - }); - getRoles().then((res: any) => { - setRoles(res); - setIsLoading(false); - }); - } + getColleges({ + setIsLoading: setIsLoading, + setColleges: setColleges + }); + getDepartments({ + setIsLoading: setIsLoading, + setDepartments: setDepartments + }); + getCompanies({ + setIsLoading: setIsLoading, + setCompanies: setCompanies + }); }, []); - - // useEffect(() => { - // setSelectedRole( - // roles.find((role: any) => role.id === userData.role)?.title || "" - // ); - // }, [userData, roles]); const onSubmit = async (values: any) => { - const newUserData: any = { - user: { - full_name: userData.user.full_name, - // mobile: userData.user.mobile, - email: userData.user.email, - password: userData.user.password, - district: userData.district - }, - organization: { - ...(values.department !== "Others" && { - department: values.department - }), - year_of_graduation: values.graduationYear, - organizations: [ - ...(values.college !== "Others" ? [values.college] : []), - ...userData.communities - ], - verified: true - } - }; - - if (selectedRole) newUserData.user["role"] = selectedRole; - - if (userData.referral) - newUserData["referral"] = { muid: userData.referral.muid }; - - if (userData.param) { - newUserData["integration"] = userData.integration; - } - - if (userData.role === "Enabler") - delete newUserData.organization.year_of_graduation; - - if (userData.gender) { - newUserData.user["gender"] = userData.gender; - } - - if (userData.dob) { - newUserData.user["dob"] = userData.dob; - } - console.log(newUserData); - - submitUserData({ + selectOrganization({ setIsLoading: setIsLoading, - userData: newUserData, - navigate: navigate + userData: { + organization: + values.organization == "Others" + ? null + : values.organization, + department: + values.department == "Others" ? null : values.department, + graduation_year: + values.graduationYear == null || values.graduationYear != "" + ? values.graduationYear + : null, + is_student: isCollege + } + }).then(res => { + if (res) { + if (ruri) { + navigate(`/${ruri}`); + } else { + navigate("/dashboard/connect-discord"); + } + } }); }; - // console.log(userData); return ( - [key, ""]) - )} - validationSchema={scheme} - onSubmit={(value, action) => onSubmit(value)} - > - {formik => ( -
-
- -
- Please enter your college details -
-
- ({ - value: college.id, - label: college.title - })) - ] as any - } - name="college" - placeholder="College" - value={selectedCollege.title} - filterOption={CustomFilter} - isDisabled={isloading} - onChange={(e: any) => { - setSelectedCollege(e); - formik.setFieldValue( - "college", - e.value - ); - inputObject.college = e.value; - }} - /> -
- {formik.touched.college && - formik.errors.college && ( - - {formik.errors.college} - - )} -
- ({ - value: department.id, - label: department.title - })) - ] as any - } - name="department" - placeholder="Department" - value={selectedDepartment.title} - isDisabled={isloading} - filterOption={CustomFilter} - onChange={(e: any) => { - setSelectedDepartment(e); - formik.setFieldValue( - "department", - e.value - ); - inputObject.department = e.value; - }} - /> -
- {formik.touched.department && - formik.errors.department && ( - - {formik.errors.department} - - )} - {getRoleTitle(selectedRole) === "Student" && ( + + + [key, ""]) + )} + validationSchema={scheme} + onSubmit={(value, action) => onSubmit(value)} + > + {formik => ( +
+
+ +
+ Please enter your organization details +
+
+ Not a college ?{" "} + { + setIsCollege(!isCollege); + }} + /> +
- ({ + value: college.id, + label: college.title + })) + : companies.map( + company => ({ + value: company.id, + label: company.title + }) + )) + ] as any + } + name="organization" + placeholder={ + isCollege + ? "College" + : "Organization" + } + value={selectedOrganization.title} + filterOption={CustomFilter} + isDisabled={isloading} + onChange={(e: any) => { + setSelectedOrganization(e); + formik.setFieldValue( + "organization", + e.value + ); + inputObject.organization = e.value; + }} /> - {formik.touched.graduationYear && - formik.errors.graduationYear && ( - - {formik.errors.graduationYear} - - )}
- )} + {formik.touched.college && + formik.errors.college && ( + + {formik.errors.college} + + )} + {isCollege ? ( + <> +
+ ({ + value: department.id, + label: department.title + }) + ) + ] as any + } + name="department" + className={styles.inputBox} + placeholder="Department" + value={selectedDepartment.title} + isDisabled={isloading} + filterOption={CustomFilter} + onChange={(e: any) => { + setSelectedDepartment(e); + formik.setFieldValue( + "department", + e.value + ); + inputObject.department = + e.value; + }} + /> +
+ {formik.touched.department && + formik.errors.department && ( + + {formik.errors.department} + + )} +
+ + {formik.touched.graduationYear && + formik.errors + .graduationYear && ( + + { + formik.errors + .graduationYear + } + + )} +
+ + ) : ( + <> + )} -
- - {isloading ? "Please wait..." : "Submit"} - -
- +
+ { + e.preventDefault(); + if (ruri) { + navigate(`/${ruri}`); + } else { + navigate( + "/dashboard/connect-discord" + ); + } + }} + > + Skip + + + {isloading + ? "Please wait..." + : "Submit"} + +
+ +
-
- )} - + )} + + ); } diff --git a/src/modules/Common/Authentication/pages/Onboarding/CompanyPage/CompanyPage.tsx b/src/modules/Common/Authentication/pages/Onboarding/CompanyPage/CompanyPage.tsx index f901ad680..f47c96710 100644 --- a/src/modules/Common/Authentication/pages/Onboarding/CompanyPage/CompanyPage.tsx +++ b/src/modules/Common/Authentication/pages/Onboarding/CompanyPage/CompanyPage.tsx @@ -153,8 +153,8 @@ export default function CompanyPage({ // console.log(newUserData); submitUserData({ setIsLoading: setIsLoading, - userData: newUserData, - navigate: navigate + userData: newUserData + // navigate: navigate }); }; diff --git a/src/modules/Common/Authentication/pages/Onboarding/RolePage/RolePage.tsx b/src/modules/Common/Authentication/pages/Onboarding/RolePage/RolePage.tsx index caa300853..2769a2f8e 100644 --- a/src/modules/Common/Authentication/pages/Onboarding/RolePage/RolePage.tsx +++ b/src/modules/Common/Authentication/pages/Onboarding/RolePage/RolePage.tsx @@ -72,8 +72,8 @@ export default function Rolepage() { submitUserData({ setIsLoading: setIsLoading, - userData: newUserData, - navigate: navigate + userData: newUserData + // navigate: navigate # want to handle this if this page is used in other places }); }; @@ -120,7 +120,7 @@ export default function Rolepage() {
*/} {nextPage && (nextPage === "select-college" ? ( - + ) : ( ))} diff --git a/src/modules/Common/Authentication/pages/Onboarding/SignIn/SignIn.tsx b/src/modules/Common/Authentication/pages/Onboarding/SignIn/SignIn.tsx index 77d3a427f..cff11d47c 100644 --- a/src/modules/Common/Authentication/pages/Onboarding/SignIn/SignIn.tsx +++ b/src/modules/Common/Authentication/pages/Onboarding/SignIn/SignIn.tsx @@ -43,8 +43,6 @@ export default function SignIn() { }); const onSubmit = (values: any) => { - console.log(values); - if (!otpForm) { login( values.emailOrMuId, @@ -153,7 +151,13 @@ export default function SignIn() { diff --git a/src/modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest.module.css b/src/modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest.module.css new file mode 100644 index 000000000..0e9d678cc --- /dev/null +++ b/src/modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest.module.css @@ -0,0 +1,241 @@ +.popUp { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100vh; + backdrop-filter: blur(10px); + background-color: #00000014; + z-index: 100; + display: flex; + justify-content: center; + align-items: center; + + .box { + background-color: #fff; + border-radius: 20px; + padding: 40px 10px 10px; + min-height: 300px; + max-width: 700px; + position: relative; + z-index: 100; + display: flex; + align-items: center; + flex-direction: column; + h1 { + text-align: center; + } + & img { + height: 30px; + } + + & h1 { + font-size: 2rem; + font-weight: 600; + } + + .subText { + margin-top: 10px; + font-size: 1rem; + font-weight: 500; + margin-bottom: 10px; + } + + .itemsContainer { + gap: 1.5rem; + z-index: 10; + cursor: pointer; + display: flex; + flex-wrap: wrap; + padding: 20px; + justify-content: center; + overflow: show; + + .itemsCard { + min-width: 200px; + max-height: 120px; + border-radius: 10px; + background-color: #fff; + box-shadow: 0px 0px 17.65823px 0px rgba(0, 0, 0, 0.07); + display: flex; + align-items: center; + flex-direction: column; + text-align: center; + justify-content: center; + padding: 10px; + position: relative; + transition: all 0.3s ease; + position: relative; + + .infoButton { + position: absolute; + top: 10px; + right: 10px; + padding: 5px; + border-radius: 50%; + cursor: pointer; + color: #456ff6; + z-index: 11; + + &:hover + .interestInfo { + display: flex; + } + } + + .interestInfo { + display: none; + position: absolute; + width: 100%; + height: 100%; + top: 0; + left: 0; + color: #22222290; + font-size: 10px; + background: #ffffff; + border: 1px solid #456ef694; + padding: 10px; + border-radius: 10px; + z-index: 10; + flex-direction: column; + justify-content: start; + gap: 10px; + overflow-x: hidden; + overflow-y: scroll; + + &:hover { + display: flex; + } + + h4 { + font-weight: 800; + text-align: start; + } + ul { + display: flex; + flex-wrap: wrap; + padding: 0; + margin: 0; + li { + text-align: start; + width: auto; + display: inline-block; + padding: 3px; + background: #22222210; + margin: 1px; + border-radius: 5px; + color: black; + } + } + } + .content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100px; + p { + transform: translateY(-90%); + } + } + + &.others { + &.checked { + display: flex; + width: calc(380px + 3rem); + justify-content: space-around; + flex-direction: column; + overflow: visible; + flex-direction: row; + gap: 1rem; + } + } + + .checkmark { + position: absolute; + top: 0px; + left: 0px; + transform: translate(-30%, -30%); + color: #ffffff; + background-color: #456ff6; + border-radius: 50%; + padding: 2px; + z-index: 12; + } + + div { + display: flex; + } + + &:hover { + outline: 1.177px solid #456ff6; + transition: 1s ease; + } + + &.others { + position: relative; + overflow: hidden; + } + + .othersTextBox { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: #fff; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 10px; + transform: translateY(0); + transition: transform 0.3s ease-in-out; + } + + .tagInput { + background: red !important; + width: 100%; + } + .otherInterestInput { + width: 90%; + padding: 8px; + margin-top: 10px; + border: 1px solid #ccc; + border-radius: 4px; + font-size: 14px; + } + } + .active { + outline: 2px solid #456ff6; + } + .itemImage { + margin-top: 1rem; + object-fit: cover; + height: 70px; + width: 70px; + -webkit-user-drag: none; + } + .title { + margin-top: 0.5rem; + font-weight: bold; + } + } + + @media (width<500px) { + .itemsContainer { + .itemsCard { + width: 300px; + flex-direction: column; + &.others { + &.checked { + height: fit-content; + max-height: none; + flex-direction: column; + width: 300px; + } + } + } + } + } + } +} diff --git a/src/modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest.tsx b/src/modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest.tsx new file mode 100644 index 000000000..1f77b1a13 --- /dev/null +++ b/src/modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest.tsx @@ -0,0 +1,313 @@ +import { useEffect, useState, useCallback } from "react"; +import { useNavigate } from "react-router-dom"; +import toast from "react-hot-toast"; +import { TagsInput } from "react-tag-input-component"; + +import OnboardingHeader from "../../../components/OnboardingHeader/OnboardingHeader"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; +import { privateGateway, publicGateway } from "@/MuLearnServices/apiGateways"; +import { onboardingRoutes } from "@/MuLearnServices/urls"; + +import styles from "./UserInterest.module.css"; +import muBrand from "/src/modules/Common/Authentication/assets/µLearn.png"; +import creative from "/src/modules/Common/Authentication/assets/interests/creative.svg"; +import maker from "/src/modules/Common/Authentication/assets/interests/makers.svg"; +import management from "/src/modules/Common/Authentication/assets/interests/management.svg"; +import software from "/src/modules/Common/Authentication/assets/interests/software.svg"; +import others from "/src/modules/Common/Authentication/assets/interests/others.svg"; + +const CheckMark = () => ( + + + +); + +const INITIAL_INTERESTS = [ + { title: "Coder", value: "coder", img: software, checked: false }, + { title: "Hardware", value: "hardware", img: maker, checked: false }, + { title: "Manager", value: "manager", img: management, checked: false }, + { title: "Creative", value: "creative", img: creative, checked: false }, + { title: "Others", value: "others", img: others, checked: false } +]; + +const INITIAL_ENDGOALS = [ + { title: "Job", value: "job", checked: false }, + { title: "Research & Development", value: "r&d", checked: false }, + { title: "Entrepreneurship", value: "entrepreneurship", checked: false }, + { title: "Gig Works", value: "gig_work", checked: false }, + { title: "Higher Education", value: "higher_education", checked: false }, + { title: "Others", value: "others", checked: false } +]; + +type InterestGroup = { + id: string; + name: string; + category: string; +}; + +type InterestGroups = { + [key: string]: InterestGroup[]; +}; + +export default function UserInterest() { + const [interests, setInterests] = useState(INITIAL_INTERESTS); + const [endgoals, setEndgoals] = useState(INITIAL_ENDGOALS); + const [otherInterest, setOtherInterest] = useState([]); + const [otherEndgoal, setOtherEndgoal] = useState([]); + const [stepTwo, setStepTwo] = useState(false); + const [interestGroups, setInterestGroups] = useState({}); + const navigate = useNavigate(); + const ruri = window.location.href.split("=")[1]; + + useEffect(() => { + const fetchInterestGroups = async () => { + try { + const res = await publicGateway.get( + onboardingRoutes.interestGroups + ); + const data: InterestGroup[] = + res.data?.response?.interestGroup ?? []; + + const interestGroupsData = interests.reduce( + (acc, interest) => ({ + ...acc, + [interest.value]: data.filter( + group => group.category === interest.value + ) + }), + {} + ); + + setInterestGroups(interestGroupsData); + } catch (err) { + console.error("Failed to fetch interest groups:", err); + } + }; + + fetchInterestGroups(); + }, []); + + const handleChange = useCallback((value: string, isInterest: boolean) => { + const setter = isInterest ? setInterests : setEndgoals; + const otherSetter = isInterest ? setOtherInterest : setOtherEndgoal; + + setter((prev: any) => { + const newItems = prev.map((item: any) => + item.value === value + ? { ...item, checked: !item.checked } + : item + ); + + if ( + value === "others" && + newItems.find((item: any) => item.value === "others") + ?.checked === false + ) { + otherSetter([]); + } + + return newItems; + }); + }, []); + + const handleContinue = useCallback(() => { + const selectedInterests = interests.filter( + interest => interest.checked + ); + if ( + selectedInterests.some(i => i.value === "others") && + otherInterest.length === 0 + ) { + return; + } + if (selectedInterests.length > 0 || otherInterest.length > 0) { + setStepTwo(true); + } + }, [interests, otherInterest]); + + const handleSubmit = useCallback(async () => { + const selectedInterests = interests + .filter(i => i.checked) + .map(i => i.value); + const selectedEndgoals = endgoals + .filter(e => e.checked) + .map(e => e.value); + + const data = { + choosen_interests: selectedInterests, + choosen_endgoals: selectedEndgoals, + other_interests: otherInterest, + other_endgoals: otherEndgoal + }; + + try { + const res = await privateGateway.post( + onboardingRoutes.interests, + data + ); + toast.success(res.data?.message.general[0]); + navigate( + ruri + ? `/register/organization/?ruri=${ruri}` + : "/register/organization" + ); + } catch (err: any) { + toast.error( + err.response?.data.message.general[0] || + "Unexpected Error occurred" + ); + } + }, [interests, endgoals, otherInterest, otherEndgoal, navigate]); + + const isInterestSelected = interests.some(interest => interest.checked); + const isEndgoalSelected = endgoals.some(endgoal => endgoal.checked); + + const renderItems = useCallback( + (items: typeof interests | typeof endgoals, isInterest: boolean) => ( +
+ {items.map(item => { + const isOthers = item.value === "others"; + const isChecked = item.checked; + const otherItems = isInterest + ? otherInterest + : otherEndgoal; + const setOtherItems = isInterest + ? setOtherInterest + : setOtherEndgoal; + + return ( +
handleChange(item.value, isInterest)} + > + {isChecked && } + {isInterest ? ( +
+ +

{item.title}

+
+ ) : ( +

{item.title}

+ )} + {isInterest && ( + <> +
e.stopPropagation()} + > + + + + +
+
+

This category includes:

+
    + {interestGroups[item.value]?.map( + (group: InterestGroup) => ( +
  • + {group.name} +
  • + ) + )} +
+
+ + )} + {isOthers && isChecked && ( +
e.stopPropagation()}> + { + if (e.target.value.length > 0) { + setOtherItems([ + ...otherItems, + e.target.value + ]); + e.target.value = ""; + } + }} + onChange={setOtherItems} + name={`other_${ + isInterest + ? "interests" + : "endgoals" + }`} + placeHolder={`Specify your ${ + isInterest ? "interest" : "endgoal" + }`} + separators={ + isInterest ? [","] : undefined + } + /> +
+ )} +
+ ); + })} +
+ ), + [handleChange, interestGroups, otherInterest, otherEndgoal] + ); + + return ( + <> + +
+
+ mulearn +

+ {stepTwo + ? "What do you expect by MuLearning " + : "What describes you the most!"} +

+

+ {stepTwo + ? "Pick your goal." + : "Please select your interested area"} +

+ + {stepTwo + ? renderItems(endgoals, false) + : renderItems(interests, true)} + + {(stepTwo ? isEndgoalSelected : isInterestSelected) && ( + + Continue + + )} +
+
+ + ); +} diff --git a/src/modules/Common/Authentication/pages/ResetPassword.tsx b/src/modules/Common/Authentication/pages/ResetPassword.tsx index f9a67cee7..c5e282cce 100644 --- a/src/modules/Common/Authentication/pages/ResetPassword.tsx +++ b/src/modules/Common/Authentication/pages/ResetPassword.tsx @@ -20,7 +20,6 @@ const ResetPassword = (props: Props) => { useEffect(() => { const paramToken = searchParams.get("token"); setToken(paramToken as string); - console.log(token); if (token.length > 0 && muid.length === 0) { getMuid(token, navigate, setMuID); } diff --git a/src/modules/Common/Authentication/services/newOnboardingApis.ts b/src/modules/Common/Authentication/services/newOnboardingApis.ts index dab1c8948..cdd59daa6 100644 --- a/src/modules/Common/Authentication/services/newOnboardingApis.ts +++ b/src/modules/Common/Authentication/services/newOnboardingApis.ts @@ -4,7 +4,6 @@ import { KKEMRoutes, onboardingRoutes } from "@/MuLearnServices/urls"; import { Dispatch, SetStateAction } from "react"; import { NavigateFunction } from "react-router-dom"; -import { bool, boolean } from "yup"; import { getInfo } from "../../../Dashboard/modules/ConnectDiscord/services/apis"; import { DWMSDetails } from "./onboardingApis"; import toast from "react-hot-toast"; @@ -53,7 +52,7 @@ export const createAccount = async ({ const tokens = response.data.response; localStorage.setItem("accessToken", tokens.accessToken); localStorage.setItem("refreshToken", tokens.refreshToken); - getInfo(() => { + getInfo(navigate, () => { navigate("/role"); }); } catch (err: any) { @@ -148,12 +147,10 @@ export const getCompanies = async ({ export const submitUserData = async ({ setIsLoading, - userData, - navigate + userData }: { setIsLoading: Dispatch>; userData: Object; - navigate: NavigateFunction; }) => { console.log("UserData", userData); try { @@ -165,13 +162,14 @@ export const submitUserData = async ({ const tokens = res.data.response; localStorage.setItem("accessToken", tokens.accessToken); localStorage.setItem("refreshToken", tokens.refreshToken); - getInfo(() => navigate("/dashboard/connect-discord")); + return true; } catch (err: any) { setIsLoading(false); const messages = err.response.data.message.general[0]; showToasts({ messages: messages }); + return false; } }; diff --git a/src/modules/Common/Authentication/services/onboardingApis.ts b/src/modules/Common/Authentication/services/onboardingApis.ts index da54fe365..75ec01e5e 100644 --- a/src/modules/Common/Authentication/services/onboardingApis.ts +++ b/src/modules/Common/Authentication/services/onboardingApis.ts @@ -4,6 +4,8 @@ import { NavigateFunction } from "react-router-dom"; import { useFormik } from "formik"; import { getInfo } from "../../../Dashboard/modules/ConnectDiscord/services/apis"; import { Dispatch, SetStateAction } from "react"; +import { privateGateway } from "@/MuLearnServices/apiGateways"; +import toast from "react-hot-toast"; // Define the type of MyValues type NN = { name: string; id: string }; @@ -234,6 +236,32 @@ export const getCommunities = ({ setIsLoading && setIsLoading(false); }; +export const selectOrganization = async ({ + setIsLoading, + userData +}: { + setIsLoading: Dispatch>; + userData: Object; +}) => { + try { + setIsLoading(true); + const res = await privateGateway.post( + "/api/v1/dashboard/user/organization/", + userData + ); + if (res.status == 200 && !res.data.hasError) { + toast.success(res.data.message.general[0]); + return true; + } else { + toast.error("Organization selection failed."); + } + setIsLoading(false); + } catch (err: any) { + toast.error("Unable to select organization."); + } + return false; +}; + // POST request for registration export const registerUser = ( setFormSuccess: FormSuccess, @@ -259,7 +287,7 @@ export const registerUser = ( "refreshToken", response.data.response.refreshToken ); - getInfo(() => { + getInfo(navigate, () => { navigate("/dashboard/connect-discord"); setShowSubmitLoader(false); }); diff --git a/src/modules/Dashboard/components/SideNavBarBody.tsx b/src/modules/Dashboard/components/SideNavBarBody.tsx index 434b45f9b..48992a133 100644 --- a/src/modules/Dashboard/components/SideNavBarBody.tsx +++ b/src/modules/Dashboard/components/SideNavBarBody.tsx @@ -54,16 +54,15 @@ const SideNavBarBody = ({ .filter( button => button.hasView && - ((!button.roles || + (!button.roles || button.roles?.some(role => userInfo?.roles?.includes(role) + ) || + button.dynamicType?.some(type => + userInfo?.dynamic_type?.includes( + type as ManagementTypes + ) )) - || - ( - button.dynamicType?.some(type => - userInfo?.dynamic_type?.includes(type as ManagementTypes) - )) - ) ) .map((button, i) => button.children ? ( @@ -87,12 +86,12 @@ const SideNavBarBody = ({ userInfo?.roles?.includes( role ) - ) - || - ( - button.dynamicType?.some(type => - userInfo?.dynamic_type?.includes(type as ManagementTypes) - ))) + ) || + button.dynamicType?.some(type => + userInfo?.dynamic_type?.includes( + type as ManagementTypes + ) + )) ) .map((button, i) => button.children ? ( @@ -110,7 +109,7 @@ const SideNavBarBody = ({ } display={ level2dropDownDisplay === - button.title + button.title ? "max-content" : "0" } @@ -124,12 +123,13 @@ const SideNavBarBody = ({ userInfo?.roles?.includes( role ) - ) - || - ( - button.dynamicType?.some(type => - userInfo?.dynamic_type?.includes(type as ManagementTypes) - ))) + ) || + button.dynamicType?.some( + type => + userInfo?.dynamic_type?.includes( + type as ManagementTypes + ) + )) ) .map((button, i) => ( { url: "/dashboard/interest-groups", title: "Interest Groups", hasView: true, - roles: [roles.ADMIN] + roles: [roles.ADMIN, roles.FELLOW] // icon: }, + { + url: "/dashboard/lc-meetup-verification", + title: "LC Meetup Verification", + hasView: true, + roles: [roles.ADMIN] + }, { url: "/dashboard/college-levels", title: "College Levels", diff --git a/src/modules/Dashboard/modules/ConnectDiscord/pages/ConnectDiscord.module.css b/src/modules/Dashboard/modules/ConnectDiscord/pages/ConnectDiscord.module.css index 80bf723e4..c6ea822cb 100644 --- a/src/modules/Dashboard/modules/ConnectDiscord/pages/ConnectDiscord.module.css +++ b/src/modules/Dashboard/modules/ConnectDiscord/pages/ConnectDiscord.module.css @@ -15,6 +15,7 @@ justify-content: space-evenly; background: #fff; /* border: 1px solid #dde2e5; */ + min-height: 250px; border-radius: 20px; overflow: hidden; font-weight: 500; diff --git a/src/modules/Dashboard/modules/ConnectDiscord/pages/ConnectDiscord.tsx b/src/modules/Dashboard/modules/ConnectDiscord/pages/ConnectDiscord.tsx index 2e3bfb133..d41d6c8e5 100644 --- a/src/modules/Dashboard/modules/ConnectDiscord/pages/ConnectDiscord.tsx +++ b/src/modules/Dashboard/modules/ConnectDiscord/pages/ConnectDiscord.tsx @@ -1,17 +1,22 @@ import { useEffect, useRef, useState } from "react"; import styles from "./ConnectDiscord.module.css"; import cdimage from "../assets/images/connectdiscordpng1.webp"; -import { getInfo } from "../services/apis"; +import { connectDiscord, getInfo } from "../services/apis"; import { MdContentCopy } from "react-icons/md"; import { BsDiscord } from "react-icons/bs"; import MuLoader from "@/MuLearnComponents/MuLoader/MuLoader"; import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; import { FaInstagram } from "react-icons/fa6"; import toast from "react-hot-toast"; +import { useNavigate, useSearchParams } from "react-router-dom"; const ConnectDiscord = () => { const [muid, setMuid] = useState(""); const firstFetch = useRef(true); + const [searchParams, _] = useSearchParams(); + const token = searchParams.get("code"); + const [discordStatus, setDiscordStatus] = useState("connecting"); + const navigate = useNavigate(); useEffect(() => { if (firstFetch.current) { if ( @@ -20,68 +25,100 @@ const ConnectDiscord = () => { ) { setMuid(JSON.parse(localStorage.getItem("userInfo")!).mu_id); } else { - getInfo(setMuid); + getInfo(navigate, setMuid); } } firstFetch.current = false; }, []); + useEffect(() => { + if (token) { + connectDiscord(token).then(res => { + if (res) { + setDiscordStatus("connected"); + navigate("/dashboard/profile"); + toast.success( + "You will be added to our discord server shortly" + ); + setTimeout(() => { + var a = document.createElement("a"); + a.href = + "https://discord.gg/gtech-mulearn-771670169691881483"; + a.target = "_blank"; + a.click(); + }, 5000); + } else { + setDiscordStatus("failed"); + } + }); + } + }, []); + return ( <> - {muid && muid.length > 0 ? ( -
-
-
-

Join Discord using your µid

-

- To join our discord server you need to connect - your account with discord. To do so you need to - copy your µid and paste it in the discord - server. -

-
- { - navigator.clipboard.writeText(muid); - - toast.success( - "Copied to clipboard, Please paste it in discord to connect your account" - ); - }} - > - - {muid} - - - - - Connect Discord - - - - -

- Follow Us + {token == null ? ( + <> + {muid && muid.length > 0 ? ( +

+
+
+

Join Discord using your µid

+

+ To join our discord server you need to + connect your account with discord. To do + so you need to copy your µid and paste + it in the discord server.

-
+
+ { + navigator.clipboard.writeText( + muid + ); + + toast.success( + "Copied to clipboard, Please paste it in discord to connect your account" + ); + }} + > + + {muid} + + + + + Join Discord + + + + +

+ Follow Us +

+
+
+
+
-
- -
-
+ {/*

Onboarding Flow

@@ -128,14 +165,46 @@ const ConnectDiscord = () => {

-
-
- ) : ( +
*/} +
+ ) : ( +
+
+ {" "} +
+
+ )} + + ) : discordStatus == "connecting" ? (
{" "}
+ ) : discordStatus == "connected" ? ( +
+
+
+

Discord Connected

+

+ Your account has been successfully connected to + discord. +

+
+
+
+ ) : ( +
+
+
+

Discord Connection Failed

+

+ Your account could not be connected to discord. + Please try again later. +

+
+
+
)} ); diff --git a/src/modules/Dashboard/modules/ConnectDiscord/services/apis.ts b/src/modules/Dashboard/modules/ConnectDiscord/services/apis.ts index 476b64238..974e7fd43 100644 --- a/src/modules/Dashboard/modules/ConnectDiscord/services/apis.ts +++ b/src/modules/Dashboard/modules/ConnectDiscord/services/apis.ts @@ -1,9 +1,33 @@ import { privateGateway } from "@/MuLearnServices/apiGateways"; -import { dashboardRoutes } from "@/MuLearnServices/urls"; +import { dashboardRoutes, onboardingRoutes } from "@/MuLearnServices/urls"; +import toast from "react-hot-toast"; +import { NavigateFunction } from "react-router-dom"; type muid = UseStateFunc; - -export const getInfo = (setMuid?: muid, onComplete?: Function) => { +export const connectDiscord = async (code: string) => { + try { + return await privateGateway + .get(onboardingRoutes.connectDiscord, { + params: { + code + } + }) + .then(response => { + return response.status === 200; + }) + .catch(err => { + console.log(err); + return false; + }); + } catch (err: any) { + return false; + } +}; +export const getInfo = ( + navigate: NavigateFunction, + setMuid?: muid, + onComplete?: Function +) => { privateGateway .get(dashboardRoutes.getInfo) .then((response: APIResponse) => { @@ -11,6 +35,10 @@ export const getInfo = (setMuid?: muid, onComplete?: Function) => { "userInfo", JSON.stringify(response.data.response) ); + if (response.data.response?.interest_selected) { + toast.error(response.data.response?.interest_selected); + navigate("/register/interests"); + } if (setMuid) setMuid(response.data.response.muid); if (onComplete) onComplete(); }) diff --git a/src/modules/Dashboard/modules/InterestGroup/InterestGroup.tsx b/src/modules/Dashboard/modules/InterestGroup/InterestGroup.tsx index 52ebf9975..511466d95 100644 --- a/src/modules/Dashboard/modules/InterestGroup/InterestGroup.tsx +++ b/src/modules/Dashboard/modules/InterestGroup/InterestGroup.tsx @@ -5,23 +5,20 @@ import THead from "@/MuLearnComponents/Table/THead"; import TableTop from "@/MuLearnComponents/TableTop/TableTop"; import { deleteInterestGroups, getInterestGroups } from "./apis"; import { useNavigate } from "react-router-dom"; -import { - MuButton, - PowerfulButton -} from "@/MuLearnComponents/MuButtons/MuButton"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; import { AiOutlinePlusCircle } from "react-icons/ai"; import styles from "./InterestGroup.module.css"; import { dashboardRoutes } from "@/MuLearnServices/urls"; import { Blank } from "@/MuLearnComponents/Table/Blank"; -import CreateOrUpdateModal from "./CreateOrUpdateModal"; import MuModal from "@/MuLearnComponents/MuModal/MuModal"; import InterestGroupForm from "./InterestGroupForm"; +import { Label } from "recharts"; -interface IgDetails { - igName: string; - igCode: string; - igIcon: string; -} +// interface IgDetails { +// igName: string; +// igCode: string; +// igIcon: string; +// } export type modalTypes = "edit" | "create" | null; @@ -38,6 +35,7 @@ function InterestGroup() { const columnOrder = [ { column: "name", Label: "Name", isSortable: true }, { column: "members", Label: "Members", isSortable: true }, + { column: "category", Label: "Category", isSortable: true }, { column: "updated_at", Label: "Updated On", isSortable: true }, { column: "updated_by", Label: "Updated By", isSortable: true }, { column: "created_by", Label: "Created By", isSortable: true }, diff --git a/src/modules/Dashboard/modules/InterestGroup/InterestGroupForm.tsx b/src/modules/Dashboard/modules/InterestGroup/InterestGroupForm.tsx index 846d552e5..196aac755 100644 --- a/src/modules/Dashboard/modules/InterestGroup/InterestGroupForm.tsx +++ b/src/modules/Dashboard/modules/InterestGroup/InterestGroupForm.tsx @@ -1,8 +1,9 @@ import { forwardRef, useEffect, useImperativeHandle, useState } from "react"; import styles from "../../utils/modalForm.module.css"; import toast from "react-hot-toast"; -import { customReactSelectStyles } from "../../utils/common"; import { createInterestGroups, editInterestGroups, getIGDetails } from "./apis"; +import ReactSelect from "react-select"; +import styles2 from "./InterestGroupFrom.module.css"; type Props = { id: string; isEditMode: boolean }; @@ -11,8 +12,19 @@ const IntrestGroupForm = forwardRef( const [data, setData] = useState({ name: "", icon: "", - code: "" + code: "", + category: "others" }); + const interestGroup = [ + { label: "Coder", value: "coder" }, + { label: "Hardware", value: "hardware" }, + { + label: "Manager", + value: "manager" + }, + { label: "Creative", value: "creative" }, + { label: "Others", value: "others" } + ]; const [errors, setErrors] = useState({}); @@ -23,7 +35,8 @@ const IntrestGroupForm = forwardRef( setData({ name: data.name, icon: data.icon, - code: data.code + code: data.code, + category: data.category }); }); } @@ -142,6 +155,23 @@ const IntrestGroupForm = forwardRef(
{errors.icon}
)}
+ { + setData(prevData => ({ + ...prevData, + category: e?.value as string + })); + }} + value={ + interestGroup.filter(e => { + console.log(e.value, data.category); + return e.value === data.category; + })[0] + } + /> ); diff --git a/src/modules/Dashboard/modules/InterestGroup/InterestGroupFrom.module.css b/src/modules/Dashboard/modules/InterestGroup/InterestGroupFrom.module.css new file mode 100644 index 000000000..a8f60d990 --- /dev/null +++ b/src/modules/Dashboard/modules/InterestGroup/InterestGroupFrom.module.css @@ -0,0 +1,3 @@ +.inputBox { + width: 45%; +} diff --git a/src/modules/Dashboard/modules/InterestGroup/InterestGroupInterface.d.ts b/src/modules/Dashboard/modules/InterestGroup/InterestGroupInterface.d.ts index 743373b74..11c0f0436 100644 --- a/src/modules/Dashboard/modules/InterestGroup/InterestGroupInterface.d.ts +++ b/src/modules/Dashboard/modules/InterestGroup/InterestGroupInterface.d.ts @@ -2,4 +2,5 @@ interface IGData { name: string; code: string; icon: string; + category: string; } diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcAdmin/LcAdmin.module.css b/src/modules/Dashboard/modules/LearningCircle/pages/LcAdmin/LcAdmin.module.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcAdmin/LcAdmin.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcAdmin/LcAdmin.tsx new file mode 100644 index 000000000..39b53d419 --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcAdmin/LcAdmin.tsx @@ -0,0 +1,96 @@ +import Pagination from "@/MuLearnComponents/Pagination/Pagination"; +import Table, { Data } from "@/MuLearnComponents/Table/Table"; +import THead from "@/MuLearnComponents/Table/THead"; +import { dashboardRoutes } from "@/MuLearnServices/urls"; +import { ReactJSXElement } from "@emotion/react/types/jsx-namespace"; +import { ReactElement, useEffect, useState } from "react"; +import { getVerifiableMeetups } from "../../services/LearningCircleAPIs"; + +const LcAdmin = () => { + const [isLoading, setIsLoading] = useState(false); + const [data, setData] = useState([]); + const [currentPage, setCurrentPage] = useState(1); + const [totalPages, setTotalPages] = useState(1); + const [perPage, setPerPage] = useState(20); + const [sort, setSort] = useState(""); + + useEffect(() => { + setIsLoading(true); + getVerifiableMeetups().then(res => { + console.log(res); + setData(res); + setIsLoading(false); + }); + }, []); + + const columnOrder: { + column: string; + Label: string; + isSortable: boolean; + wrap?: ( + data: string | ReactElement, + id: string, + row: Data + ) => ReactJSXElement; + }[] = [ + { + column: "learning_circle", + Label: "Learning Circle", + isSortable: false + }, + { column: "title", Label: "Meetup Title", isSortable: false }, + { column: "join_count", Label: "Join Count", isSortable: false }, + { + column: "interested_count", + Label: "Interest Count", + isSortable: false + }, + { + column: "report_submitted_attendees", + Label: "Report Submitted Attendees", + isSortable: false + }, + { + column: "held_on", + Label: "Started At", + isSortable: false + } + ]; + return ( + <> + {}} + > + {}} + action={false} + /> +
+ {!isLoading && ( + {}} + handlePreviousClick={() => {}} + onSearchText={() => {}} + onPerPageNumber={() => {}} + perPage={perPage} + setPerPage={setPerPage} + /> + )} +
+ {/*use when u don't need or cause
needs atleast 2 children*/} +
+ + ); +}; + +export default LcAdmin; diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.module.css b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.module.css index 732f9f094..ec3342014 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.module.css +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.module.css @@ -133,10 +133,11 @@ display: flex; align-items: flex-start; justify-content: space-between; + flex-direction: column; width: 100%; background-color: white; padding: 5%; - gap: 10px; + gap: 20px; height: 100%; } .ReportWrapper .DetailSection { @@ -146,6 +147,86 @@ justify-content: space-between; gap: 20px; width: 65%; + + .tasks { + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; + width: 100%; + h4 { + text-align: start; + font-size: 18px; + font-weight: 500; + } + p { + font-size: 15px; + text-align: start; + font-weight: 400; + color: #3d5c9b; + margin-bottom: 10px; + } + .task { + width: 100%; + background: #fff; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.15); + border-radius: 10px; + padding: 10px 20px; + display: flex; + flex-direction: column; + align-items: start; + justify-content: center; + .taskTitle { + font-size: 18px; + font-weight: 600; + gap: 10px; + display: flex; + align-items: center; + } + .taskPow { + display: none; + width: 100%; + flex-direction: row; + align-items: center; + justify-content: center; + gap: 10px; + .choosenFile { + display: none; + align-items: center; + gap: 10px; + &.active { + display: flex; + } + .file { + font-size: 15px; + font-weight: 600; + color: #456ff6; + display: flex; + align-items: center; + gap: 5px; + .icon { + font-size: 20px; + } + } + .delete { + color: red; + font-size: 15px; + font-weight: 600; + cursor: pointer; + } + } + &.active { + display: flex; + } + .input { + width: 100%; + clip-path: none; + padding: 20px 10px; + border-radius: 5px; + } + } + } + } } .ReportWrapper .DetailSection .Sectionone { display: flex; @@ -161,7 +242,6 @@ width: 45%; } .ReportWrapper .DetailSection .Sectionone > div label { - color: black; font-size: 18px; font-weight: 600; } @@ -187,10 +267,49 @@ gap: 10px; } .ReportWrapper .DetailSection .SectionTwo p { - color: black; font-size: 18px; font-weight: 600; } + +.input_switch { + width: calc(100% - 20px); + background: #fff; + padding: 20px; + border-radius: 10px; + display: flex; + justify-content: space-between; + align-items: end; + margin: 10px; + .label { + font-size: 15px; + } +} + +.input_field { + background: #fff; + padding: 20px; + border-radius: 10px; + margin: 10px; + label.label { + display: block; + width: 100%; + text-align: left; + margin: 0 0 10px 0; + } + textarea { + width: 100%; + background-color: rgba(238, 242, 255, 1); + min-height: 130px; + border-radius: 10px; + padding: 10px; + } + .error_message { + color: rgb(246, 45, 45); + font-size: 12px !important; + margin-top: 10px; + text-align: start; + } +} .ReportWrapper .DetailSection .SectionTwo textarea { width: 100%; background-color: rgba(238, 242, 255, 1); @@ -204,6 +323,77 @@ width: 100%; gap: 10px; align-items: flex-start; + + .attendees { + width: 100%; + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; + .attendee { + width: 100%; + display: flex; + gap: 10px; + padding: 15px; + background-color: rgba(238, 242, 255, 1); + align-items: center; + justify-content: space-between; + border-radius: 10px; + font-size: 17px; + font-weight: 600; + cursor: pointer; + h4 { + font-size: 13px; + font-weight: 700; + } + .ratingHeading { + width: 100%; + display: flex; + justify-content: space-between; + align-items: center; + .fullname { + display: flex; + align-items: center; + gap: 10px; + } + .rating { + display: flex; + align-items: center; + justify-content: center; + color: #456ff6; + } + } + .proof { + display: none; + flex-direction: column; + align-items: start; + width: 100%; + background: #fff; + padding: 10px; + border-radius: 10px; + &.active { + display: flex; + } + .reportText { + font-size: 13px; + color: #22222290; + } + .task { + width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; + gap: 10px; + align-items: center; + padding: 10px; + background: #fff; + box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.15); + border-radius: 5px; + font-weight: 500; + } + } + } + } } .ReportWrapper .DetailSection .SectionThree > p { color: black; @@ -318,6 +508,17 @@ display: flex; flex-direction: column; gap: 10px; + + .title { + font-size: 15px; + font-weight: 600; + margin-bottom: 20px; + color: #ddddddf8; + text-align: left; + width: fit-content; + padding-bottom: 10px; + border-bottom: 1px solid #ddddddf8; + } } .loading { @@ -365,25 +566,98 @@ align-items: flex-start; } .HistoryDataWrapper .Headings { - width: 38%; + width: 43%; + text-align: left; + .qrcode { + width: 100%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + margin: 10px; + gap: 10px; + img { + padding: 20px; + background: white; + border-radius: 10px; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.15); + } + } } .HistoryDataWrapper .detailedSection { - width: 60%; + width: 55%; } .HistoryDataWrapper .SectionBottom .Headings > div { display: flex; flex-wrap: wrap; gap: 5px; } +.Headings { + .info { + padding: 10px; + background: #dddddd50; + border-radius: 10px; + margin: 10px 0; + } + .meetupTags { + display: flex; + flex-direction: row !important; + flex-wrap: wrap; + width: 100%; + + .meetupInfoTag { + font-size: 13px; + display: flex; + gap: 10px; + align-items: center; + justify-content: start; + padding: 5px 10px; + background-color: white; + color: #456ff6; + border: 1px dashed #456ff6; + border-radius: 10px; + margin: 5px; + } + } +} + .HistoryDataWrapper .SectionBottom .detailedSection { display: flex !important; flex-direction: row; flex-wrap: wrap; } -.HistoryDataWrapper .SectionBottom .detailedSection img { - height: 280px; - width: 460px; - object-fit: cover; +.detailedSection { + .tasks { + display: flex; + flex-direction: column; + gap: 10px; + width: 100%; + width: 100%; + color: black; + .task { + width: 100%; + display: flex; + flex-direction: row; + justify-content: start; + gap: 10px; + align-items: center; + padding: 10px; + background-color: rgba(238, 242, 255, 1); + border-radius: 10px; + font-size: 15px; + span { + font-size: 17px; + font-weight: 900; + padding-right: 10px; + border-right: 1px solid #dddddd; + } + } + } + .HistoryDataWrapper .SectionBottom .detailedSection img { + height: 280px; + width: 460px; + object-fit: cover; + } } @media screen and (max-width: 1000px) { .HistoryDataWrapper .Headings, @@ -422,7 +696,7 @@ display: flex; width: 100%; justify-content: space-between; - gap: 2%; + gap: 20px; flex-wrap: wrap; } @@ -495,7 +769,7 @@ .ContainerWrapper .ContentWrapper .BottomContainer { display: flex; flex-direction: column; - width: 100%; + width: 68%; gap: 10px; } .ContainerWrapper .ContentWrapper .BottomContainer > div { @@ -515,6 +789,9 @@ .ContainerWrapper .ContentWrapper .TopContainer .sectionOne { width: 100%; } + .ContainerWrapper .ContentWrapper .TopContainer .BottomContainer { + width: 100%; + } .ContainerWrapper .ContentWrapper .TopContainer { gap: 15px; } @@ -703,6 +980,9 @@ input[type="time"]::-webkit-calendar-picker-indicator { .ScheduleOn { text-align: center; + margin-bottom: 10px; + padding-bottom: 10px; + border-bottom: 1px solid var(--grey); } .ScheduleOn b { @@ -744,7 +1024,7 @@ input[type="time"]::-webkit-calendar-picker-indicator { flex-wrap: wrap; } -.dateandtime input[type="time"] { +.dateandtime input[type="datetime-local"] { padding: 0px 10px; border-radius: 6px; width: 47%; @@ -1125,3 +1405,237 @@ input[type="time"]::-webkit-calendar-picker-indicator { text-align: left; color: #1d1d1d; } + +.ContainerWrapper .ContentWrapper .TopContainer .sectionOne { + .meetups { + display: flex; + flex-direction: column; + gap: 10px; + .meetup { + background: #fff; + padding: 10px; + width: 100%; + border-radius: 10px; + .meetupStatusBar { + display: flex; + justify-content: space-between; + align-items: center; + gap: 10px; + width: 100%; + .date { + font-size: 15px; + font-weight: 800; + display: flex; + align-items: end; + gap: 5px; + justify-content: start; + + span { + width: 20px; + height: 20px; + display: inline-flex; + align-items: center; + justify-content: center; + svg { + width: 15px; + height: 15px; + } + } + } + .status { + font-size: 12px; + font-weight: 600; + &.ongoing { + color: var(--green); + } + &.upcoming { + color: var(--blue); + } + } + } + .meetupDetails { + display: flex; + justify-content: space-between; + align-items: start; + flex-direction: column; + gap: 10px; + background: #22222205; + padding: 20px; + margin: 20px 10px; + border-radius: 5px; + text-align: left; + .title { + font-size: 18px; + font-weight: 800; + } + .agenda { + font-size: 15px; + font-weight: 600; + color: #1d1d1d; + } + .venue { + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; + align-items: start; + .venueHead { + font-size: 15px; + font-weight: 800; + color: #1d1d1d; + } + .actions { + width: 100%; + display: flex; + align-items: center; + gap: 10px; + justify-content: end; + } + .meetupVenue { + margin: 10px 0; + padding: 10px 10px; + background: #fff; + border-radius: 5px; + display: flex; + align-items: center; + gap: 5px; + width: 100%; + flex-direction: column; + + .head { + font-size: 15px; + font-weight: 900; + border-bottom: 1px solid #1d1d1d; + color: #1d1d1d; + } + .venueLink { + font-size: 15px; + font-weight: 600; + color: var(--blue); + background: #dddddd90; + padding: 2px 10px; + border-radius: 5px; + width: 100%; + } + } + } + } + } + } +} + +.inputBox input, +.inputBox select { + border: none; + background: rgba(239, 241, 249, 0.6); + border-radius: 6px; + padding: 10px; + outline: none; + width: 100%; + margin-top: 10px; +} + +.imageBox { + position: relative; + + div { + color: #456ff6; + position: absolute; + top: 0; + display: flex; + align-items: center; + right: 5%; + height: 110%; + + &:active { + transform: scale(0.9); + } + } +} + +.imageBox input::file-selector-button { + background-color: rgb(69, 111, 246); + color: white; + border: none; + border-radius: 0.25rem; + padding: 0.25rem; +} + +.label { + font-weight: 600; + margin-top: 5px; + color: var(--black); + text-align: left; +} + +.powerfulButton:hover { + color: hsl(var(--primary-btn-color)); +} + +.powerfulButton { + height: 50px; +} + +.input_field { + .inputBox { + .tasks { + display: flex; + gap: 10px; + align-items: center; + justify-content: center; + button { + height: fit-content; + padding: 12px; + background: var(--blue); + border-radius: 10px; + color: #fff; + } + } + } + .addedTasks { + display: flex; + justify-content: space-between; + flex-direction: column; + gap: 10px; + align-items: center; + + .task { + display: flex; + justify-content: space-between; + width: 100%; + font-size: 13px; + align-items: center; + padding: 10px; + background: #dddddd50; + border-radius: 10px; + justify-content: center; + div { + display: flex; + flex-direction: row; + align-items: center; + width: 100%; + gap: 10px; + span { + font-size: 15px; + font-weight: 900; + } + p { + font-size: 15px !important; + font-weight: 500; + } + } + } + .taskAdd { + background: var(--blue); + height: fit-content; + padding: 12px; + border-radius: 10px; + color: #fff; + } + } +} +/* @media (max-width: 1500px) { + .edit_profile_container { + left: unset; + } +} */ diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.tsx index 5d3a551a3..29b846bf5 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.tsx +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.tsx @@ -9,7 +9,6 @@ import MuLoader from "@/MuLearnComponents/MuLoader/MuLoader"; import { comingSoon } from "../../../../utils/common"; import LcTeam from "./components/LcTeam"; import LcHome from "./components/LcHome"; -import LcProgress from "./components/LcProgress"; const LcDashboard = () => { const [lc, setLc] = useState(); @@ -19,7 +18,8 @@ const LcDashboard = () => { isHistory: false, isTeam: false, isSchedule: false, - reRender: false + reRender: false, + isCreateMeeting: false }); const [tab, setTab] = useState<"Dashboard">("Dashboard"); @@ -39,7 +39,7 @@ const LcDashboard = () => { useEffect(() => { handleFetchDetails(); - }, [temp.isSchedule, temp.isTeam, temp.reRender]); + }, [temp.isTeam, temp.reRender]); return temp.loading ? ( diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcAttendeeReport.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcAttendeeReport.tsx new file mode 100644 index 000000000..589c7a622 --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcAttendeeReport.tsx @@ -0,0 +1,276 @@ +import { createRef, useEffect, useRef, useState } from "react"; +import styles from "../LcDashboard.module.css"; +import { + getMeetupInfo, + submitAttendeeReport, + submitAttendeeTaskImage +} from "../../../services/LearningCircleAPIs"; +import toast from "react-hot-toast"; +import { useNavigate, useParams } from "react-router-dom"; +import { Checkbox, Input } from "@chakra-ui/react"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; + +const LcReportAttendee = () => { + const [reportText, setReportText] = useState(""); + const [meetup, setMeetup] = useState(); + const props = useParams<{ id: string }>(); + const filePickerRefs = useRef>({}); // Object to store refs by task.id + const [completedTasks, setCompletedTasks] = useState([]); + const [taskImages, setTaskImages] = useState<{ + [key: string]: File | null; + }>({}); + const [taskUrls, setTaskUrls] = useState<{ [key: string]: string }>({}); + const [submitedTasks, setSubmittedtasks] = useState([]); + const [isTaskPOWSubmitting, setIsTaskPOWSubmitting] = + useState(false); + const navigate = useNavigate(); + useEffect(() => { + getMeetupInfo(setMeetup, props.id ?? ""); + }, [props.id]); + useEffect(() => { + if (meetup?.is_attendee_report_submitted) { + toast.success("Report already submitted"); + navigate("/dashboard/learning-circle"); + return; + } + meetup?.tasks.forEach(task => { + if (task.is_completed) { + setSubmittedtasks([...submitedTasks, task.id ?? ""]); + } + }); + }, [meetup]); + const handleTaskSubmit = (taskId: string) => { + const formData = new FormData(); + formData.append("meet_task", taskId); + if (taskImages[taskId]) { + console.log(taskImages[taskId]); + formData.append("is_image", "1"); + formData.append( + "image_url", + taskImages[taskId] as any, + (taskImages[taskId] as any).name + ); + setIsTaskPOWSubmitting(true); + submitAttendeeTaskImage(props.id ?? "", taskId, formData).then( + res => { + if (res) { + setSubmittedtasks([...submitedTasks, taskId]); + setIsTaskPOWSubmitting(false); + } + } + ); + } else if (taskUrls[taskId]) { + formData.append("proof_url", taskUrls[taskId]); + setIsTaskPOWSubmitting(true); + submitAttendeeTaskImage(props.id ?? "", taskId, formData).then( + res => { + if (res) { + setSubmittedtasks([...submitedTasks, taskId]); + } + setIsTaskPOWSubmitting(false); + } + ); + } else { + toast.error("Please upload an image or provide a url"); + } + }; + const handleSubmit = (event: any) => { + event.preventDefault(); + const formData = new FormData(); + if (reportText.length > 0) { + formData.append("report", reportText); + if (submitedTasks.length === 0) { + toast.error( + "Please submit proof of work for atleast one task you have done." + ); + return; + } + submitAttendeeReport(props.id ?? "", formData).then(() => { + navigate("/dashboard/learning-circle"); + }); + } else { + toast.error("Please provide a brief description"); + } + }; + return ( +
+
+
+

Brief description *

+ +
+
+

Meeting Tasks

+

+ Please check which tasks you've done, and upload an + image or a link that shows the work you have done. +

+ {meetup?.tasks.map((task, index) => ( +
+
+ { + e.target.checked + ? setCompletedTasks([ + ...(completedTasks as any), + task.id + ]) + : setCompletedTasks( + completedTasks.filter( + id => id !== task.id + ) + ); + }} + /> + + {task.title} + +
+
+
+ { + e.preventDefault(); + filePickerRefs.current[ + task.id ?? "" + ]?.click(); + }} + disabled={isTaskPOWSubmitting} + > + Upload Image + + + + {taskImages[task.id ?? ""]?.name ?? ""} + +
+ OR + { + setTaskUrls({ + ...taskUrls, + [task.id ?? ""]: e.target.value + }); + }} + className={styles.input} + disabled={isTaskPOWSubmitting} + placeholder="Enter URL" + /> + + (filePickerRefs.current[task.id ?? ""] = + el) + } + type="file" + onChange={e => { + if (e.target.files) { + if ( + e.target.files[0].size > 5000000 + ) { + toast.error( + "File size should not exceed 5MB" + ); + return; + } + if ( + e.target.files[0].type != + "image/jpeg" && + e.target.files[0].type != + "image/png" + ) { + toast.error( + "Please upload png or jpeg image" + ); + return; + } + setTaskImages({ + ...taskImages, + [task.id ?? ""]: + e.target.files[0] + }); + } + }} + style={{ display: "none" }} + className={styles.input} + placeholder="Upload File" + disabled={isTaskPOWSubmitting} + /> + + handleTaskSubmit(task.id ?? "") + } + > + Submit + +
+
+ ))} +
+
+ +
+ ); +}; + +export default LcReportAttendee; diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcHistory.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcHistory.tsx index 6fa11b128..b41071d0e 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcHistory.tsx +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcHistory.tsx @@ -1,86 +1,241 @@ import styles from "../LcDashboard.module.css"; -import { LcAttendees } from "./LcAttendees"; -import { useEffect, useState } from "react"; -import { getLCMeetingReport } from "../../../services/LearningCircleAPIs"; -import { convertDateToDayAndMonthAndYear } from "../../../../../utils/common"; +import { + fetchURLQRCode, + interestedMeetup, + joinMeetup +} from "../../../services/LearningCircleAPIs"; +import { convertToFormatedDate } from "../../../../../utils/common"; import { convert24to12, extract24hTimeFromDateTime, getDayOfWeek } from "../../../services/utils"; -import { useParams } from "react-router-dom"; import MuLoader from "@/MuLearnComponents/MuLoader/MuLoader"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; +import toast from "react-hot-toast"; +import { useNavigate, useSearchParams } from "react-router-dom"; +import { useEffect, useState } from "react"; type Props = { id: string | undefined; - lc: LcDetail | undefined; + lc: LcMeetupDetailInfo | undefined; + setLc: UseStateFunc; }; const LcHistory = (props: Props) => { - const [data, setData] = useState(); - const { id } = useParams(); - + const navigate = useNavigate(); + const [blob, setBlob] = useState(null); + const [meetupCode, setMeetupCode] = useState(""); + const [query, setQuery] = useSearchParams(); useEffect(() => { - getLCMeetingReport(props.id, id).then(res => { - setData(res); - }); - }, []); + fetchURLQRCode( + setBlob, + (window.location.href ?? "unknown") + + "/?code=" + + props.lc?.meet_code + ); + }, [props.id]); + useEffect(() => { + if (query.get("code")) { + const code = query.get("code"); + if (code) { + setMeetupCode(code); + } + } + }, [query]); + const handleInterested = (e: any) => { + e.preventDefault(); + if ( + (props.lc?.is_lc_member || (props.lc?.is_started && meetupCode)) && + !props.lc?.joined_at + ) { + joinMeetup(props.lc?.id ?? "").then(res => { + props.setLc({ + ...props.lc, + joined_at: new Date().toISOString() + } as any); + }); + return; + } + interestedMeetup(props.lc?.id ?? "", props.lc?.is_interested).then( + res => { + props.setLc({ + ...props.lc, + is_interested: !props.lc?.is_interested + } as any); + } + ); + }; return (
- {data ? ( +

Learning Circle Meetup

+ {props.lc ? ( <>
-

- {convertDateToDayAndMonthAndYear( - data?.meet_time - )} -

-

{getDayOfWeek(data?.meet_time)}

+

{props.lc?.title}

+

{getDayOfWeek(props.lc?.meet_time)}

-
+
+ {props.lc.is_lc_member && ( +
+

{ + navigator.clipboard.writeText( + props.lc?.meet_code ?? + "NOTCOPIED" + ); + toast.success("Code Copied"); + }} + > + {" "} + + + + + {props.lc.meet_code} +

+

{ + navigator.clipboard.writeText( + (window.location.href ?? + "NOTCOPIED") + + "/?code=" + + props.lc?.meet_code + ); + toast.success("Link Copied"); + }} + > + {" "} + + + + + Copy Link +

+

+ {props.lc.total_interested}{" "} + Interests Submitted +

+

+ {props.lc.total_joined} Joined +

+
+ )} + {props.lc.is_started && + props.lc.is_lc_member ? ( +
+ +

+ Share this QR Code for joining the + meet. +

+
+ ) : ( + <> + )} { -

- Venuesdf:{" "} - {data.meet_place || +

+ Venue:{" "} + {props.lc.meet_place || props.lc?.meet_place}

} -

+

Time:{" "} - {convert24to12( - extract24hTimeFromDateTime( - data.meet_time - ) - )} + {convertToFormatedDate(props.lc.meet_time) + + " " + + convert24to12( + extract24hTimeFromDateTime( + props.lc.meet_time + ) + )}

Agenda

-

{data.agenda}

-
-
-
-
-

Attendees

- {Array.isArray(data.attendees_details) && - data.attendees_details.map(attendee => ( -
- +

{props.lc.agenda}

+ {props.lc.pre_requirements ? ( + <> +

Prerequisites

+

{props.lc.pre_requirements}

+ + ) : ( + <> + )} +

Tasks

+
+ {props.lc.tasks.map((task, index) => ( +
+ {index + 1} + {task.title}
))} +
-
- -
+
+ {props.lc.image ? ( +
+ +
+ ) : null} +
+ {props.lc.joined_at ? ( + { + e.preventDefault(); + navigate( + "/dashboard/learning-circle/meetup/" + + props.lc?.id + + "/attendee-report" + ); + }} + > + {props.lc.is_attendee_report_submitted + ? "Report Submitted" + : "Submit Report"} + + ) : null} + + {props.lc.joined_at + ? "Joined" + : props.lc.is_started + ? props.lc.is_lc_member || meetupCode + ? "Join" + : "I'm Interested to Join" + : props.lc.is_lc_member + ? "Join & Start Meetup" + : props.lc.is_interested + ? "Undo Interested" + : "I'm Interested Join"} + ) : (
{ - const nextMeet = getNextMeetingDate( - props.lc?.day || [], - props.lc?.meet_time === null ? "00:00" : String(props.lc?.meet_time) - ); - - const [selectedMeeting, setSelectedMeeting] = useState(""); - + const [meetups, setMeetups] = useState([]); + const [pastMeetups, setPastMeetups] = useState([]); + const [reportPending, setReportPending] = useState([]); + const [selectedMeeting, setSelectedMeeting] = useState(""); + useEffect(() => { + getLcMeetups(props.id ?? "").then(res => { + if (res) { + if (res.hasError) { + toast.error(res.message.general[0]); + } else { + setMeetups(res.meetups); + setPastMeetups(res.past); + setReportPending(res.report_pending); + } + } + }); + }, [props.lc]); + const navigate = useNavigate(); return (
@@ -40,8 +49,8 @@ const LcHome = (props: Props) => { ...props.temp, isReport: false, isHistory: false, - isTeam: false, - isSchedule: false + isTeam: false + // isSchedule: false }) } > @@ -59,7 +68,321 @@ const LcHome = (props: Props) => { Team
- {props.temp.isReport ? ( +
+
+
+ {props.temp.isReport ? ( + + ) : props.temp.isCreateMeeting ? ( + + ) : ( + <> +
+ {meetups.length > 0 ? ( + meetups.map(meetup => ( +
+
+
+ + + + {convertToFormatedDate( + meetup.meet_time + )} +
+
+ {meetup.is_started + ? "Ongoing" + : "Upcoming"} +
+
+
+

+ {meetup.title} +

+

+ {meetup.agenda} +

+
+

+ Venue Details +

+
+
+ + { + meetup.meet_place + } + +
+ + { + meetup.location + } + +
+
+ { + props.setTemp( + prev => ({ + ...prev, + isReport: + true + }) + ); + setSelectedMeeting( + meetup.id + ); + }} + > + Submit Report + + { + navigate( + "/dashboard/learning-circle/meetup/" + + meetup.id + ); + }} + > + More Info + +
+
+
+
+ )) + ) : ( + <> +
+

+ Next meeting not scheduled. +
+ Kindly schedule a meeting. +

+
+ { + props.setTemp(prev => ({ + ...prev, + isCreateMeeting: true + })); + }} + > + Schedule Meet + + + )} +
+ + {/*
+
+ {props.lc?.meet_place && ( +

Venue: {props.lc?.meet_place}

+ )} + {props.lc?.meet_time && ( +

Time: {nextMeet?.formattedTime}

+ )} +
+ {props.lc?.meet_time && ( + + )} +
*/} + + )} +
+ {!props.temp.isSchedule && + !props.temp.isTeam && + !props.temp.isReport ? ( + <> + {(reportPending ?? []).length > 0 ? ( +
+

Pending Report Submissions

+
+ {reportPending.map((report, index) => ( +
+
+

{index + 1}.

+

+ {convertToFormatedDate( + report.meet_time + )} +

+
+
+

+ {convertToFormatedDate( + report.meet_time + )}{" "} + {convert24to12( + extract24hTimeFromDateTime( + report.meet_time + ) + )} +

+ +
+
+ ))} +
+
+ ) : ( + <> + )} +
+ {props.lc?.previous_meetings && + props.lc?.previous_meetings.length > 0 && ( +

Your past meetings

+ )} +
+ {pastMeetups.map((report, index) => ( +
{ + navigate( + "/dashboard/learning-circle/meetup/" + + report.id + ); + }} + > +
+

{index + 1}.

+

+ {convertToFormatedDate( + report.meet_time + )} +

+
+
+

+ {convertToFormatedDate( + report.meet_time + )}{" "} + {convert24to12( + extract24hTimeFromDateTime( + report.meet_time + ) + )} +

+ +
+
+ ))} +
+
+ + ) : ( + <> + )} +
+
+ {/* {props.temp.isReport ? ( ) : props.temp.isHistory ? ( @@ -67,8 +390,8 @@ const LcHome = (props: Props) => {
- {props.temp.isSchedule ? ( - { <>
{nextMeet && - props.lc?.meet_place && - props.lc?.meet_time ? ( + props.lc?.meet_place && + props.lc?.meet_time ? (

Next meeting on

@@ -103,7 +426,7 @@ const LcHome = (props: Props) => { onClick={() => { props.setTemp(prev => ({ ...prev, - isSchedule: true + isCreateMeeting: true })); }} > @@ -125,16 +448,18 @@ const LcHome = (props: Props) => {

)}

- {props.lc?.meet_time && ()} + {props.lc?.meet_time && ( + + )}
)} @@ -151,52 +476,11 @@ const LcHome = (props: Props) => {

Your past meetings

)}
- {props.lc?.previous_meetings.map( - (report, index) => ( -
{ - props.setTemp({ - ...props.temp, - isReport: false, - isHistory: true - }); - setSelectedMeeting(report.id); - }} - > -
-

{index + 1}.

-

- {convertToFormatedDate( - report.meet_time - )} -

-
-
-

- {convert24to12( - extract24hTimeFromDateTime( - report.meet_time - ) - )} -

- -
-
- ) - )} +
- )} + )} */}
); }; diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetCreate.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetCreate.tsx new file mode 100644 index 000000000..49888b147 --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetCreate.tsx @@ -0,0 +1,379 @@ +import { createRef, Dispatch, SetStateAction, useRef, useState } from "react"; +import styles from "../LcDashboard.module.css"; +import toast from "react-hot-toast"; +import { + createMeetup, + setLCMeetTime +} from "../../../services/LearningCircleAPIs"; +import { useFormik } from "formik"; +import { Switch } from "@chakra-ui/react"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; + +type Props = { + setTemp: Dispatch>; + lc: LcDetail | undefined; + id: string | undefined; +}; + +const LcMeetCreate = (props: Props) => { + const [tasks, setTasks] = useState([]); + const taskInputRef = createRef(); + const [isLoading, setIsLoading] = useState(false); + const formik = useFormik({ + initialValues: { + title: "", + location: "", + meet_time: "", + meet_place: "", + agenda: "", + need_pre_requirements: false, + pre_requirements: null, + is_public: true, + limit_attendees: false, + max_attendees: -1, + is_online: false + }, + onSubmit: values => { + if (tasks.length === 0) { + toast.error("Please add tasks"); + return; + } + setIsLoading(true); + createMeetup({ ...values, tasks: tasks }, props.id ?? "") + .then(res => { + setIsLoading(false); + if (res) { + if (res.hasError) { + toast.error(res.message.general[0]); + } else { + toast.success(res.message.general[0]); + } + } + }) + .catch(err => { + setIsLoading(false); + toast.error("Failed to create meetup"); + }); + + props.setTemp(prev => ({ + ...prev, + isCreateMeeting: false + })); + }, + validate: values => { + if (values.location === "") { + return { location: "Location is required" }; + } else if (!values.location.startsWith("http")) { + return { + location: + "Location should be link to maps location or online meet link." + }; + } + } + }); + + return ( + <> +
+ Create a Meetup +

Enter details to schedule a meet

+
+ +
+
+
+ + + +
+
+ +
+ + {formik.touched.title && formik.errors.title ? ( +

+ {formik.errors.title} +

+ ) : null} +
+
+
+ +
+ + {formik.touched.agenda && formik.errors.agenda ? ( +

+ {formik.errors.agenda} +

+ ) : null} +
+
+
+ +
+ {tasks.map((task, index) => ( +
+
+ {index + 1}. +

{task.title}

+
+ +
+ ))} +
+
+
+ { + e.preventDefault(); + if ( + e.currentTarget.value.endsWith("\n") + ) { + setTasks([ + ...tasks, + { + title: e.currentTarget.value.slice( + 0, + -1 + ) + } as any + ]); + e.currentTarget.value = ""; + } + }} + /> + +
+
+
+
+ + { + formik.setFieldValue( + "is_online", + e.target.checked + ); + }} + /> +
+
+ +
+ + {formik.touched.location && + formik.errors.location ? ( +

+ {formik.errors.location} +

+ ) : null} +
+
+
+ + { + formik.setFieldValue( + "is_public", + e.target.checked + ); + }} + /> +
+
+ + { + formik.setFieldValue( + "need_pre_requirements", + e.target.checked + ); + }} + /> +
+ {formik.values.need_pre_requirements && ( +
+ +
+ + {formik.touched.pre_requirements && + formik.errors.pre_requirements ? ( +

+ {formik.errors.pre_requirements} +

+ ) : null} +
+
+ )} +
+ + { + if (!e.target.checked) { + formik.setFieldValue("max_attendees", -1); + } else { + formik.setFieldValue("max_attendees", 100); + } + formik.setFieldValue( + "limit_attendees", + e.target.checked + ); + }} + /> +
+ {formik.values.limit_attendees && ( +
+ +
+ + {formik.touched.max_attendees && + formik.errors.max_attendees ? ( +

+ {formik.errors.max_attendees} +

+ ) : null} +
+
+ )} + + Create Meetup + +
+
+ + ); +}; + +export default LcMeetCreate; diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetups.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetups.tsx new file mode 100644 index 000000000..d64786360 --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetups.tsx @@ -0,0 +1,144 @@ +import styles from "../../LearningCircle.module.css"; +import imageBottom from "../../../assets/images/LC3.webp"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; +import { useNavigate } from "react-router-dom"; +import { useEffect, useState } from "react"; +import { BsChevronRight } from "react-icons/bs"; +import { getMeetups } from "../../../services/LearningCircleAPIs"; +import toast from "react-hot-toast"; +import { convertToFormatedDate } from "../../../../../utils/common"; +import { + convert24to12, + extract24hTimeFromDateTime +} from "../../../services/utils"; +import Select from "react-select"; + +const LcMeetups = ({ user_id }: { user_id: string | null }) => { + const navigate = useNavigate(); + const [meetups, setMeetups] = useState(); + const [selectedCategory, setSelectedCategories] = useState<{ + label: string; + value: string; + }>(); + useEffect(() => { + getMeetups( + setMeetups, + undefined, + user_id ? user_id : undefined, + selectedCategory?.value == "all" + ? undefined + : selectedCategory?.value + ) + .then(() => {}) + .catch(error => { + console.log(error); + toast.error("Failed to fetch meetups"); + }); + }, [user_id, selectedCategory]); + const categories = [ + { label: "All Categories", value: "all" }, + { label: "Coder", value: "coder" }, + { label: "Hardware", value: "hardware" }, + { label: "Manager", value: "manager" }, + { label: "Creative", value: "creative" } + ]; + + return ( +
+
+
    + {meetups && meetups.length > 0 ? ( + <> + Meetups + - setFormData(prevState => ({ - ...prevState, - day: e.target.value - })) - } - style={{ - backgroundColor: "#f0f0f0", - color: "lightgrey" - }} - /> -
-
- - - setFormData(prevState => ({ - ...prevState, - meet_time: e.target.value + ":00" - })) - } - /> -
-
-

Agenda

+

Brief description *

-

Attendees

-
- {props.lc?.members.map(member => ( +

Attendees List

+
+ {attendees.map(attendee => (
handleMemberClick(member.id)} + className={styles.attendee} + key={attendee.attendee_id} + onClick={() => { + setAttendeeDetailsExpanded(prevState => ({ + ...prevState, + [attendee.attendee_id]: + !prevState?.[attendee.attendee_id] + })); + }} > - + + {attendee.fullname} + +
+ { + changeRating( + attendee.attendee_id, + rating + ); + }} + numberOfStars={5} + name="rating" + starDimension="15px" + starSpacing="1px" + /> +
+
+
+

Report

+

+ {attendee.report} +

+

Tasks Completed

+ {attendee.proof_of_work.map( + (task, index) => ( +
+
+ {index + 1} | + {task.title} +
+
+ { + if (task.is_image) { + window.open( + import.meta + .env + .VITE_BACKEND_URL + + (task.image_url ?? + "404"), + "_blank" + ); + } else { + window.open( + task.proof_url ?? + "", + "_blank" + ); + } + }} + > + + +
+
+ ) )} - /> +
))} - {/* */}
diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/YourLc.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/YourLc.tsx new file mode 100644 index 000000000..e1cca1351 --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/YourLc.tsx @@ -0,0 +1,107 @@ +import styles from "../../LearningCircle.module.css"; +import imageBottom from "../../../assets/images/LC3.webp"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; +import { useNavigate } from "react-router-dom"; +import { useEffect, useState } from "react"; +import { BsChevronRight } from "react-icons/bs"; +import { getUserLearningCircles } from "../../../services/LearningCircleAPIs"; + +const YourLc = ({ userCircleList }: { userCircleList: LcType[] }) => { + const navigate = useNavigate(); + + return ( +
+
+
    + {userCircleList && userCircleList.length > 0 ? ( + <> + Your learning circles + {userCircleList?.map((circle, pos) => ( +
    +
  • { + navigate( + `/dashboard/learning-circle/dashboard/${circle.id}` + ); + }} + > + + +
  • +
    + ))} + + ) : ( +
    + You haven't joined any circles yet + Nothing yet! +

    You haven't joined any learning circles yet.

    +
    + )} +
+
+
+ ); +}; + +export default YourLc; diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/YourMeetups.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/YourMeetups.tsx new file mode 100644 index 000000000..621d56052 --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/YourMeetups.tsx @@ -0,0 +1,108 @@ +import styles from "../../LearningCircle.module.css"; +import imageBottom from "../../../assets/images/LC3.webp"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; +import { useNavigate } from "react-router-dom"; +import { useEffect, useState } from "react"; +import { BsChevronRight } from "react-icons/bs"; +import { getMeetups } from "../../../services/LearningCircleAPIs"; +import toast from "react-hot-toast"; +import { convertToFormatedDate } from "../../../../../utils/common"; +import { + convert24to12, + extract24hTimeFromDateTime +} from "../../../services/utils"; + +const YourMeetups = ({ user_id }: { user_id: string | null }) => { + const navigate = useNavigate(); + const [meetups, setMeetups] = useState(); + useEffect(() => { + console.log(user_id); + getMeetups(setMeetups, undefined, "user") + .then(() => {}) + .catch(error => { + console.log(error); + toast.error("Failed to fetch meetups"); + }); + }, [user_id]); + + return ( +
+
+
    + {meetups && meetups.length > 0 ? ( + <> + Meetups +
    + {meetups.map((meetup, pos) => ( +
    +

    + {meetup.title} +

    +
    +

    + {convertToFormatedDate( + meetup.meet_time + ) + + " " + + convert24to12( + extract24hTimeFromDateTime( + meetup.meet_time + ) + )} +

    +

    + {meetup.is_online + ? "Online" + : "Offline"} +

    +

    + {meetup.meet_place} +

    +
    +

    + {meetup.agenda.slice(0, 150) + + "..."} +

    +
    + { + navigate( + `/dashboard/learning-circle/meetup/${meetup.id}` + ); + }} + > + More info + +
    +
    + ))} +
    + + ) : ( +
    + No meetups + No Meetups! +

    No meetups are currently running now

    +
    + )} +
+
+
+ ); +}; + +export default YourMeetups; diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircle.module.css b/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircle.module.css index 8d1abd845..30888fa70 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircle.module.css +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircle.module.css @@ -29,6 +29,7 @@ } .learningCircleLandingPageMiddle { + width: 100%; display: flex; flex-direction: column; justify-content: center; @@ -164,6 +165,9 @@ .learningCircleLandingPageLevel div { font-size: 0.8rem; } + .learningCircleLandingPage .learningCircleLandingPageButton button { + font-size: 15px; + } } @media (width<=820px) { @@ -1264,3 +1268,118 @@ transform: scaleX(-1); } } +.SwitchNav { + display: flex; + gap: 5px; + align-items: center; + .items { + padding: 8px 20px; + background-color: #f3f3f4; + color: black; + font-weight: 600; + border-radius: 15px; + &.active { + background-color: white; + border-radius: 15px 15px 0px 0px; + } + } + .plusItem { + border-left: 2px solid #8b8e92; + color: black; + font-size: 25px; + padding: 0px; + height: fit-content; + padding-left: 10px; + line-height: 1; + } +} + +.ContentWrapper { + width: 100%; + padding: 30px; + background-color: white; + display: flex; + flex-direction: column; + gap: 15px; + align-items: start; +} +.inputBox { + background: #fff; + margin: 0px 10px; + input { + width: 100%; + background-color: rgba(238, 242, 255, 1); + border: none; + border-radius: 10px; + padding: 10px; + } +} +.modalinfo { + margin: 10px; + color: #22222290; + font-size: 15px; +} +.meetupGrid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; + .meetupCard { + background: #fdfdfd; + color: #222; + padding: 20px; + box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.05); + border-radius: 10px; + .meetupTitle { + font-size: 20px; + font-weight: 600; + color: #5570f2; + margin: 10px; + } + .meetupAgenda { + font-size: 15px; + margin: 10px; + text-align: justify; + } + .buttons { + display: flex; + margin: 10px; + gap: 10px; + width: 100%; + justify-content: space-between; + align-items: center; + margin-top: 20px; + a { + display: flex; + align-items: center; + gap: 5px; + padding: 10px 20px; + border: 1px dashed var(--blue); + border-radius: 10px; + } + } + .tags { + display: flex; + gap: 10px; + padding: 10px 0; + .tag { + display: flex; + align-items: center; + padding: 5px; + border: 1px dashed #5570f2; + border-radius: 10px; + color: #222; + font-size: 10px; + } + } + } + @media screen and (max-width: 768px) { + grid-template-columns: 1fr; + .meetupCard { + .tags { + .tag { + font-size: 10px; + } + } + } + } +} diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircleLandingPage.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircleLandingPage.tsx index 59fd3de51..863c2e9f3 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircleLandingPage.tsx +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircleLandingPage.tsx @@ -1,24 +1,31 @@ import styles from "./LearningCircle.module.css"; import imageTop from "../assets/images/LC2.webp"; -import imageBottom from "../assets/images/LC3.webp"; import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; import { useNavigate } from "react-router-dom"; import { useEffect, useState } from "react"; -import { BsChevronRight } from "react-icons/bs"; -import { getUserLearningCircles } from "../services/LearningCircleAPIs"; +import { + getUserLearningCircles, + joinMeetup +} from "../services/LearningCircleAPIs"; import MuLoader from "@/MuLearnComponents/MuLoader/MuLoader"; +import YourLc from "./LcDashboard/components/YourLc"; +import LcMeetups from "./LcDashboard/components/LcMeetups"; +import MuModal from "@/MuLearnComponents/MuModal/MuModal"; +import toast from "react-hot-toast"; +import YourMeetups from "./LcDashboard/components/YourMeetups"; const LearningCircleLandingPage = () => { const navigate = useNavigate(); const [userCircleList, setUserCircleList] = useState(); const [isLoading, setIsLoading] = useState(true); - + const [curpage, setCurPage] = useState(0); + const [meetingCodeModalOpen, setMeetingCodeModalOpen] = useState(false); useEffect(() => { getUserLearningCircles(setUserCircleList).then(() => { setIsLoading(false); }); }, []); - + const [meetupCode, setMeetupCode] = useState(""); const handleJoin = () => { navigate("/dashboard/learning-circle/find-circle"); }; @@ -27,8 +34,46 @@ const LearningCircleLandingPage = () => { navigate("/dashboard/learning-circle/create-circle"); }; + const joinMeet = () => { + if (meetupCode.length !== 6) { + toast.error("Invalid meetup code"); + return; + } + joinMeetup(meetupCode); + setMeetingCodeModalOpen(false); + }; + + const handleJoinMeetup = () => { + setMeetingCodeModalOpen(true); + }; return ( <> + { + setMeetingCodeModalOpen(false); + }} + title={"Enter Meeting Code"} + type={"success"} + onDone={joinMeet} + > +
+ { + setMeetupCode(e.target.value.toUpperCase()); + }} + /> +
+

+ Enter the 6 digit code provided by the meetup organizer to + join the meetup and earn karma points. +

+
{isLoading ? (
@@ -49,6 +94,11 @@ const LearningCircleLandingPage = () => { styles.learningCircleLandingPageButton } > + { onClick={handleJoin} />
- -
-
    - {userCircleList && userCircleList.length > 0 ? ( - <> - Your learning circles - {userCircleList?.map((circle, pos) => ( -
    -
  • { - navigate( - `/dashboard/learning-circle/dashboard/${circle.id}` - ); - }} - > - - -
  • -
    - ))} - - ) : ( -
    - You haven't joined any circles yet - Nothing yet! -

    - You haven't joined any learning circles - yet. -

    -
    - )} -
+
+
+ + + +
+ {curpage === 0 ? ( + + ) : curpage === 1 ? ( + + ) : ( + + )}
)} diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.module.css b/src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.module.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.tsx new file mode 100644 index 000000000..4e43e1806 --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.tsx @@ -0,0 +1,25 @@ +import { useParams } from "react-router-dom"; +import LcHistory from "../LcDashboard/components/LcHistory"; +import { useEffect, useState } from "react"; +import { getMeetupInfo } from "../../services/LearningCircleAPIs"; +import toast from "react-hot-toast"; +import MuLoader from "@/MuLearnComponents/MuLoader/MuLoader"; + +export default function LcMeetupIfo() { + const params = useParams(); + const [data, setData] = useState(); + useEffect(() => { + getMeetupInfo(setData, params.id ?? "") + .then(res => { + console.log(res); + }) + .catch(() => { + toast.error("Failed to fetch data"); + }); + }, []); + return data ? ( + + ) : ( + + ); +} diff --git a/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleAPIs.ts b/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleAPIs.ts index c90d7b54d..d4a46a5d3 100644 --- a/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleAPIs.ts +++ b/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleAPIs.ts @@ -1,4 +1,4 @@ -import { AxiosError } from "axios"; +import axios, { AxiosError } from "axios"; import { privateGateway } from "@/MuLearnServices/apiGateways"; import { dashboardRoutes } from "@/MuLearnServices/urls"; import { SetStateAction } from "react"; @@ -24,6 +24,173 @@ export const getUserLearningCircles = async ( } }; +export const joinMeetup = async (meetId: string) => { + try { + const response = await privateGateway.post( + dynamicRoute(dashboardRoutes.joinMeetup, meetId) + ); + const message: any = response?.data; + toast.success(message.message?.general[0] ?? "Failed to join meetup"); + } catch (err: unknown) { + const error = err as AxiosError; + toast.error( + ((error?.response?.data as any).message?.general ?? [ + "Failed to join meetup" + ])[0] + ); + if (error?.response) { + throw error; + } + toast.error("Failed to join meetup"); + } +}; + +export const interestedMeetup = async ( + meetId: string, + undo: boolean = false +) => { + try { + if (undo) { + const response = await privateGateway.delete( + dynamicRoute(dashboardRoutes.interestedMeetup, meetId) + ); + const message: any = response?.data; + toast.success( + message.message?.general[0] ?? "Failed to undo interest" + ); + return; + } + const response = await privateGateway.post( + dynamicRoute(dashboardRoutes.interestedMeetup, meetId) + ); + const message: any = response?.data; + toast.success(message.message?.general[0] ?? "Failed to show interest"); + } catch (err: unknown) { + console.log(err); + const error = err as AxiosError; + toast.error( + ((error?.response?.data as any).message?.general ?? [ + "Failed to show interest" + ])[0] + ); + if (error?.response) { + throw error; + } + toast.error("Failed to show interest"); + } +}; + +export const getMeetupInfo = async ( + setMeetup: + | UseStateFunc + | UseStateFunc, + meetId: string +) => { + try { + console.log(meetId); + const response = await privateGateway.get( + dynamicRoute(dashboardRoutes.getMeetupInfo, meetId) + ); + console.log(response); + const message: any = response?.data; + setMeetup(message.response); + } catch (err: unknown) { + const error = err as AxiosError; + if (error?.response) { + throw error; + } + } +}; + +export const submitAttendeeTaskImage = async ( + meetId: string, + taskId: string, + formData: FormData +) => { + try { + const response = await privateGateway.post( + dynamicRoute( + dashboardRoutes.submitAttendeeTaskImage, + meetId, + taskId + ), + formData, + { + headers: { + "content-type": "multipart/form-data" + } + } + ); + console.log(response); + const message: any = response?.data?.message?.general[0]; + toast.success(message); + return true; + } catch (err: unknown) { + const error = err as AxiosError; + if ((error?.response?.data as any)?.message?.general[0]) { + toast.error((error?.response?.data as any)?.message?.general[0]); + } + console.log(error); + return false; + } +}; + +export const submitAttendeeReport = async ( + meetId: string, + formData: FormData +) => { + try { + console.log(meetId); + const response = await privateGateway.post( + dynamicRoute(dashboardRoutes.submitAttendeeReport, meetId), + formData + ); + console.log(response); + const message: any = response?.data; + toast.success(message.message?.general[0] ?? "Failed to submit report"); + } catch (err: unknown) { + const error = err as AxiosError; + toast.error((error?.response?.data as any)?.message?.general[0]); + if (error?.response) { + throw error; + } + } +}; +export const getMeetups = async ( + setMeetup: + | UseStateFunc + | UseStateFunc, + meetId: string | undefined = undefined, + userId: string | undefined = undefined, + category: string | undefined = undefined +) => { + try { + console.log(meetId); + const response = await privateGateway.get( + dashboardRoutes.getMeetups + (userId ? userId : ""), + { + params: meetId + ? { + meet_id: meetId + } + : category + ? { + category: category + } + : {} + } + ); + console.log(response); + const message: any = response?.data; + setMeetup(message.response); + } catch (err: unknown) { + const error = err as AxiosError; + if (error?.response) { + throw error; + } + } +}; + export const getUserOrg = (setOrg: { (value: SetStateAction): void; (arg0: any): void; @@ -235,6 +402,52 @@ export const updateLcNote = async (data: LcNote) => { } }; +export const getMeetupAttendees = async (id: string | undefined) => { + try { + console.log(dynamicRoute(lcRoutes.getLcAttendees, id as string)); + const response = await privateGateway.get( + dynamicRoute(lcRoutes.getLcAttendees, id as string) + ); + const message: any = response?.data; + return message.response; + } catch (err) { + const error = err as AxiosError; + if (error?.response) { + throw error; + } + } +}; + +export const getLcMeetups = async (id: string | undefined) => { + try { + const response = await privateGateway.get( + dynamicRoute(lcRoutes.getLcMeetups, id as string) + ); + const message: any = response?.data; + return message.response; + } catch (err) { + const error = err as AxiosError; + if (error?.response) { + throw error; + } + } +}; + +export const createMeetup = async (data: LcMeetup, id: string) => { + try { + const response = await privateGateway.post( + dynamicRoute(lcRoutes.createMeet, id as string), + data + ); + const message: any = response?.data; + return message; + } catch (err) { + const error = err as AxiosError; + if (error?.response) { + throw error; + } + } +}; export const setLCMeetTime = async ( data: LcMeetSchedule, id: string | undefined @@ -254,6 +467,38 @@ export const setLCMeetTime = async ( } }; +export const getVerifiableMeetups = async () => { + try { + const response = await privateGateway.get(lcRoutes.verifyList); + const message: any = response?.data; + return message.response; + } catch (err) { + const error = err as AxiosError; + toast.error("Failed to get list of meetups."); + if (error?.response) { + throw error; + } + } +}; + +export const fetchURLQRCode = async (setBlob: any, target_url: string) => { + try { + const url = `https://quickchart.io/qr?text=${target_url}¢erImageUrl=https://avatars.githubusercontent.com/u/98015594?s=88&v=4`; + const response = await axios + .get(url, { + responseType: "arraybuffer" + }) + .then(response => { + const blob = new Blob([response.data], { + type: "image/png" + }); + setBlob(URL.createObjectURL(blob)); + }); + } catch (error) { + console.error(error); + } +}; + export const reportMeeting = async (id: string | undefined, data: FormData) => { try { const response = await privateGateway.post( diff --git a/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleInterface.d.ts b/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleInterface.d.ts index ae9f183f7..54ae26804 100644 --- a/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleInterface.d.ts +++ b/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleInterface.d.ts @@ -45,6 +45,7 @@ interface LcDashboardTempData { isTeam: boolean; isSchedule: boolean; reRender: boolean; + isCreateMeeting: boolean; } interface LcMeetSchedule { @@ -52,7 +53,47 @@ interface LcMeetSchedule { meet_place: string; day: string; } +type LcTask = { + id: string | undefined; + title: string; + is_completed: boolean; + is_image: boolean; + image_url: string | null; + proof_url: string | null; +}; +interface LcMeetup { + title: string; + location: string; + meet_time: string; + meet_place: string; + agenda: string; + need_pre_requirements: boolean; + pre_requirements: string | null; + is_public: boolean; + limit_attendees: boolean; + max_attendees: number; + tasks: LcTask[]; + is_online: boolean; +} +type LcMeetupInfo = LcMeetup & { + id: string; + is_started: boolean; + is_report_submitted: boolean; + meet_code: string | null; + image: string | null; +}; + +type LcMeetupDetailInfo = LcMeetupInfo & { + tasks: LcTask[]; + is_interested: boolean; + joined_at: string | null; + total_interested: number; + total_joined: number; + lc_members: number; + is_lc_member: boolean; + is_attendee_report_submitted: boolean; +}; interface LcNote { note: string; id: string | undefined; @@ -64,13 +105,6 @@ interface ChecklistItem { isChecked: boolean; } -interface LcReport { - agenda: string; - attendees: string[]; - day: string; - meet_time: string; -} - interface LcPastReports { id: string; meet_time: string; @@ -91,6 +125,10 @@ interface LcHistory { } interface LcAttendees { + attendee_id: string; fullname: string; profile_pic: string; + title: string; + report: string; + proof_of_work: LcTask[]; } diff --git a/src/modules/Dashboard/modules/Settings/pages/Organization/Organization.module.css b/src/modules/Dashboard/modules/Settings/pages/Organization/Organization.module.css new file mode 100644 index 000000000..2d04c5326 --- /dev/null +++ b/src/modules/Dashboard/modules/Settings/pages/Organization/Organization.module.css @@ -0,0 +1,61 @@ +@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@200;300;400;500;600;700;800&display=swap"); + +.wrapper { + padding: 1rem; + display: flex; + justify-content: center; + align-items: center; +} + +.tableWrapper { + background-color: white; + border-radius: 10px; + padding: 2rem; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +.wrapper form { + width: 20rem; +} + +.inputBox { + width: 100%; + height: 2.5rem; + margin-top: 1.5rem; +} + +.inputBox span { + color: red; + font-size: small; + margin-left: 15px; +} + +.inputBox input { + width: 100%; + height: 100%; + background: #f3f3f4; + border-radius: 8px; + border: none; + padding: 1rem; +} + +.submit { + margin-top: 20px; + display: flex; + justify-content: center; + align-items: center; +} + +.submit button { + width: 100%; + color: white; +} + +.text { + font-weight: 700; +} + +.errorsSpan { + color: red; + font-size: small; +} diff --git a/src/modules/Dashboard/modules/Settings/pages/Organization/Organization.tsx b/src/modules/Dashboard/modules/Settings/pages/Organization/Organization.tsx new file mode 100644 index 000000000..bb29ca52d --- /dev/null +++ b/src/modules/Dashboard/modules/Settings/pages/Organization/Organization.tsx @@ -0,0 +1,226 @@ +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; +import styles from "./Organization.module.css"; +import { Form, Formik } from "formik"; +import * as z from "yup"; +import { FormikTextInputWithoutLabel as SimpleInput } from "@/MuLearnComponents/FormikComponents/FormikComponents"; +import { useEffect, useState } from "react"; +import { + getColleges, + getDepartments, + getRoles, + submitUserData +} from "../../../../../Common/Authentication/services/newOnboardingApis"; +import ReactSelect, { SingleValue } from "react-select"; +import { useLocation, useNavigate } from "react-router-dom"; +import { selectOrganization } from "../../settingsApis"; + +// Define the Option type for ReactSelect +type Option = { + value: string; + label: string; +}; + +const inputObject = { + college: "College Name", + department: "Department", + graduationYear: "Graduation Year" +}; + +const scheme = z.object({ + college: z + .string() + .required(`${inputObject.college} is Required`) + .min(3, `${inputObject.college} must be at least 3 characters`) + .max(100, `${inputObject.college} must be at most 100 characters`), + department: z + .string() + .required(`${inputObject.department} is Required`) + .min(2, `${inputObject.department} must be at least 2 characters`) + .max(100, `${inputObject.department} must be at most 100 characters`), + graduationYear: z + .number() + .integer() + .positive() + .when("role", { + is: "student", + then: s => + s + .required(`${inputObject.graduationYear} is Required`) + .min(2000, `${inputObject.graduationYear} > 2000`) + .max(2030, `${inputObject.graduationYear} < 2030`) + }) +}); + +export default function CollegePage({}: {}) { + const navigate = useNavigate(); + const location = useLocation(); + let userData: any = location.state as Object; + + const [isloading, setIsLoading] = useState(true); + const [colleges, setColleges] = useState([{ id: "", title: "" }]); + const [departments, setDepartments] = useState([{ id: "", title: "" }]); + const [roles, setRoles] = useState([{ id: "", title: "" }]); + + const [selectedCollege, setSelectedCollege] = useState