From 8274a1b48fbf3a71adfeeffcce6b1a8c04a1c7cb Mon Sep 17 00:00:00 2001 From: Rusi Solanki Date: Sun, 11 Aug 2024 02:18:08 -0400 Subject: [PATCH 001/524] Issue 113: Implement Settings page Frontend --- frontend/src/scenes/settings/Settings.css | 6 ++ frontend/src/scenes/settings/Settings.jsx | 18 ++++ .../SettingsTabs/ProfileTab/ProfileTab.css | 83 +++++++++++++++++++ .../SettingsTabs/ProfileTab/ProfileTab.jsx | 76 +++++++++++++++++ .../settings/SettingsTabs/SettingsTabs.css | 3 + .../settings/SettingsTabs/SettingsTabs.jsx | 36 ++++++++ 6 files changed, 222 insertions(+) create mode 100644 frontend/src/scenes/settings/Settings.css create mode 100644 frontend/src/scenes/settings/Settings.jsx create mode 100644 frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.css create mode 100644 frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx create mode 100644 frontend/src/scenes/settings/SettingsTabs/SettingsTabs.css create mode 100644 frontend/src/scenes/settings/SettingsTabs/SettingsTabs.jsx diff --git a/frontend/src/scenes/settings/Settings.css b/frontend/src/scenes/settings/Settings.css new file mode 100644 index 00000000..cd61f0da --- /dev/null +++ b/frontend/src/scenes/settings/Settings.css @@ -0,0 +1,6 @@ +.settings{ + display: flex; + justify-content: center; + width: 60%; + margin: 30px 30px; +} \ No newline at end of file diff --git a/frontend/src/scenes/settings/Settings.jsx b/frontend/src/scenes/settings/Settings.jsx new file mode 100644 index 00000000..5f5b1ba7 --- /dev/null +++ b/frontend/src/scenes/settings/Settings.jsx @@ -0,0 +1,18 @@ +import React from "react"; +import SettingsTabs from "./SettingsTabs/SettingsTabs"; +import './Settings.css' +import HomePageTemplate from "../../components/templates/HomePageTemplate"; + +const Settings = () => { + return ( +
+ +
+ +
+
+
+ ); +}; + +export default Settings; diff --git a/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.css b/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.css new file mode 100644 index 00000000..80ecd73d --- /dev/null +++ b/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.css @@ -0,0 +1,83 @@ +*{ + font-size: 13px; +} +.form{ + padding-bottom: 20px; + border-bottom: 1px solid #EEEEEE; +} +.first-name-element{ + display: flex; + justify-content: space-between; + margin: 0px; +} +.form-elements{ + display: flex; + justify-content: space-between; + margin: 25px 0px; +} +.photo-elements{ + display: flex; + gap: 12px; + margin: 30px 0px; +} +.photo-options{ + display: flex; + gap: 20px; +} +.label-elements{ + display: flex; + flex-direction: column; +} +.label{ + font-weight: 600; +} +.support-text{ + margin: 0; + font-weight: 400; + color: #667085; + padding-right: 25px; +} +.input{ + width: 378px; + height: 34px; + border: 1px solid #D0D5DD; + border-radius: 4px; +} +.update{ + color: #1976d2; + border: none; + background: none; + cursor: pointer; +} +.button-options{ + display: flex; + gap: 16px; +} +.save-button{ + display: flex; + justify-content: flex-end; +} +.save{ + width: 160px; + height: 34px; + color: white; + background-color: #4C7DE7; + padding: 10px 16px; + border: 1px solid #175CD3; + border-radius: 4px; + cursor: pointer; +} +.delete-heading{ + margin-top: 10px; + margin-bottom: 0px; +} +.delete{ + width: 160px; + height: 34px; + color: white; + background-color: #DB504A; + border: 1px solid #DB504A; + margin-top: 20px; + border-radius: 4px; + cursor: pointer; +} \ No newline at end of file diff --git a/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx b/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx new file mode 100644 index 00000000..4db9809f --- /dev/null +++ b/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx @@ -0,0 +1,76 @@ +import React from "react"; +import Avatar from "../../../../components/Avatar/Avatar"; +import "./ProfileTab.css"; + +const ProfileTab = () => { + return ( +
+
+
+
+ + +
+
+ + +
+
+
+ +

+ This is your current email address -- it cannot be changed. +

+
+ +
+
+
+ +

+ This photo will be displayed in your profile page. +

+
+
+ +
+

Delete

+ +
+
+
+
+ +
+
+
+
+

Delete Account

+

Note that deleting your account will remove all data from our system. This is permanent and non-recoverable.

+
+ +
+
+
+ ); +}; + +export default ProfileTab; diff --git a/frontend/src/scenes/settings/SettingsTabs/SettingsTabs.css b/frontend/src/scenes/settings/SettingsTabs/SettingsTabs.css new file mode 100644 index 00000000..16dab61e --- /dev/null +++ b/frontend/src/scenes/settings/SettingsTabs/SettingsTabs.css @@ -0,0 +1,3 @@ +.tab-label{ + font-size: 13px !important; +} \ No newline at end of file diff --git a/frontend/src/scenes/settings/SettingsTabs/SettingsTabs.jsx b/frontend/src/scenes/settings/SettingsTabs/SettingsTabs.jsx new file mode 100644 index 00000000..772e1145 --- /dev/null +++ b/frontend/src/scenes/settings/SettingsTabs/SettingsTabs.jsx @@ -0,0 +1,36 @@ +import { useState } from 'react'; +import Box from '@mui/material/Box'; +import Tab from '@mui/material/Tab'; +import TabContext from '@mui/lab/TabContext'; +import TabList from '@mui/lab/TabList'; +import TabPanel from '@mui/lab/TabPanel'; +import './SettingsTabs.css' +import ProfileTab from './ProfileTab/ProfileTab'; + + +const tabLabel = ['Profile', 'Password', 'Team'] + +export default function SettingsTabs() { + const [value, setValue] = useState('1'); + + const handleChange = (event, newValue) => { + setValue(newValue); + }; + + return ( + + + + + + + + + + + Item Two + Item Three + + + ); +} From 378646f68ec5aa0afc8570ba4f4e423aa139d072 Mon Sep 17 00:00:00 2001 From: Rusi Solanki Date: Mon, 12 Aug 2024 01:10:47 -0400 Subject: [PATCH 002/524] Update code --- frontend/src/scenes/settings/Settings.jsx | 4 +++- .../scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx | 6 +++++- frontend/src/scenes/settings/SettingsTabs/SettingsTabs.jsx | 5 +---- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/scenes/settings/Settings.jsx b/frontend/src/scenes/settings/Settings.jsx index 5f5b1ba7..5a8021fb 100644 --- a/frontend/src/scenes/settings/Settings.jsx +++ b/frontend/src/scenes/settings/Settings.jsx @@ -1,16 +1,18 @@ import React from "react"; import SettingsTabs from "./SettingsTabs/SettingsTabs"; -import './Settings.css' import HomePageTemplate from "../../components/templates/HomePageTemplate"; +import './Settings.css' const Settings = () => { return (
+
+
); }; diff --git a/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx b/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx index 4db9809f..0915f25e 100644 --- a/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx +++ b/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx @@ -3,10 +3,14 @@ import Avatar from "../../../../components/Avatar/Avatar"; import "./ProfileTab.css"; const ProfileTab = () => { + + const submitHandler = (e) => { + e.preventDefault() + } return (
-
+
+ +
+ ); +}; + +export default ProfileSettingsPage; From 0a7e666440e662dcc39dd432baff022b7178cca5 Mon Sep 17 00:00:00 2001 From: prashant-80 Date: Sat, 5 Oct 2024 09:58:14 +0530 Subject: [PATCH 065/524] merge develop branch --- .DS_Store | Bin 0 -> 6148 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..50d86b883aa6ddc4c5ed3ff7ea417814bf25652f GIT binary patch literal 6148 zcmeHKJ5B>Z41I=3M50MaIalBYt0 z^NRHvfUOVXHLwD(q&ni=O)q}#+R0gY94%@*;2Goiy4!E3F8Z{?b1$&PJ$87)xBO|( zlDzj3FPK>Ntv@_nQC=}12E>3E5CdZ1HwL`HQkIvAvSL6Ch=DH#{QJ>2DP`6wZm64vU*vr*5{IP%LhzzePA~ zNR$-=V&Is8^W3hy|KCu5nE#KHv=akj;9oIdi_Pt3%_miF?H=d7wo&h>9`iwU;W|=i mq8$^X9dqOD_$q=juKAkhL*bkl>GVfBQ9lFDi$o0kH3Of80UR3u literal 0 HcmV?d00001 From 47450699f3f2b2b5df6d22f3347afe716ee9e9f4 Mon Sep 17 00:00:00 2001 From: prashant-80 Date: Sat, 5 Oct 2024 10:29:03 +0530 Subject: [PATCH 066/524] Fix:#261 Disable button while loading --- frontend/src/scenes/login/SetNewPassword.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/scenes/login/SetNewPassword.jsx b/frontend/src/scenes/login/SetNewPassword.jsx index a830402c..7023be1f 100644 --- a/frontend/src/scenes/login/SetNewPassword.jsx +++ b/frontend/src/scenes/login/SetNewPassword.jsx @@ -110,7 +110,7 @@ function SetNewPasswordPage({ email = 'asdf@asdf.com' }) { Must contain one special character
- From f450891df7ac4dc1a0e70046303325a64bafeb21 Mon Sep 17 00:00:00 2001 From: prashant-80 Date: Sat, 5 Oct 2024 11:19:53 +0530 Subject: [PATCH 067/524] fix #262 Refactor Popup&banner controller --- backend/src/models/Banner.js | 8 ++++++-- backend/src/models/Popup.js | 8 ++++++-- backend/src/utils/popup.helper.js | 21 +++++++++------------ frontend/dist/index.html | 4 ++-- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/backend/src/models/Banner.js b/backend/src/models/Banner.js index 54715225..a640e0e0 100644 --- a/backend/src/models/Banner.js +++ b/backend/src/models/Banner.js @@ -8,7 +8,9 @@ module.exports = (sequelize, DataTypes) => { allowNull: false, validate: { isValidAction(value) { - validateCloseButtonAction(value); + if (!validateCloseButtonAction(value)) { + throw new Error('Invalid close button action'); + } }, }, }, @@ -17,7 +19,9 @@ module.exports = (sequelize, DataTypes) => { allowNull: false, validate: { isValidPosition(value) { - validatePosition(value); + if (!validatePosition(value)) { + throw new Error('Invalid position'); + } }, }, }, diff --git a/backend/src/models/Popup.js b/backend/src/models/Popup.js index 0fa8f4a5..d6c2df9f 100644 --- a/backend/src/models/Popup.js +++ b/backend/src/models/Popup.js @@ -15,7 +15,9 @@ module.exports = (sequelize, DataTypes) => { allowNull: false, validate: { isValidAction(value) { - validateCloseButtonAction(value); + if (!validateCloseButtonAction(value)) { + throw new Error('Invalid close button action'); + } }, }, }, @@ -24,7 +26,9 @@ module.exports = (sequelize, DataTypes) => { allowNull: false, validate: { isValidPopupSize(value) { - validatePopupSize(value); + if (!validatePopupSize(value)) { + throw new Error('Invalid popup size'); + } }, }, }, diff --git a/backend/src/utils/popup.helper.js b/backend/src/utils/popup.helper.js index a0acdfa8..a7c2ad61 100644 --- a/backend/src/utils/popup.helper.js +++ b/backend/src/utils/popup.helper.js @@ -1,14 +1,11 @@ +const { validateCloseButtonAction } = require("./banner.helper"); + const validatePopupSize = (value) => { - const validSizes = ["small", "medium", "large"]; - return validSizes.includes(value); - }; - - const validateCloseButtonAction = (value) => { - const validActions = ["no action", "open url", "open url in a new tab"]; - return validActions.includes(value); - }; + const validSizes = ["small", "medium", "large"]; + return validSizes.includes(value); +}; - module.exports = { - validatePopupSize, - validateCloseButtonAction, - }; \ No newline at end of file +module.exports = { + validatePopupSize, + validateCloseButtonAction, +}; diff --git a/frontend/dist/index.html b/frontend/dist/index.html index 5f67c20a..3435691a 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -5,8 +5,8 @@ Bluewave Onboarding - - + + From 4132bc7055a23a6810e92b0902dab8f5e8b9f234 Mon Sep 17 00:00:00 2001 From: prashant-80 Date: Sat, 5 Oct 2024 12:04:56 +0530 Subject: [PATCH 068/524] Fix Refactor Popup&banner controller and Popup&banner models validations #227 --- backend/src/controllers/banner.controller.js | 4 ++-- backend/src/controllers/popup.controller.js | 4 ++-- backend/src/models/Banner.js | 4 ++-- backend/src/models/Popup.js | 4 ++-- backend/src/utils/banner.helper.js | 11 +++-------- backend/src/utils/guideHelpers.js | 8 +++++++- backend/src/utils/popup.helper.js | 3 --- 7 files changed, 18 insertions(+), 20 deletions(-) diff --git a/backend/src/controllers/banner.controller.js b/backend/src/controllers/banner.controller.js index b72ba3e6..fd3427df 100644 --- a/backend/src/controllers/banner.controller.js +++ b/backend/src/controllers/banner.controller.js @@ -1,7 +1,7 @@ const bannerService = require("../service/banner.service.js"); const { internalServerError } = require("../utils/errors.js"); -const { isValidHexColor, checkColorFields } = require("../utils/guideHelpers.js"); -const { validatePosition, validateCloseButtonAction } = require("../utils/banner.helper.js"); +const { isValidHexColor, checkColorFields, validateCloseButtonAction } = require("../utils/guideHelpers.js"); +const { validatePosition } = require("../utils/banner.helper.js"); const db = require("../models/index.js"); const Banner = db.Banner; diff --git a/backend/src/controllers/popup.controller.js b/backend/src/controllers/popup.controller.js index 1f425fd2..9b736f2e 100644 --- a/backend/src/controllers/popup.controller.js +++ b/backend/src/controllers/popup.controller.js @@ -1,9 +1,9 @@ const popupService = require("../service/popup.service"); const { internalServerError } = require("../utils/errors"); -const { isValidHexColor, checkColorFields } = require("../utils/guideHelpers"); +const { isValidHexColor, checkColorFields, validateCloseButtonAction } = require("../utils/guideHelpers"); const db = require("../models"); const Popup = db.Popup; -const { validatePopupSize, validateCloseButtonAction } = require("../utils/popup.helper"); +const { validatePopupSize } = require("../utils/popup.helper"); class PopupController { async addPopup(req, res) { diff --git a/backend/src/models/Banner.js b/backend/src/models/Banner.js index a640e0e0..833ca2a0 100644 --- a/backend/src/models/Banner.js +++ b/backend/src/models/Banner.js @@ -1,5 +1,5 @@ -const { validateHexColor } = require('../utils/guideHelpers'); -const { validateCloseButtonAction, validatePosition } = require('../utils/banner.helper'); +const { validateHexColor, validateCloseButtonAction } = require('../utils/guideHelpers'); +const { validatePosition } = require('../utils/banner.helper'); module.exports = (sequelize, DataTypes) => { const Banner = sequelize.define('Banner', { diff --git a/backend/src/models/Popup.js b/backend/src/models/Popup.js index d6c2df9f..5dd4f7eb 100644 --- a/backend/src/models/Popup.js +++ b/backend/src/models/Popup.js @@ -1,5 +1,5 @@ -const { validateHexColor } = require('../utils/guideHelpers'); -const { validateCloseButtonAction, validatePopupSize } = require('../utils/popup.helper'); +const { validateHexColor, validateCloseButtonAction } = require('../utils/guideHelpers'); +const { validatePopupSize } = require('../utils/popup.helper'); module.exports = (sequelize, DataTypes) => { const Popup = sequelize.define( diff --git a/backend/src/utils/banner.helper.js b/backend/src/utils/banner.helper.js index 5d70c7ab..2d8f8b5b 100644 --- a/backend/src/utils/banner.helper.js +++ b/backend/src/utils/banner.helper.js @@ -1,14 +1,9 @@ const validatePosition = (value) => { - const validPositions = ["top", "bottom"]; - return validPositions.includes(value); - }; + const validPositions = ["top", "bottom"]; + return validPositions.includes(value.toLowerCase()); +}; - const validateCloseButtonAction = (value) => { - const validActions = ["no action", "open url", "open url in a new tab"]; - return validActions.includes(value); - }; module.exports = { validatePosition, - validateCloseButtonAction, }; \ No newline at end of file diff --git a/backend/src/utils/guideHelpers.js b/backend/src/utils/guideHelpers.js index a67a6da3..47429ccd 100644 --- a/backend/src/utils/guideHelpers.js +++ b/backend/src/utils/guideHelpers.js @@ -20,8 +20,14 @@ const checkColorFields = (colorFields, res) => { return true; }; +const validateCloseButtonAction = (value) => { + const validActions = ["no action", "open url", "open url in a new tab"]; + return validActions.includes(value); +}; + module.exports = { isValidHexColor, validateHexColor, - checkColorFields + checkColorFields, + validateCloseButtonAction, }; \ No newline at end of file diff --git a/backend/src/utils/popup.helper.js b/backend/src/utils/popup.helper.js index a7c2ad61..be451cb0 100644 --- a/backend/src/utils/popup.helper.js +++ b/backend/src/utils/popup.helper.js @@ -1,5 +1,3 @@ -const { validateCloseButtonAction } = require("./banner.helper"); - const validatePopupSize = (value) => { const validSizes = ["small", "medium", "large"]; return validSizes.includes(value); @@ -7,5 +5,4 @@ const validatePopupSize = (value) => { module.exports = { validatePopupSize, - validateCloseButtonAction, }; From 55a4470397b1549d2f6e7614807ea5e1c860561a Mon Sep 17 00:00:00 2001 From: prashant-80 Date: Sat, 5 Oct 2024 12:33:57 +0530 Subject: [PATCH 069/524] handle res in colorFields --- backend/src/controllers/banner.controller.js | 12 ++++++++++-- backend/src/utils/guideHelpers.js | 7 ++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/backend/src/controllers/banner.controller.js b/backend/src/controllers/banner.controller.js index fd3427df..957b36ae 100644 --- a/backend/src/controllers/banner.controller.js +++ b/backend/src/controllers/banner.controller.js @@ -27,7 +27,11 @@ class BannerController { } const colorFields = { fontColor, backgroundColor }; - checkColorFields(colorFields, res); + try { + checkColorFields(colorFields); + } catch (error) { + return res.status(400).json({ errors: [{ msg: error.message }] }); + } try { const newBannerData = { ...req.body, createdBy: userId }; @@ -98,7 +102,11 @@ class BannerController { } const colorFields = { fontColor: req.body.fontColor, backgroundColor: req.body.backgroundColor }; - checkColorFields(colorFields, res); + try { + checkColorFields(colorFields); + } catch (error) { + return res.status(400).json({ errors: [{ msg: error.message }] }); + } const updatedBanner = await bannerService.updateBanner(id, req.body); res.status(200).json(updatedBanner); diff --git a/backend/src/utils/guideHelpers.js b/backend/src/utils/guideHelpers.js index 47429ccd..04a4138f 100644 --- a/backend/src/utils/guideHelpers.js +++ b/backend/src/utils/guideHelpers.js @@ -9,15 +9,12 @@ const validateHexColor = (value, fieldName) => { } }; -const checkColorFields = (colorFields, res) => { +const checkColorFields = (colorFields) => { for (const [field, value] of Object.entries(colorFields)) { if (value && !isValidHexColor(value)) { - return res.status(400).json({ - errors: [{ msg: `${field} must be a valid hex color code` }], - }); + throw new Error(`${field} must be a valid hex color code`); } } - return true; }; const validateCloseButtonAction = (value) => { From 76efffb8ad46ca9260a3352ed68fbd19acfe8217 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 5 Oct 2024 15:47:55 +0530 Subject: [PATCH 070/524] refactor modals into seperate components, add upload image functionality only UI side --- frontend/package-lock.json | 39 ++++++++++ frontend/package.json | 1 + .../DeleteConfirmationModal.jsx | 26 +++++++ .../DeleteConfirmationModal.module.scss | 19 +++++ .../Modals/UploadImageModal/UploadModal.jsx | 70 ++++++++++++++++++ .../UploadImageModal/UploadModal.module.scss | 38 ++++++++++ .../ProfileSettings.module.scss | 27 +++++++ .../ProfileSettings/ProfileSettingsPage.jsx | 73 +++++++------------ 8 files changed, 245 insertions(+), 48 deletions(-) create mode 100644 frontend/src/components/Modals/DeleteConfirmationModal/DeleteConfirmationModal.jsx create mode 100644 frontend/src/components/Modals/DeleteConfirmationModal/DeleteConfirmationModal.module.scss create mode 100644 frontend/src/components/Modals/UploadImageModal/UploadModal.jsx create mode 100644 frontend/src/components/Modals/UploadImageModal/UploadModal.module.scss diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 9e2ca764..95a04949 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,6 +23,7 @@ "mui-color-input": "^4.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-dropzone": "^14.2.9", "react-quill": "^2.0.0", "react-redux": "^9.1.2", "react-router": "^6.23.0", @@ -3961,6 +3962,15 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -5700,6 +5710,18 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-selector": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.6.0.tgz", + "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -8358,6 +8380,23 @@ "react": "^18.3.1" } }, + "node_modules/react-dropzone": { + "version": "14.2.9", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.2.9.tgz", + "integrity": "sha512-jRZsMC7h48WONsOLHcmhyn3cRWJoIPQjPApvt/sJVfnYaB3Qltn025AoRTTJaj4WdmmgmLl6tUQg1s0wOhpodQ==", + "license": "MIT", + "dependencies": { + "attr-accept": "^2.2.2", + "file-selector": "^0.6.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "react": ">= 16.8 || 18.0.0" + } + }, "node_modules/react-element-to-jsx-string": { "version": "15.0.0", "resolved": "https://registry.npmjs.org/react-element-to-jsx-string/-/react-element-to-jsx-string-15.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index dd7552d8..c1973adb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,6 +19,7 @@ "mui-color-input": "^4.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-dropzone": "^14.2.9", "react-quill": "^2.0.0", "react-redux": "^9.1.2", "react-router": "^6.23.0", diff --git a/frontend/src/components/Modals/DeleteConfirmationModal/DeleteConfirmationModal.jsx b/frontend/src/components/Modals/DeleteConfirmationModal/DeleteConfirmationModal.jsx new file mode 100644 index 00000000..98c5fe5d --- /dev/null +++ b/frontend/src/components/Modals/DeleteConfirmationModal/DeleteConfirmationModal.jsx @@ -0,0 +1,26 @@ +import React from 'react'; +import Modal from '@mui/material/Modal'; +import Box from '@mui/material/Box'; +import Button from '../../Button/Button'; +import styles from './DeleteConfirmationModal.module.scss'; + +const DeleteConfirmationModal = ({ open, handleClose }) => { + return ( + + +

Really Delete this account ?

+

If you delete your account, you will no longer be able to sign in, and all of your data will be deleted. Deleting your account is permanent and non-recoverable action.

+
+
+
+
+ ) +} + +export default DeleteConfirmationModal; \ No newline at end of file diff --git a/frontend/src/components/Modals/DeleteConfirmationModal/DeleteConfirmationModal.module.scss b/frontend/src/components/Modals/DeleteConfirmationModal/DeleteConfirmationModal.module.scss new file mode 100644 index 00000000..324d55d3 --- /dev/null +++ b/frontend/src/components/Modals/DeleteConfirmationModal/DeleteConfirmationModal.module.scss @@ -0,0 +1,19 @@ +.modalBox { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 500px; + background-color: white; + box-shadow: 24; + border-radius: 5px; + padding: 2rem; + font-size: 13px; + color: var(--third-text-color); + font-weight: 400; + + h3 { + font-size: 16px; + font-weight: 600; + } +} \ No newline at end of file diff --git a/frontend/src/components/Modals/UploadImageModal/UploadModal.jsx b/frontend/src/components/Modals/UploadImageModal/UploadModal.jsx new file mode 100644 index 00000000..64dfe82b --- /dev/null +++ b/frontend/src/components/Modals/UploadImageModal/UploadModal.jsx @@ -0,0 +1,70 @@ +import { React, useState, useCallback } from 'react'; +import Modal from '@mui/material/Modal'; +import Box from '@mui/material/Box'; +import Button from '../../Button/Button'; +import styles from './UploadModal.module.scss'; +import { useDropzone } from 'react-dropzone'; +import CloudUploadOutlinedIcon from '@mui/icons-material/CloudUploadOutlined'; + +const UploadModal = ({ open, handleClose }) => { + + const [uploadedFile, setUploadedFile] = useState(null); + + const onDrop = useCallback((acceptedFiles) => { + setUploadedFile(acceptedFiles[0]); // Only allow one file + }, []); + + const { getRootProps, getInputProps, fileRejections } = useDropzone({ + onDrop, + maxFiles: 1, + maxSize: 3 * 1024 * 1024, + accept: { + "image/*": [".png", ".jpg"], + } + }) + + const clearUploadedFile = () => { + setUploadedFile(null); + } + + const handleUpload = () => { + // do something with uploadedFile + } + + return ( + + +

Upload Image

+
+ + {!uploadedFile && + <> + +

Click to upload or drag and drop

(maximum size: 3MB)

+ + } + {uploadedFile &&

{uploadedFile.path}

} +
+ {fileRejections.map(({ file, errors }) =>

{ + errors.map(e => ( +

{e.message}

+ )) + }

)} +

Supported formats: JPG, PNG

+
+
+ +
+
+ ) +} + +export default UploadModal; \ No newline at end of file diff --git a/frontend/src/components/Modals/UploadImageModal/UploadModal.module.scss b/frontend/src/components/Modals/UploadImageModal/UploadModal.module.scss new file mode 100644 index 00000000..2203bce9 --- /dev/null +++ b/frontend/src/components/Modals/UploadImageModal/UploadModal.module.scss @@ -0,0 +1,38 @@ +.uploadBox { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: white; + box-shadow: 0px 1px 2px 0px #1018280D; + border-radius: 5px; + padding: 1.5rem 3rem; + box-sizing: content-box; + font-size: 13px; + width: 350px; + color: var(--third-text-color); + + p { + .errorMessage { + color: #D92D20; + } + } +} + +.uploadContainer { + display: flex; + flex-direction: column; + border: 1px dashed #ccc; + border-radius: 5px; + align-items: center; + justify-content: center; + text-align: center; + cursor: pointer; + height: 150px; + + p { + span { + color: #1570EF; + } + } +} \ No newline at end of file diff --git a/frontend/src/scenes/ProfileSettings/ProfileSettings.module.scss b/frontend/src/scenes/ProfileSettings/ProfileSettings.module.scss index 95294766..1c7ed75a 100644 --- a/frontend/src/scenes/ProfileSettings/ProfileSettings.module.scss +++ b/frontend/src/scenes/ProfileSettings/ProfileSettings.module.scss @@ -97,4 +97,31 @@ box-shadow: 24; border-radius: 5px; padding: 2rem; +} + +.uploadBox { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: white; + box-shadow: 0px 1px 2px 0px #1018280D; + border-radius: 5px; + padding: 1.5rem 3rem; + box-sizing: content-box; + font-size: 13px; + width: 350px; + color: var(--third-text-color); +} + +.uploadContainer { + display: flex; + flex-direction: column; + border: 1px dashed #ccc; + border-radius: 5px; + align-items: center; + justify-content: center; + text-align: center; + cursor: pointer; + height: 150px; } \ No newline at end of file diff --git a/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx b/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx index b0348670..94cf3027 100644 --- a/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx +++ b/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx @@ -1,35 +1,14 @@ -import HomePageTemplate from '../../templates/HomePageTemplate/HomePageTemplate'; -import GuideTemplate from '../../templates/GuideTemplate/GuideTemplate'; -import BannerLeftContent from '../../components/BannerPageComponents/BannerLeftContent/BannerLeftContent'; -import BannerLeftAppearance from '../../components/BannerPageComponents/BannerLeftAppearance/BannerLeftApperance'; -import { React, useState, useEffect } from 'react'; -import BannerPreview from '../../components/BannerPageComponents/BannerPreview/BannerPreview'; -import { addBanner, getBannerById, editBanner } from '../../services/bannerServices'; -import { useNavigate, useLocation } from 'react-router-dom'; -import toastEmitter, { TOAST_EMITTER_KEY } from '../../utils/toastEmitter'; -import { emitToastError } from '../../utils/guideHelpers' +import { React, useState, useCallback } from 'react'; +import { useNavigate } from 'react-router-dom'; import styles from './ProfileSettings.module.scss'; -import CloseOutlinedIcon from '@mui/icons-material/CloseOutlined'; import classNames from 'classnames'; import Button from '../../components/Button/Button'; import CustomTextField from '../../components/TextFieldComponents/CustomTextField/CustomTextField'; -import { TextField, InputLabel, Divider } from "@mui/material"; +import { InputLabel, Divider } from "@mui/material"; import Avatar from '../../components/Avatar/Avatar'; -import Modal from '@mui/material/Modal'; -import Typography from '@mui/material/Typography'; -import Box from '@mui/material/Box'; +import DeleteConfirmationModal from '../../components/Modals/DeleteConfirmationModal/DeleteConfirmationModal'; +import UploadModal from '../../components/Modals/UploadImageModal/UploadModal'; -const style = { - position: 'absolute', - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - width: 500, - bgcolor: 'background.paper', - boxShadow: 24, - borderRadius: '5px', - p: 4, -}; const ProfileSettingsPage = ({ title = '', leftContent = () => null, rightContent = () => null, leftAppearance = () => null, onSave = () => null }) => { const navigate = useNavigate(); @@ -37,10 +16,16 @@ const ProfileSettingsPage = ({ title = '', leftContent = () => null, rightConten const handleButtonClick = (index) => { setActiveButton(index); }; - const [open, setOpen] = useState(false); - const handleOpen = () => setOpen(true); - const handleClose = () => setOpen(false); + const [openDeleteConfirmationModal, setOpenDeleteConfirmationModal] = useState(false); + const handleOpenDeleteConfirmationModal = () => setOpenDeleteConfirmationModal(true); + const handleCloseDeleteConfirmationModal = () => setOpenDeleteConfirmationModal(false); + + const [openUploadModal, setOpenUploadModal] = useState(false); + const handleOpenUploadModal = () => setOpenUploadModal(true); + const handleCloseUploadModal = () => setOpenUploadModal(false); + const buttons = ['Profile', 'Password', 'Team']; + return (
@@ -72,9 +57,9 @@ const ProfileSettingsPage = ({ title = '', leftContent = () => null, rightConten This photo will be displayed in your profile page.
- +
@@ -85,24 +70,16 @@ const ProfileSettingsPage = ({ title = '', leftContent = () => null, rightConten

Delete Account

Note that deleting your account will remove all data from our system. This is permanent and non-recoverable.

-
- - -

Really Delete this account ?

-

If you delete your account, you will no longer be able to sign in, and all of your data will be deleted. Deleting your account is permanent and non-recoverable action.

-
-
-
-
- + + ) From 27593b3ea3b13bf367ce7edd3e7382eff7fdc178 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 5 Oct 2024 16:17:42 +0530 Subject: [PATCH 071/524] refactor profile into seperate component --- frontend/src/components/Profile/Profile.jsx | 60 +++++++++++++++++++ .../components/Profile/Profile.module.scss | 25 ++++++++ .../ProfileSettings.module.scss | 47 +-------------- .../ProfileSettings/ProfileSettingsPage.jsx | 56 +---------------- 4 files changed, 89 insertions(+), 99 deletions(-) create mode 100644 frontend/src/components/Profile/Profile.jsx create mode 100644 frontend/src/components/Profile/Profile.module.scss diff --git a/frontend/src/components/Profile/Profile.jsx b/frontend/src/components/Profile/Profile.jsx new file mode 100644 index 00000000..20f598c6 --- /dev/null +++ b/frontend/src/components/Profile/Profile.jsx @@ -0,0 +1,60 @@ +import { React, useState } from 'react'; +import Button from '../../components/Button/Button'; +import CustomTextField from '../../components/TextFieldComponents/CustomTextField/CustomTextField'; +import { InputLabel, Divider } from "@mui/material"; +import Avatar from '../../components/Avatar/Avatar'; +import DeleteConfirmationModal from '../../components/Modals/DeleteConfirmationModal/DeleteConfirmationModal'; +import UploadModal from '../../components/Modals/UploadImageModal/UploadModal'; +import styles from './Profile.module.scss'; + +const Profile = ({ onSave }) => { + + const [openDeleteConfirmationModal, setOpenDeleteConfirmationModal] = useState(false); + const handleOpenDeleteConfirmationModal = () => setOpenDeleteConfirmationModal(true); + const handleCloseDeleteConfirmationModal = () => setOpenDeleteConfirmationModal(false); + + const [openUploadModal, setOpenUploadModal] = useState(false); + const handleOpenUploadModal = () => setOpenUploadModal(true); + const handleCloseUploadModal = () => setOpenUploadModal(false); + + return ( + +
+ + + + {/* Change Avatar Field */} +
+
+ Your Photo + This photo will be displayed in your profile page. +
+
+ +
+
+
+
+
+ +
+

Delete Account

+

Note that deleting your account will remove all data from our system. This is permanent and non-recoverable.

+
+ + + + ) +} + +export default Profile; \ No newline at end of file diff --git a/frontend/src/components/Profile/Profile.module.scss b/frontend/src/components/Profile/Profile.module.scss new file mode 100644 index 00000000..824c7744 --- /dev/null +++ b/frontend/src/components/Profile/Profile.module.scss @@ -0,0 +1,25 @@ +.profileContainer { + display: flex; + flex-direction: column; + width: 100%; + margin-top: 20px; + gap: 2rem; +} + +.textFieldContainer { + width: 100%; + display: flex; + flex-direction: column; + gap: 1rem; +} + +.optionButtons { + display: flex; + justify-content: flex-end; + gap: 1rem; +} + +.avatarContainer { + display: flex; + gap: 1rem +} \ No newline at end of file diff --git a/frontend/src/scenes/ProfileSettings/ProfileSettings.module.scss b/frontend/src/scenes/ProfileSettings/ProfileSettings.module.scss index 1c7ed75a..cc175f44 100644 --- a/frontend/src/scenes/ProfileSettings/ProfileSettings.module.scss +++ b/frontend/src/scenes/ProfileSettings/ProfileSettings.module.scss @@ -44,13 +44,7 @@ margin-top: 1rem; } - .optionButtons { - display: flex; - justify-content: flex-end; - margin-top: 2rem; - gap: 1rem; - } - + .menuButton { border: none; @@ -85,43 +79,4 @@ .menuButton.active::after { background-color: var(--dark-purple); } -} - -.modalBox { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 500px; - background-color: white; - box-shadow: 24; - border-radius: 5px; - padding: 2rem; -} - -.uploadBox { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: white; - box-shadow: 0px 1px 2px 0px #1018280D; - border-radius: 5px; - padding: 1.5rem 3rem; - box-sizing: content-box; - font-size: 13px; - width: 350px; - color: var(--third-text-color); -} - -.uploadContainer { - display: flex; - flex-direction: column; - border: 1px dashed #ccc; - border-radius: 5px; - align-items: center; - justify-content: center; - text-align: center; - cursor: pointer; - height: 150px; } \ No newline at end of file diff --git a/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx b/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx index 94cf3027..b7f810a5 100644 --- a/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx +++ b/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx @@ -2,12 +2,7 @@ import { React, useState, useCallback } from 'react'; import { useNavigate } from 'react-router-dom'; import styles from './ProfileSettings.module.scss'; import classNames from 'classnames'; -import Button from '../../components/Button/Button'; -import CustomTextField from '../../components/TextFieldComponents/CustomTextField/CustomTextField'; -import { InputLabel, Divider } from "@mui/material"; -import Avatar from '../../components/Avatar/Avatar'; -import DeleteConfirmationModal from '../../components/Modals/DeleteConfirmationModal/DeleteConfirmationModal'; -import UploadModal from '../../components/Modals/UploadImageModal/UploadModal'; +import Profile from '../../components/Profile/Profile'; const ProfileSettingsPage = ({ title = '', leftContent = () => null, rightContent = () => null, leftAppearance = () => null, onSave = () => null }) => { @@ -16,13 +11,7 @@ const ProfileSettingsPage = ({ title = '', leftContent = () => null, rightConten const handleButtonClick = (index) => { setActiveButton(index); }; - const [openDeleteConfirmationModal, setOpenDeleteConfirmationModal] = useState(false); - const handleOpenDeleteConfirmationModal = () => setOpenDeleteConfirmationModal(true); - const handleCloseDeleteConfirmationModal = () => setOpenDeleteConfirmationModal(false); - - const [openUploadModal, setOpenUploadModal] = useState(false); - const handleOpenUploadModal = () => setOpenUploadModal(true); - const handleCloseUploadModal = () => setOpenUploadModal(false); + const buttons = ['Profile', 'Password', 'Team']; @@ -44,46 +33,7 @@ const ProfileSettingsPage = ({ title = '', leftContent = () => null, rightConten ))} - {activeButton == 0 && - ( -
-
- - - -
-
- Your Photo - This photo will be displayed in your profile page. -
-
- -
-
-
-
-
- -
-

Delete Account

-

Note that deleting your account will remove all data from our system. This is permanent and non-recoverable.

-
- - -
- - ) - } + {activeButton == 0 && }
{activeButton === 1 ? leftAppearance() : leftContent()} {rightContent()} From e6b31aa860d113d8555b972ece99ae650fa8a280 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 5 Oct 2024 16:21:02 +0530 Subject: [PATCH 072/524] remove redundant code --- .../ProfileSettings/ProfileSettingsPage.jsx | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx b/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx index b7f810a5..7232b417 100644 --- a/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx +++ b/frontend/src/scenes/ProfileSettings/ProfileSettingsPage.jsx @@ -1,17 +1,17 @@ -import { React, useState, useCallback } from 'react'; +import { React, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import styles from './ProfileSettings.module.scss'; import classNames from 'classnames'; import Profile from '../../components/Profile/Profile'; -const ProfileSettingsPage = ({ title = '', leftContent = () => null, rightContent = () => null, leftAppearance = () => null, onSave = () => null }) => { +const ProfileSettingsPage = ({ onSave = () => null }) => { const navigate = useNavigate(); const [activeButton, setActiveButton] = useState(0); const handleButtonClick = (index) => { setActiveButton(index); }; - + const buttons = ['Profile', 'Password', 'Team']; @@ -19,7 +19,7 @@ const ProfileSettingsPage = ({ title = '', leftContent = () => null, rightConten
- {/* Content and Appereance buttons */} + {/* Profile, Password, Team tabs */}
{buttons.map((buttonName, index) => ( ))}
- {activeButton == 0 && } -
- {activeButton === 1 ? leftAppearance() : leftContent()} - {rightContent()} -
- {/*
-
*/} + {activeButton == 0 && }
From f4257d897aa1f2e3e4e759410a21d7b42dfd6939 Mon Sep 17 00:00:00 2001 From: mr-loop-1 Date: Sat, 5 Oct 2024 17:10:29 +0530 Subject: [PATCH 073/524] refactor: migrate code to service and remove imports --- ...0240906060143-add-name-surname-to-users.js | 1 - .../20240916052017-create_teams_table.js | 2 - .../20240916053636-create_invites_table.js | 4 -- .../20240927182322-update_role_in_users.js | 25 +++++++------ backend/src/controllers/auth.controller.js | 2 +- backend/src/controllers/user.controller.js | 37 +++++++------------ backend/src/service/user.service.js | 21 +++++++++++ 7 files changed, 50 insertions(+), 42 deletions(-) diff --git a/backend/migrations/20240906060143-add-name-surname-to-users.js b/backend/migrations/20240906060143-add-name-surname-to-users.js index ccd0e66a..c8b2befe 100644 --- a/backend/migrations/20240906060143-add-name-surname-to-users.js +++ b/backend/migrations/20240906060143-add-name-surname-to-users.js @@ -17,7 +17,6 @@ module.exports = { await queryInterface.addColumn("users", "username", { type: Sequelize.STRING(50), allowNull: false, - unique: true, defaultValue: "" }); }, diff --git a/backend/migrations/20240916052017-create_teams_table.js b/backend/migrations/20240916052017-create_teams_table.js index a1432899..b6e3e0a7 100644 --- a/backend/migrations/20240916052017-create_teams_table.js +++ b/backend/migrations/20240916052017-create_teams_table.js @@ -1,5 +1,3 @@ -"use strict"; - const config = require('../config/config'); /** @type {import('sequelize-cli').Migration} */ diff --git a/backend/migrations/20240916053636-create_invites_table.js b/backend/migrations/20240916053636-create_invites_table.js index 90f2ca64..f4cf9f81 100644 --- a/backend/migrations/20240916053636-create_invites_table.js +++ b/backend/migrations/20240916053636-create_invites_table.js @@ -1,7 +1,3 @@ -"use strict"; - -const settings = require('../config/settings'); - /** @type {import('sequelize-cli').Migration} */ module.exports = { up: async (queryInterface, Sequelize) => { diff --git a/backend/migrations/20240927182322-update_role_in_users.js b/backend/migrations/20240927182322-update_role_in_users.js index 21e9dc0f..c63285ae 100644 --- a/backend/migrations/20240927182322-update_role_in_users.js +++ b/backend/migrations/20240927182322-update_role_in_users.js @@ -1,23 +1,26 @@ -"use strict"; const settings = require("../config/settings") /** @type {import('sequelize-cli').Migration} */ module.exports = { up: async (queryInterface, Sequelize) => { - await queryInterface.removeColumn("users", "role"); - await queryInterface.addColumn("users", "role", { - type: Sequelize.INTEGER, - allowNull: false, - defaultValue: settings.user.role.member + return queryInterface.sequelize.transaction(async (transaction) => { + await queryInterface.removeColumn("users", "role", { transaction }); + await queryInterface.addColumn("users", "role", { + type: Sequelize.INTEGER, + allowNull: false, + defaultValue: settings.user.role.member + }, { transaction }); }); }, down: async (queryInterface, Sequelize) => { - await queryInterface.removeColumn("users", "role"); - await queryInterface.addColumn("users", "role", { - type: Sequelize.STRING(20), - allowNull: false, - defaultValue: "user", + return queryInterface.sequelize.transaction(async (transaction) => { + await queryInterface.removeColumn("users", "role", { transaction }); + await queryInterface.addColumn("users", "role", { + type: Sequelize.STRING(20), + allowNull: false, + defaultValue: "user", + }, { transaction }); }); }, }; diff --git a/backend/src/controllers/auth.controller.js b/backend/src/controllers/auth.controller.js index 678387d4..3f9a19d0 100644 --- a/backend/src/controllers/auth.controller.js +++ b/backend/src/controllers/auth.controller.js @@ -44,7 +44,7 @@ const register = async (req, res) => { await sendSignupEmail(newUser.email, newUser.name); - res.status(201).json({ user: newUser, token }); + res.status(201).json({ user: {name: newUser.name, surname: newUser.surname, email: newUser.email, role: settings.user.roleName[newUser.role]}, token }); } catch (error) { console.error("Error registering user:", error); await transaction.rollback(); diff --git a/backend/src/controllers/user.controller.js b/backend/src/controllers/user.controller.js index 7b7bd895..f3827611 100644 --- a/backend/src/controllers/user.controller.js +++ b/backend/src/controllers/user.controller.js @@ -7,12 +7,10 @@ const getUsersList = async (req, res) => { const { page = 1, limit = 10, search = "" } = req.query; try { - const offset = (page - 1) * limit; - const { rows: users, count: totalUsers } = await userService.getUsers({page, limit, search}) let returnObj = { - ...users.map(user => ({ + users: users.map(user => ({ name: user.name, surname: user.surname, email: user.email, @@ -32,14 +30,18 @@ const getUsersList = async (req, res) => { const getCurrentUser = async (req, res) => { const userId = req.user.id; - const user = await userService.getUserById(userId); - if (user){ - const { name, surname, email, role } = user; - const roleName = settings.user.roleName[role]; - return res.status(200).json({ user: { name, surname, email, role: roleName } }); + try { + const user = await userService.getUser(userId); + if (user){ + const { id, name, surname, email, role } = user; + return res.status(200).json({ user: { id, name, surname, email, role: settings.user.roleName[role] } }); + } + else{ + return res.status(400).json({ error: "User not found" }); + } } - else{ - return res.status(400).json({ error: "User not found" }); + catch(err) { + res.status(500).json({ error: err.message }); } }; @@ -47,20 +49,9 @@ const updateUserDetails = async (req, res) => { const userId = req.user.id; const inputs = req.body; try { - const user = await userService.getUserById(userId); - if(!user) { - return res.status(400).json({ error: "User not found" }); - } - await user.update({ - ...(inputs.name && { name: inputs.name }), - ...(inputs.surname && { surname: inputs.surname }), - ...(inputs.email && { email: inputs.email }), - }) - - const updatedUser = await userService.getUserById(userId); - const { name, surname, email, role } = updatedUser; + const user = await userService.updateUser(userId, inputs); - return res.status(200).json({ user: { name, surname, email, role} }); + return res.status(200).json({ message: "User updated successfully" }); } catch (err) { return res.status(500).json({ error: "Internal Server Error" }) } diff --git a/backend/src/service/user.service.js b/backend/src/service/user.service.js index a67c678c..023c9f37 100644 --- a/backend/src/service/user.service.js +++ b/backend/src/service/user.service.js @@ -19,6 +19,8 @@ class UserService { async getUsers({search, page, limit}) { try { + const offset = (page - 1) * limit; + return await User.findAndCountAll({ where: { [Sequelize.Op.or]: [ @@ -43,6 +45,25 @@ class UserService { } } + async updateUser(userId, inputs) { + try { + const details = { + ...(inputs.name && { name: inputs.name }), + ...(inputs.surname && { surname: inputs.surname }), + ...(inputs.email && { email: inputs.email }), + }; + + await User.update({ + details, + }, { + where: { id: userId } + }); + } + catch(err) { + throw new Error("Error updating user"); + } + } + async deleteUser(userId) { const transaction = await sequelize.transaction(); try { From f6c96cf65d2bc1af32b582546cb4ec4bda1747bc Mon Sep 17 00:00:00 2001 From: mr-loop-1 Date: Sat, 5 Oct 2024 18:37:02 +0530 Subject: [PATCH 074/524] add: override subsequent invites --- backend/src/controllers/auth.controller.js | 9 ++++----- backend/src/controllers/user.controller.js | 2 +- backend/src/service/invite.service.js | 21 +++++++++++++++++---- backend/src/service/team.service.js | 15 +++++++++++---- backend/src/service/user.service.js | 7 +++---- 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/backend/src/controllers/auth.controller.js b/backend/src/controllers/auth.controller.js index 3f9a19d0..f8be08eb 100644 --- a/backend/src/controllers/auth.controller.js +++ b/backend/src/controllers/auth.controller.js @@ -28,15 +28,14 @@ const register = async (req, res) => { if(!invite) { throw new Error("No Invite Found"); } - + await invite.destroy({ transaction }); - newUser = await User.create({ name, surname, email, password: hashedPassword, role: invite.role }, transaction); - await transaction.commit(); } else { newUser = await User.create({ name, surname, email, password: hashedPassword, role: settings.user.role.admin }); } + await transaction.commit(); const token = generateToken({ id: newUser.id, email: newUser.email }); @@ -44,7 +43,7 @@ const register = async (req, res) => { await sendSignupEmail(newUser.email, newUser.name); - res.status(201).json({ user: {name: newUser.name, surname: newUser.surname, email: newUser.email, role: settings.user.roleName[newUser.role]}, token }); + res.status(201).json({ user: {id: newUser.id, name: newUser.name, surname: newUser.surname, email: newUser.email, role: settings.user.roleName[newUser.role]}, token }); } catch (error) { console.error("Error registering user:", error); await transaction.rollback(); @@ -65,7 +64,7 @@ const login = async (req, res) => { const token = generateToken({ id: user.id, email: user.email }); await Token.create({ token, userId: user.id, type: 'auth' }); - res.status(200).json({ user: {name: user.name, surname: user.surname, email: user.email, role: settings.user.roleName[user.role]}, token }); + res.status(200).json({ user: {id: user.id, name: user.name, surname: user.surname, email: user.email, role: settings.user.roleName[user.role]}, token }); } catch (error) { console.error("Error logging in user:", error); res.status(500).json({ error: "Internal Server Error" }); diff --git a/backend/src/controllers/user.controller.js b/backend/src/controllers/user.controller.js index f3827611..e95c82dc 100644 --- a/backend/src/controllers/user.controller.js +++ b/backend/src/controllers/user.controller.js @@ -49,7 +49,7 @@ const updateUserDetails = async (req, res) => { const userId = req.user.id; const inputs = req.body; try { - const user = await userService.updateUser(userId, inputs); + await userService.updateUser(userId, inputs); return res.status(200).json({ message: "User updated successfully" }); } catch (err) { diff --git a/backend/src/service/invite.service.js b/backend/src/service/invite.service.js index c558a9f3..de76d5c6 100644 --- a/backend/src/service/invite.service.js +++ b/backend/src/service/invite.service.js @@ -19,11 +19,24 @@ class InviteService { if(invitedUser) { throw new Error("Invited User already exists in team") } - await Invite.create({ - invitedBy: userId, - invitedEmail: invitedEmail, - role: settings.user.role[role], + + const existingInvite = await Invite.findOne({ + where: { invitedEmail: invitedEmail } }); + + if(existingInvite) { + await existingInvite.update({ + invitedBy: userId, + role: settings.user.role[role], + }) + } + else { + await Invite.create({ + invitedBy: userId, + invitedEmail: invitedEmail, + role: settings.user.role[role], + }); + } } catch(err) { console.log("🚀 ~ InviteService ~ sendInvite ~ err:", err.message) diff --git a/backend/src/service/team.service.js b/backend/src/service/team.service.js index e3800676..c3ed2ad0 100644 --- a/backend/src/service/team.service.js +++ b/backend/src/service/team.service.js @@ -42,6 +42,7 @@ class TeamService { } async removeUserFromTeam(userId, memberId) { + const transaction = await sequelize.transaction(); try { if(userId == memberId) { throw new Error("User can't remove itself through team list"); @@ -54,14 +55,20 @@ class TeamService { } await User.destroy({ - where: {id: memberId} - }) + where: { id: memberId } + }, { transaction }) await Token.destroy({ where: { userId: memberId } - }); + }, { transaction }); + await Invite.destroy({ + where: { invitedBy: memberId } + }, { transaction }); + + await transaction.commit(); } catch(err) { - console.log("🚀 ~ TeamService ~ removeUserFromTeam ~ err:", err) + console.log("🚀 ~ TeamService ~ removeUserFromTeam ~ err:", err); + await transaction.rollback(); throw new Error("Error Deleting User"); } } diff --git a/backend/src/service/user.service.js b/backend/src/service/user.service.js index 023c9f37..9f7f2c0a 100644 --- a/backend/src/service/user.service.js +++ b/backend/src/service/user.service.js @@ -19,7 +19,7 @@ class UserService { async getUsers({search, page, limit}) { try { - const offset = (page - 1) * limit; + const offset = (parseInt(page) - 1) * parseInt(limit); return await User.findAndCountAll({ where: { @@ -53,9 +53,8 @@ class UserService { ...(inputs.email && { email: inputs.email }), }; - await User.update({ - details, - }, { + await User.update( + details, { where: { id: userId } }); } From 14d644ad263daffaf75bc8c8468bff4110bd588d Mon Sep 17 00:00:00 2001 From: mr-loop-1 Date: Sat, 5 Oct 2024 20:28:32 +0530 Subject: [PATCH 075/524] fixes: transaction arg --- .../20240916053636-create_invites_table.js | 1 + backend/src/controllers/auth.controller.js | 4 ++-- backend/src/models/Invite.js | 1 + backend/src/service/team.service.js | 17 +++++++++++------ 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/backend/migrations/20240916053636-create_invites_table.js b/backend/migrations/20240916053636-create_invites_table.js index f4cf9f81..fb057f00 100644 --- a/backend/migrations/20240916053636-create_invites_table.js +++ b/backend/migrations/20240916053636-create_invites_table.js @@ -19,6 +19,7 @@ module.exports = { }, invitedEmail: { type: Sequelize.STRING(100), + unique: true, allowNull: false, }, role: { diff --git a/backend/src/controllers/auth.controller.js b/backend/src/controllers/auth.controller.js index f8be08eb..6dccc2ae 100644 --- a/backend/src/controllers/auth.controller.js +++ b/backend/src/controllers/auth.controller.js @@ -30,10 +30,10 @@ const register = async (req, res) => { } await invite.destroy({ transaction }); - newUser = await User.create({ name, surname, email, password: hashedPassword, role: invite.role }, transaction); + newUser = await User.create({ name, surname, email, password: hashedPassword, role: invite.role }, { transaction }); } else { - newUser = await User.create({ name, surname, email, password: hashedPassword, role: settings.user.role.admin }); + newUser = await User.create({ name, surname, email, password: hashedPassword, role: settings.user.role.admin }, { transaction }); } await transaction.commit(); diff --git a/backend/src/models/Invite.js b/backend/src/models/Invite.js index 56fea1d1..cfc13225 100644 --- a/backend/src/models/Invite.js +++ b/backend/src/models/Invite.js @@ -19,6 +19,7 @@ module.exports = (sequelize, DataTypes) => { }, invitedEmail: { type: DataTypes.STRING(100), + unique: true, allowNull: false, }, role: { diff --git a/backend/src/service/team.service.js b/backend/src/service/team.service.js index c3ed2ad0..6f89491c 100644 --- a/backend/src/service/team.service.js +++ b/backend/src/service/team.service.js @@ -3,6 +3,8 @@ const db = require("../models"); const Team = db.Team; const User = db.User; const Token = db.Token; +const Invite = db.Invite; +const sequelize = db.sequelize; class TeamService { async getTeam() { @@ -55,14 +57,17 @@ class TeamService { } await User.destroy({ - where: { id: memberId } - }, { transaction }) + where: { id: memberId }, + transaction + }) await Token.destroy({ - where: { userId: memberId } - }, { transaction }); + where: { userId: memberId }, + transaction + }); await Invite.destroy({ - where: { invitedBy: memberId } - }, { transaction }); + where: { invitedBy: memberId }, + transaction + }); await transaction.commit(); } From cb5eea98527923768715c18bc701f274ea6a4bd4 Mon Sep 17 00:00:00 2001 From: Prashant singh <121568016+prashant-80@users.noreply.github.com> Date: Sat, 5 Oct 2024 20:43:08 +0530 Subject: [PATCH 076/524] Update PassswordResetPage.jsx --- frontend/src/scenes/login/PassswordResetPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/scenes/login/PassswordResetPage.jsx b/frontend/src/scenes/login/PassswordResetPage.jsx index dc280b70..bb9ea887 100644 --- a/frontend/src/scenes/login/PassswordResetPage.jsx +++ b/frontend/src/scenes/login/PassswordResetPage.jsx @@ -9,7 +9,7 @@ function PasswordResetPage() {

Password reset

Your password has been successfully reset. Click below to log in manually.

- From 7f4fce6b918e2aa7a5832ea7e3085fc5648b2877 Mon Sep 17 00:00:00 2001 From: mr-loop-1 Date: Sat, 5 Oct 2024 22:33:48 +0530 Subject: [PATCH 077/524] add: loading page while fetching auth --- frontend/src/App.jsx | 5 +-- .../components/LoadingPage/Loading.module.css | 34 +++++++++++++++++++ .../components/LoadingPage/LoadingPage.jsx | 12 +++++++ frontend/src/services/authProvider.jsx | 8 +++-- 4 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 frontend/src/components/LoadingPage/Loading.module.css create mode 100644 frontend/src/components/LoadingPage/LoadingPage.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index dcb199e3..bf92dc07 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -21,14 +21,15 @@ import CreatePopupPage from "./scenes/popup/CreatePopupPage"; import { Error404 } from "./scenes/errors/404"; import { Error403 } from "./scenes/errors/403"; import HomePageTemplate from "./templates/HomePageTemplate/HomePageTemplate"; +import LoadingPage from "./components/LoadingPage/LoadingPage"; const App = () => { - const { isLoggedIn } = useAuth(); + const { isLoggedIn, isFetching } = useAuth(); return ( <> - : }> + : (isLoggedIn ? : )}> } /> } /> } /> diff --git a/frontend/src/components/LoadingPage/Loading.module.css b/frontend/src/components/LoadingPage/Loading.module.css new file mode 100644 index 00000000..150dce39 --- /dev/null +++ b/frontend/src/components/LoadingPage/Loading.module.css @@ -0,0 +1,34 @@ +@import url(../../styles/variables.css); + +.loading-container { + display: flex; + flex-direction: column; + width: 400px; + margin: 0 auto; + padding: 20px; + background-repeat: no-repeat; + background-image: url('../../assets/auth-screen-background.svg'); + background-position: center -350px; +} + +.loading { + display: flex; + margin-top: 100px; + justify-content: center; +} + +.loading::after { + content: ""; + width: 50px; + height: 50px; + border: 10px solid #dddddd; + border-top-color: var(--main-purple); + border-radius: 50%; + animation: loading 1s ease infinite; +} + +@keyframes loading { + to { + transform: rotate(1turn); + } +} \ No newline at end of file diff --git a/frontend/src/components/LoadingPage/LoadingPage.jsx b/frontend/src/components/LoadingPage/LoadingPage.jsx new file mode 100644 index 00000000..6980a9c1 --- /dev/null +++ b/frontend/src/components/LoadingPage/LoadingPage.jsx @@ -0,0 +1,12 @@ +import React from 'react'; +import styles from './Loading.module.css'; + +const LoadingPage = () => { + return ( +
+
+
+ ); +}; + +export default LoadingPage; diff --git a/frontend/src/services/authProvider.jsx b/frontend/src/services/authProvider.jsx index e2722e4b..932f1d26 100644 --- a/frontend/src/services/authProvider.jsx +++ b/frontend/src/services/authProvider.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useContext, useReducer } from 'react'; +import React, { useEffect, useContext, useReducer, useState } from 'react'; import { apiClient } from './apiClient'; const AuthContext = React.createContext(); @@ -24,6 +24,7 @@ const authReducer = (state, action) => { export const AuthProvider = ({ children }) => { const [state, dispatch] = useReducer(authReducer, { isLoggedIn: false, userInfo: null }); + const [isFetching, setIsFetching] = useState(true); useEffect(() => { const fetchUser = async () => { @@ -31,6 +32,7 @@ export const AuthProvider = ({ children }) => { const authToken = localStorage.getItem('authToken'); if (!authToken) { dispatch({ type: 'LOGOUT' }); + setIsFetching(false); return; } const response = await apiClient.get('/users/current-user'); @@ -50,6 +52,8 @@ export const AuthProvider = ({ children }) => { } catch (error) { localStorage.removeItem('authToken'); dispatch({ type: 'LOGOUT' }); + } finally { + setIsFetching(false); } }; @@ -65,7 +69,7 @@ export const AuthProvider = ({ children }) => { }; return ( - + {children} ); From 24762f3cb392c94f5fbe907db48f8063f7de1c2b Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 6 Oct 2024 19:24:03 +0530 Subject: [PATCH 078/524] add jwt secret key in dev .env, update seeder to use hashed password --- backend/.env | 21 ++++++++++---------- backend/seeders/20240610054534-demo-users.js | 19 ++++++++++-------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/backend/.env b/backend/.env index 9bb1b20d..420615a2 100644 --- a/backend/.env +++ b/backend/.env @@ -1,11 +1,12 @@ -# Node environment -NODE_ENV=development - -# Development environment -DEV_DB_USERNAME=user123 -DEV_DB_PASSWORD=password123 -DEV_DB_NAME=onboarding_db -DEV_DB_HOST=localhost -DEV_DB_PORT=5432 - +# Node environment +NODE_ENV=development + +# Development environment +DEV_DB_USERNAME=user123 +DEV_DB_PASSWORD=password123 +DEV_DB_NAME=onboarding_db +DEV_DB_HOST=localhost +DEV_DB_PORT=5432 +JWT_SECRET=your_development_jwt_secret + EMAIL_ENABLE=false \ No newline at end of file diff --git a/backend/seeders/20240610054534-demo-users.js b/backend/seeders/20240610054534-demo-users.js index 629812db..f007d0f2 100644 --- a/backend/seeders/20240610054534-demo-users.js +++ b/backend/seeders/20240610054534-demo-users.js @@ -1,35 +1,38 @@ "use strict"; +const bcrypt = require('bcrypt'); + module.exports = { up: async (queryInterface, Sequelize) => { + const hashedPassword = await bcrypt.hash('password123', 10); await queryInterface.bulkInsert( "users", [ { - username: "demoUser1", + name: "demoUser1", email: "demo1@example.com", - password: "password123", + password: hashedPassword, role: "user", createdAt: new Date(), }, { - username: "demoUser2", + name: "demoUser2", email: "demo2@example.com", - password: "password123", + password: hashedPassword, role: "user", createdAt: new Date(), }, { - username: "demoUser3", + name: "demoUser3", email: "demo3@example.com", - password: "password123", + password: hashedPassword, role: "user", createdAt: new Date(), }, { - username: "demoUser4", + name: "demoUser4", email: "demo4@example.com", - password: "password123", + password: hashedPassword, role: "user", createdAt: new Date(), }, From 067ee507b221bb4105f30add2da5d36c050f9e0d Mon Sep 17 00:00:00 2001 From: prashant-80 Date: Sun, 6 Oct 2024 21:01:06 +0530 Subject: [PATCH 079/524] Create validate wrapper #227 --- backend/src/models/Banner.js | 12 ++++-------- backend/src/models/Popup.js | 12 ++++-------- backend/src/utils/banner.helper.js | 7 +++++++ backend/src/utils/guideHelpers.js | 7 +++++++ backend/src/utils/popup.helper.js | 9 +++++++++ frontend/dist/index.html | 2 +- 6 files changed, 32 insertions(+), 17 deletions(-) diff --git a/backend/src/models/Banner.js b/backend/src/models/Banner.js index 833ca2a0..9f2c34df 100644 --- a/backend/src/models/Banner.js +++ b/backend/src/models/Banner.js @@ -1,5 +1,5 @@ -const { validateHexColor, validateCloseButtonAction } = require('../utils/guideHelpers'); -const { validatePosition } = require('../utils/banner.helper'); +const { validateHexColor, validateActionButton } = require('../utils/guideHelpers'); +const { validatePositionWrapper } = require('../utils/banner.helper'); module.exports = (sequelize, DataTypes) => { const Banner = sequelize.define('Banner', { @@ -8,9 +8,7 @@ module.exports = (sequelize, DataTypes) => { allowNull: false, validate: { isValidAction(value) { - if (!validateCloseButtonAction(value)) { - throw new Error('Invalid close button action'); - } + validateActionButton(value); }, }, }, @@ -19,9 +17,7 @@ module.exports = (sequelize, DataTypes) => { allowNull: false, validate: { isValidPosition(value) { - if (!validatePosition(value)) { - throw new Error('Invalid position'); - } + validatePositionWrapper(value); }, }, }, diff --git a/backend/src/models/Popup.js b/backend/src/models/Popup.js index 5dd4f7eb..25a0300e 100644 --- a/backend/src/models/Popup.js +++ b/backend/src/models/Popup.js @@ -1,5 +1,5 @@ -const { validateHexColor, validateCloseButtonAction } = require('../utils/guideHelpers'); -const { validatePopupSize } = require('../utils/popup.helper'); +const { validateHexColor, validateActionButton } = require('../utils/guideHelpers'); +const { validatePopupSizeWrapper } = require('../utils/popup.helper'); module.exports = (sequelize, DataTypes) => { const Popup = sequelize.define( @@ -15,9 +15,7 @@ module.exports = (sequelize, DataTypes) => { allowNull: false, validate: { isValidAction(value) { - if (!validateCloseButtonAction(value)) { - throw new Error('Invalid close button action'); - } + validateActionButton(value); }, }, }, @@ -26,9 +24,7 @@ module.exports = (sequelize, DataTypes) => { allowNull: false, validate: { isValidPopupSize(value) { - if (!validatePopupSize(value)) { - throw new Error('Invalid popup size'); - } + validatePopupSizeWrapper(value); }, }, }, diff --git a/backend/src/utils/banner.helper.js b/backend/src/utils/banner.helper.js index 2d8f8b5b..5c23eb8c 100644 --- a/backend/src/utils/banner.helper.js +++ b/backend/src/utils/banner.helper.js @@ -2,8 +2,15 @@ const validatePosition = (value) => { const validPositions = ["top", "bottom"]; return validPositions.includes(value.toLowerCase()); }; + +const validatePositionWrapper = (value) => { + if (!validatePosition(value)) { + throw new Error('Invalid position'); + } +}; module.exports = { validatePosition, + validatePositionWrapper }; \ No newline at end of file diff --git a/backend/src/utils/guideHelpers.js b/backend/src/utils/guideHelpers.js index 04a4138f..568528c5 100644 --- a/backend/src/utils/guideHelpers.js +++ b/backend/src/utils/guideHelpers.js @@ -22,9 +22,16 @@ const validateCloseButtonAction = (value) => { return validActions.includes(value); }; +const validateActionButton = (value) => { + if (!validateCloseButtonAction(value)) { + throw new Error('Invalid close button action'); + } +}; + module.exports = { isValidHexColor, validateHexColor, checkColorFields, validateCloseButtonAction, + validateActionButton }; \ No newline at end of file diff --git a/backend/src/utils/popup.helper.js b/backend/src/utils/popup.helper.js index be451cb0..41d258a8 100644 --- a/backend/src/utils/popup.helper.js +++ b/backend/src/utils/popup.helper.js @@ -3,6 +3,15 @@ const validatePopupSize = (value) => { return validSizes.includes(value); }; +const validatePopupSizeWrapper = (value) => { + if (!validatePopupSize(value)) { + throw new Error('Invalid popup size'); + } +}; + + + module.exports = { validatePopupSize, + validatePopupSizeWrapper }; diff --git a/frontend/dist/index.html b/frontend/dist/index.html index 3435691a..89687f27 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -5,7 +5,7 @@ Bluewave Onboarding - + From d25041181cd4ba5577b65bb974800e613ca3b395 Mon Sep 17 00:00:00 2001 From: mr-loop-1 Date: Mon, 7 Oct 2024 00:28:56 +0530 Subject: [PATCH 080/524] refactor: route guard check --- frontend/src/App.jsx | 11 ++++------- frontend/src/components/Private.jsx | 9 +++++---- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index bf92dc07..29c44651 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -7,7 +7,6 @@ import ForgotPasswordPage from "./scenes/login/ForgotPasswordPage"; import CheckYourEmailPage from "./scenes/login/CheckYourEmailPage"; import SetNewPasswordPage from "./scenes/login/SetNewPassword"; import Private from "./components/Private"; -import { useAuth } from "./services/authProvider"; import ProgressStepsMain from "./scenes/progressSteps/ProgressStepsMain"; import BannerPage from "./scenes/bannerPage/BannerPage"; import BannerDefaultPage from "./scenes/bannerPage/BannerDefaultPage"; @@ -21,22 +20,20 @@ import CreatePopupPage from "./scenes/popup/CreatePopupPage"; import { Error404 } from "./scenes/errors/404"; import { Error403 } from "./scenes/errors/403"; import HomePageTemplate from "./templates/HomePageTemplate/HomePageTemplate"; -import LoadingPage from "./components/LoadingPage/LoadingPage"; const App = () => { - const { isLoggedIn, isFetching } = useAuth(); return ( <> - : (isLoggedIn ? : )}> + }> } /> } /> } /> } /> - } /> - } /> - } /> + } /> + } /> + } /> } /> } /> } /> diff --git a/frontend/src/components/Private.jsx b/frontend/src/components/Private.jsx index aaab7f57..8db7c058 100644 --- a/frontend/src/components/Private.jsx +++ b/frontend/src/components/Private.jsx @@ -1,11 +1,12 @@ import React from 'react'; import { Navigate } from 'react-router-dom'; import { useAuth } from '../services/authProvider'; +import LoadingPage from './LoadingPage/LoadingPage' -const Private = ({Component}) => { - const { isLoggedIn } = useAuth(); +const Private = ({ Component }) => { + const { isLoggedIn, isFetching } = useAuth(); - return isLoggedIn ? : + return isFetching ? : (isLoggedIn ? : ); } -export default Private \ No newline at end of file +export default Private; \ No newline at end of file From 7504c13d5fc373f823227bf66fb381673e119d88 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 7 Oct 2024 02:21:11 +0530 Subject: [PATCH 081/524] directly add hashed password as bcrypt is causing issues from windows to linux mount, remove jwt secret --- backend/.env | 1 - backend/seeders/20240610054534-demo-users.js | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/backend/.env b/backend/.env index 420615a2..19bd5967 100644 --- a/backend/.env +++ b/backend/.env @@ -7,6 +7,5 @@ DEV_DB_PASSWORD=password123 DEV_DB_NAME=onboarding_db DEV_DB_HOST=localhost DEV_DB_PORT=5432 -JWT_SECRET=your_development_jwt_secret EMAIL_ENABLE=false \ No newline at end of file diff --git a/backend/seeders/20240610054534-demo-users.js b/backend/seeders/20240610054534-demo-users.js index f007d0f2..707d20f6 100644 --- a/backend/seeders/20240610054534-demo-users.js +++ b/backend/seeders/20240610054534-demo-users.js @@ -1,10 +1,8 @@ "use strict"; -const bcrypt = require('bcrypt'); - module.exports = { up: async (queryInterface, Sequelize) => { - const hashedPassword = await bcrypt.hash('password123', 10); + const hashedPassword = "$2b$10$tQiyc0NpG9UFoH6k6j6IbuPcZNFZFUkFMC28r9752WLqlDB.sIzC." //password123 await queryInterface.bulkInsert( "users", [ From 3e0657a91efb1df6ced533426be7b55d9a71d126 Mon Sep 17 00:00:00 2001 From: thomastepi Date: Sun, 6 Oct 2024 19:44:12 -0400 Subject: [PATCH 082/524] Test and fix hint endpoints --- backend/config/config.js | 2 +- backend/src/controllers/hint.controller.js | 2 +- backend/src/routes/hint.routes.js | 6 +++--- frontend/dist/index.html | 7 +++---- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/backend/config/config.js b/backend/config/config.js index 0e01dd7a..802011fb 100644 --- a/backend/config/config.js +++ b/backend/config/config.js @@ -4,7 +4,7 @@ module.exports = { username: process.env.DEV_DB_USERNAME, password: process.env.DEV_DB_PASSWORD, database: process.env.DEV_DB_NAME, - host: 'host.docker.internal', + host: 'db', dialect: "postgres", port: process.env.DEV_DB_PORT, logging: false, diff --git a/backend/src/controllers/hint.controller.js b/backend/src/controllers/hint.controller.js index f310b4f5..13471dbd 100644 --- a/backend/src/controllers/hint.controller.js +++ b/backend/src/controllers/hint.controller.js @@ -95,7 +95,7 @@ class HintController { async getHintById(req, res) { const { hintId } = req.params; - if (isNaN(hintId) || hintId.trim() === "") { + if (Number.isNaN(Number(hintId)) || hintId.trim() === "") { return res.status(400).json({ errors: [{ msg: "Invalid hint ID" }] }); } diff --git a/backend/src/routes/hint.routes.js b/backend/src/routes/hint.routes.js index 38dc4544..dba36727 100644 --- a/backend/src/routes/hint.routes.js +++ b/backend/src/routes/hint.routes.js @@ -5,10 +5,10 @@ const authenticateJWT = require("../middleware/auth.middleware"); const router = express.Router(); router.post("/add_hint", authenticateJWT, hintController.addHint); -router.delete("/delete_hint/:id", authenticateJWT, hintController.deleteHint); -router.put("/edit_hint/:id", authenticateJWT, hintController.updateHint); +router.delete("/delete_hint/:hintId", authenticateJWT, hintController.deleteHint); +router.put("/edit_hint/:hintId", authenticateJWT, hintController.updateHint); router.get("/all_hints", authenticateJWT, hintController.getAllHints); router.get("/hints", authenticateJWT, hintController.getHints); -router.get("/get_hint/:id", authenticateJWT, hintController.getHintById); +router.get("/get_hint/:hintId", authenticateJWT, hintController.getHintById); module.exports = router; \ No newline at end of file diff --git a/frontend/dist/index.html b/frontend/dist/index.html index 568852c5..7a190d2d 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -5,13 +5,12 @@ Bluewave Onboarding - - + + -
- +
From d6705a9d613b67c5729670d3afd4e16ec823ae83 Mon Sep 17 00:00:00 2001 From: thomastepi Date: Mon, 7 Oct 2024 00:03:22 -0400 Subject: [PATCH 083/524] enhance hint data validation --- backend/src/controllers/hint.controller.js | 77 ++-------------------- backend/src/models/Hint.js | 2 +- backend/src/utils/hintValidation.js | 44 +++++++++++++ frontend/dist/index.html | 32 ++++----- 4 files changed, 68 insertions(+), 87 deletions(-) create mode 100644 backend/src/utils/hintValidation.js diff --git a/backend/src/controllers/hint.controller.js b/backend/src/controllers/hint.controller.js index 13471dbd..d4054bfb 100644 --- a/backend/src/controllers/hint.controller.js +++ b/backend/src/controllers/hint.controller.js @@ -1,51 +1,17 @@ const HintService = require("../service/hint.service"); const { internalServerError } = require("../utils/errors"); -const { isValidHexColor } = require("../utils/guideHelpers"); +const validateHintData = require("../utils/hintValidation"); const db = require("../models"); const Hint = db.Hint; -const validateAction = (value) => { - const validActions = ["no action", "open url", "open url in a new tab"]; - return validActions.includes(value); -}; - class HintController { async addHint(req, res) { const userId = req.user.id; - const { - action, - headerBackgroundColor, - headerColor, - textColor, - buttonBackgroundColor, - buttonTextColor, - } = req.body; - - if (!action) { - return res.status(400).json({ - errors: [{ msg: "action is required" }], - }); - } - if (!validateAction(action)) { - return res.status(400).json({ - errors: [{ msg: "Invalid value for action" }], - }); - } + const validationErrors = validateHintData(req.body); - const colorFields = { - headerBackgroundColor, - headerColor, - textColor, - buttonBackgroundColor, - buttonTextColor, - }; - for (const [field, value] of Object.entries(colorFields)) { - if (value && !isValidHexColor(value)) { - return res.status(400).json({ - errors: [{ msg: `Invalid value for ${field}` }], - }); - } + if (validationErrors.length > 0) { + return res.status(400).json({ errors: validationErrors }); } try { @@ -120,40 +86,11 @@ class HintController { async updateHint(req, res) { const { hintId } = req.params; - const { - action, - headerBackgroundColor, - headerColor, - textColor, - buttonBackgroundColor, - buttonTextColor, - } = req.body; - - if (!action) { - return res.status(400).json({ - errors: [{ msg: "action is required" }], - }); - } - if (!validateAction(action)) { - return res.status(400).json({ - errors: [{ msg: "Invalid value for action" }], - }); - } + const validationErrors = validateHintData(req.body); - const colorFields = { - headerBackgroundColor, - headerColor, - textColor, - buttonBackgroundColor, - buttonTextColor, - }; - for (const [field, value] of Object.entries(colorFields)) { - if (value && !isValidHexColor(value)) { - return res.status(400).json({ - errors: [{ msg: `Invalid value for ${field}` }], - }); - } + if (validationErrors.length > 0) { + return res.status(400).json({ errors: validationErrors }); } try { diff --git a/backend/src/models/Hint.js b/backend/src/models/Hint.js index 48af96cb..eb60d15d 100644 --- a/backend/src/models/Hint.js +++ b/backend/src/models/Hint.js @@ -68,7 +68,7 @@ module.exports = (sequelize, DataTypes) => { textColor: { type: DataTypes.STRING, allowNull: false, - defaultValue: "#OOOOOO", + defaultValue: "#000000", validate: { isHexColor(value) { validateHexColor(value, "textColor"); diff --git a/backend/src/utils/hintValidation.js b/backend/src/utils/hintValidation.js new file mode 100644 index 00000000..7492958f --- /dev/null +++ b/backend/src/utils/hintValidation.js @@ -0,0 +1,44 @@ +const { isValidHexColor } = require("./guideHelpers"); + +const validateHintData = ({ + action, + headerBackgroundColor, + headerColor, + textColor, + buttonBackgroundColor, + buttonTextColor, +}) => { + const errors = []; + + // Validate action + if (!action) { + errors.push({ msg: "action is required" }); + return errors; + } + + const validActions = ["no action", "open url", "open url in a new tab"]; + if (!validActions.includes(action)) { + errors.push({ msg: "Invalid value for action" }); + return errors; + } + + // Validate color fields + const colorFields = { + headerBackgroundColor, + headerColor, + textColor, + buttonBackgroundColor, + buttonTextColor, + }; + + for (const [field, value] of Object.entries(colorFields)) { + if (value && !isValidHexColor(value)) { + errors.push({ msg: `Invalid value for ${field}` }); + return errors; + } + } + + return errors; +}; + +module.exports = validateHintData; diff --git a/frontend/dist/index.html b/frontend/dist/index.html index 872b0ec4..e868de03 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -1,16 +1,16 @@ - - - - - - - Bluewave Onboarding - - - - - -
- - - + + + + + + + Bluewave Onboarding + + + + + +
+ + + From c0e6e85ed29eec4a7eb75c8fed9c6d2b062f18eb Mon Sep 17 00:00:00 2001 From: mr-loop-1 Date: Mon, 7 Oct 2024 21:48:16 +0530 Subject: [PATCH 084/524] add: store userInfo in localstorage for sidebar --- .../components/LoadingPage/Loading.module.css | 19 ++++++++++++++++--- .../components/LoadingPage/LoadingPage.jsx | 10 ++++++++-- .../UserProfileSidebar/UserProfileSidebar.jsx | 4 ++-- frontend/src/services/authProvider.jsx | 3 ++- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/LoadingPage/Loading.module.css b/frontend/src/components/LoadingPage/Loading.module.css index 150dce39..e0d0e9c0 100644 --- a/frontend/src/components/LoadingPage/Loading.module.css +++ b/frontend/src/components/LoadingPage/Loading.module.css @@ -1,6 +1,19 @@ @import url(../../styles/variables.css); +.container{ + display: flex; + flex-direction: column; + width:100vw; + height:100vh; + flex-grow: 1; +} + .loading-container { + display: flex; + flex-grow: 1; +} + +.background-pattern { display: flex; flex-direction: column; width: 400px; @@ -11,13 +24,13 @@ background-position: center -350px; } -.loading { +.loading-spinner { display: flex; margin-top: 100px; justify-content: center; } -.loading::after { +.loading-spinner::after { content: ""; width: 50px; height: 50px; @@ -27,7 +40,7 @@ animation: loading 1s ease infinite; } -@keyframes loading { +@keyframes loading-spinner { to { transform: rotate(1turn); } diff --git a/frontend/src/components/LoadingPage/LoadingPage.jsx b/frontend/src/components/LoadingPage/LoadingPage.jsx index 6980a9c1..27f4b7f8 100644 --- a/frontend/src/components/LoadingPage/LoadingPage.jsx +++ b/frontend/src/components/LoadingPage/LoadingPage.jsx @@ -1,10 +1,16 @@ import React from 'react'; import styles from './Loading.module.css'; +import LeftMenu from '../LeftMenu/LeftMenu'; const LoadingPage = () => { return ( -
-
+
+
+ +
+
+
+
); }; diff --git a/frontend/src/components/UserProfileSidebar/UserProfileSidebar.jsx b/frontend/src/components/UserProfileSidebar/UserProfileSidebar.jsx index 91c1fcf8..ce78717d 100644 --- a/frontend/src/components/UserProfileSidebar/UserProfileSidebar.jsx +++ b/frontend/src/components/UserProfileSidebar/UserProfileSidebar.jsx @@ -21,8 +21,8 @@ function UserProfileSidebar() {
-
{userInfo.fullName}
-
{userInfo.role}
+
{userInfo?.fullName}
+
{userInfo?.role}
From b7125eb5bdd43c8e30b782621dcb9f483a7df6e3 Mon Sep 17 00:00:00 2001 From: erenfn Date: Tue, 8 Oct 2024 13:11:15 +0300 Subject: [PATCH 086/524] fixed close icon --- .../ProgressSteps/TeamMemberList/TeamMembersList.jsx | 2 +- frontend/src/scenes/progressSteps/ProgressStepsMain.jsx | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/ProgressSteps/TeamMemberList/TeamMembersList.jsx b/frontend/src/components/ProgressSteps/TeamMemberList/TeamMembersList.jsx index fa888b99..d4758d08 100644 --- a/frontend/src/components/ProgressSteps/TeamMemberList/TeamMembersList.jsx +++ b/frontend/src/components/ProgressSteps/TeamMemberList/TeamMembersList.jsx @@ -18,7 +18,7 @@ const TeamMembersList = ({ members, setMembers }) => { {member} handleDeleteMember(index)} - style={{color: '#98A2B3', fontSize: '12px', cursor: 'pointer'}} + style={{color: '#98A2B3', fontSize: '12px', cursor: 'pointer', zIndex:1000}} />
))} diff --git a/frontend/src/scenes/progressSteps/ProgressStepsMain.jsx b/frontend/src/scenes/progressSteps/ProgressStepsMain.jsx index fd355c5d..5bee055d 100644 --- a/frontend/src/scenes/progressSteps/ProgressStepsMain.jsx +++ b/frontend/src/scenes/progressSteps/ProgressStepsMain.jsx @@ -4,8 +4,10 @@ import styles from './ProgressStepsMain.module.scss'; import Button from '../../components/Button/Button'; import CheckboxHRM from '../../components/Checkbox/CheckboxHRM'; import TeamMembersList from '../../components/ProgressSteps/TeamMemberList/TeamMembersList'; +import { useNavigate } from "react-router-dom"; const ProgressStepsMain = () => { + const navigate = useNavigate(); const NUMBER_OF_STEPS = 4; const [step, setStep] = useState(1); const [teamMembersEmails, setTeamMembersEmails] = useState([]); @@ -123,8 +125,8 @@ const ProgressStepsMain = () => { const fourthPage = () => { return ( <> -
-
) From 0052fb1a3a6642eb08d58af497dfa0365d54b26b Mon Sep 17 00:00:00 2001 From: mr-loop-1 Date: Wed, 9 Oct 2024 16:14:59 +0530 Subject: [PATCH 087/524] remove background pattern --- .../src/components/LoadingPage/Loading.module.css | 13 +------------ frontend/src/components/LoadingPage/LoadingPage.jsx | 4 +--- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/LoadingPage/Loading.module.css b/frontend/src/components/LoadingPage/Loading.module.css index 378f5dba..e0e1efa2 100644 --- a/frontend/src/components/LoadingPage/Loading.module.css +++ b/frontend/src/components/LoadingPage/Loading.module.css @@ -13,20 +13,9 @@ flex-grow: 1; } -.background-pattern { - display: flex; - flex-direction: column; - width: 400px; - margin: 0 auto; - padding: 20px; - background-repeat: no-repeat; - background-image: url('../../assets/auth-screen-background.svg'); - background-position: center -350px; -} - .loading { display: flex; - margin-top: 100px; + margin: auto; justify-content: center; } diff --git a/frontend/src/components/LoadingPage/LoadingPage.jsx b/frontend/src/components/LoadingPage/LoadingPage.jsx index 75b3f808..ad9a23df 100644 --- a/frontend/src/components/LoadingPage/LoadingPage.jsx +++ b/frontend/src/components/LoadingPage/LoadingPage.jsx @@ -7,9 +7,7 @@ const LoadingPage = () => {
-
-
-
+
); From bad9d8c310aa0967f18b6f024c6e218d0c53441b Mon Sep 17 00:00:00 2001 From: erenfn <81182796+erenfn@users.noreply.github.com> Date: Wed, 9 Oct 2024 20:25:11 +0300 Subject: [PATCH 088/524] Update backend/src/controllers/banner.controller.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- backend/src/controllers/banner.controller.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/controllers/banner.controller.js b/backend/src/controllers/banner.controller.js index c9559f15..a885bdbd 100644 --- a/backend/src/controllers/banner.controller.js +++ b/backend/src/controllers/banner.controller.js @@ -1,7 +1,7 @@ const bannerService = require("../service/banner.service.js"); -const { internalServerError } = require("../utils/errors.js"); -const { isValidHexColor, checkColorFields, validateCloseButtonAction } = require("../utils/guideHelpers.js"); -const { validatePosition } = require("../utils/banner.helper.js"); +const { internalServerError } = require("../utils/errors"); +const { isValidHexColor, checkColorFields, validateCloseButtonAction } = require("../utils/guideHelpers"); +const { validatePosition } = require("../utils/banner.helper"); const db = require("../models/index.js"); const Banner = db.Banner; From fb4471781bcab83d4b316225a811fe9bcb76175e Mon Sep 17 00:00:00 2001 From: erenfn Date: Wed, 9 Oct 2024 20:54:44 +0300 Subject: [PATCH 089/524] fixed checkColorFields --- backend/src/controllers/banner.controller.js | 18 ++++-------- backend/src/controllers/popup.controller.js | 31 ++++++++------------ backend/src/utils/guideHelpers.js | 6 ++-- 3 files changed, 21 insertions(+), 34 deletions(-) diff --git a/backend/src/controllers/banner.controller.js b/backend/src/controllers/banner.controller.js index a885bdbd..c54d7fbc 100644 --- a/backend/src/controllers/banner.controller.js +++ b/backend/src/controllers/banner.controller.js @@ -1,6 +1,6 @@ const bannerService = require("../service/banner.service.js"); const { internalServerError } = require("../utils/errors"); -const { isValidHexColor, checkColorFields, validateCloseButtonAction } = require("../utils/guideHelpers"); +const { isValidHexColor, checkColorFieldsFail, validateCloseButtonAction } = require("../utils/guideHelpers"); const { validatePosition } = require("../utils/banner.helper"); const db = require("../models/index.js"); const Banner = db.Banner; @@ -27,7 +27,8 @@ class BannerController { } const colorFields = { fontColor, backgroundColor }; - checkColorFields(colorFields, res); + const colorCheck = checkColorFieldsFail(colorFields, res) + if(colorCheck){return colorCheck}; try { const newBannerData = { ...req.body, createdBy: userId }; @@ -97,16 +98,9 @@ class BannerController { .json({ errors: [{ msg: "Invalid value for closeButtonAction" }] }); } - const colorFields = ["fontColor", "backgroundColor"]; - for (const field of colorFields) { - if (req.body[field] && !isValidHexColor(req.body[field])) { - return res - .status(400) - .json({ - errors: [{ msg: `${field} must be a valid hex color code` }], - }); - } - } + const colorFields = { fontColor, backgroundColor }; + const colorCheck = checkColorFieldsFail(colorFields, res) + if(colorCheck){return colorCheck}; const updatedBanner = await bannerService.updateBanner(id, req.body); res.status(200).json(updatedBanner); diff --git a/backend/src/controllers/popup.controller.js b/backend/src/controllers/popup.controller.js index 9b736f2e..5bbd2b5a 100644 --- a/backend/src/controllers/popup.controller.js +++ b/backend/src/controllers/popup.controller.js @@ -1,6 +1,6 @@ const popupService = require("../service/popup.service"); const { internalServerError } = require("../utils/errors"); -const { isValidHexColor, checkColorFields, validateCloseButtonAction } = require("../utils/guideHelpers"); +const { isValidHexColor, checkColorFieldsFail, validateCloseButtonAction } = require("../utils/guideHelpers"); const db = require("../models"); const Popup = db.Popup; const { validatePopupSize } = require("../utils/popup.helper"); @@ -44,7 +44,8 @@ class PopupController { buttonBackgroundColor, buttonTextColor, }; - checkColorFields(colorFields, res); + const colorCheck = checkColorFieldsFail(colorFields, res) + if(colorCheck){return colorCheck}; try { const newPopupData = { ...req.body, createdBy: userId }; @@ -114,23 +115,15 @@ class PopupController { .json({ errors: [{ msg: "Invalid value for closeButtonAction" }] }); } - const colorFields = [ - "headerBackgroundColor", - "headerColor", - "textColor", - "buttonBackgroundColor", - "buttonTextColor", - ]; - - for (const field of colorFields) { - if (req.body[field] && !isValidHexColor(req.body[field])) { - return res - .status(400) - .json({ - errors: [{ msg: `${field} must be a valid hex color code` }], - }); - } - } + const colorFields = { + headerBackgroundColor, + headerColor, + textColor, + buttonBackgroundColor, + buttonTextColor, + }; + const colorCheck = checkColorFieldsFail(colorFields, res) + if(colorCheck){return colorCheck}; const updatedPopup = await popupService.updatePopup(id, req.body); res.status(200).json(updatedPopup); diff --git a/backend/src/utils/guideHelpers.js b/backend/src/utils/guideHelpers.js index 28abeb4d..b5dd5126 100644 --- a/backend/src/utils/guideHelpers.js +++ b/backend/src/utils/guideHelpers.js @@ -9,7 +9,7 @@ const validateHexColor = (value, fieldName) => { } }; -const checkColorFields = (colorFields, res) => { +const checkColorFieldsFail = (colorFields, res) => { for (const [field, value] of Object.entries(colorFields)) { if (value && !isValidHexColor(value)) { return res.status(400).json({ @@ -17,7 +17,7 @@ const checkColorFields = (colorFields, res) => { }); } } - return true; + return false; }; const validateCloseButtonAction = (value) => { @@ -34,7 +34,7 @@ const validateActionButton = (value) => { module.exports = { isValidHexColor, validateHexColor, - checkColorFields, + checkColorFieldsFail, validateCloseButtonAction, validateActionButton }; \ No newline at end of file From f409742018b7fdc52a0f0875c91597fa1a80fa46 Mon Sep 17 00:00:00 2001 From: erenfn Date: Thu, 10 Oct 2024 17:58:47 +0300 Subject: [PATCH 090/524] fix settings --- frontend/package-lock.json | 347 ++++++++++++------ frontend/package.json | 6 +- frontend/src/App.jsx | 3 +- frontend/src/assets/{theme.js => theme.jsx} | 9 + .../components/DropdownMenu/DropdownMenu.jsx | 2 +- frontend/src/index.jsx | 2 +- frontend/src/scenes/settings/Settings.jsx | 5 +- .../SettingsTabs/PasswordTab/PasswordTab.css | 65 ---- .../SettingsTabs/PasswordTab/PasswordTab.jsx | 129 ++++--- .../PasswordTab/PasswordTab.module.css | 37 ++ .../SettingsTabs/ProfileTab/ProfileTab.css | 83 ----- .../SettingsTabs/ProfileTab/ProfileTab.jsx | 142 ++++--- .../ProfileTab/ProfileTab.module.css | 78 ++++ .../settings/SettingsTabs/TeamTab/TeamTab.css | 38 -- .../settings/SettingsTabs/TeamTab/TeamTab.jsx | 81 ++-- .../SettingsTabs/TeamTab/TeamTab.module.css | 37 ++ .../TeamTab/TeamTable/TeamTable.css | 17 - .../TeamTab/TeamTable/TeamTable.jsx | 48 +-- .../TeamTab/TeamTable/TeamTable.module.css | 19 + 19 files changed, 654 insertions(+), 494 deletions(-) rename frontend/src/assets/{theme.js => theme.jsx} (87%) delete mode 100644 frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.css create mode 100644 frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.module.css delete mode 100644 frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.css create mode 100644 frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.module.css delete mode 100644 frontend/src/scenes/settings/SettingsTabs/TeamTab/TeamTab.css create mode 100644 frontend/src/scenes/settings/SettingsTabs/TeamTab/TeamTab.module.css delete mode 100644 frontend/src/scenes/settings/SettingsTabs/TeamTab/TeamTable/TeamTable.css create mode 100644 frontend/src/scenes/settings/SettingsTabs/TeamTab/TeamTable/TeamTable.module.css diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6bec35f8..789f6bf3 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,8 +10,9 @@ "dependencies": { "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", - "@mui/icons-material": "^5.15.19", - "@mui/material": "^5.16.5", + "@mui/icons-material": "^6.1.3", + "@mui/lab": "^6.0.0-beta.11", + "@mui/material": "^6.1.3", "@mui/x-date-pickers": "^7.3.1", "@mui/x-date-pickers-pro": "^7.3.1", "@vitejs/plugin-react-swc": "^3.6.0", @@ -23,6 +24,7 @@ "mui-color-input": "^4.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-icons": "^5.3.0", "react-quill": "^2.0.0", "react-redux": "^9.1.2", "react-router": "^6.23.0", @@ -1029,6 +1031,44 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", + "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", + "license": "MIT" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -1174,10 +1214,72 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.58", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.58.tgz", + "integrity": "sha512-P0E7ZrxOuyYqBvVv9w8k7wm+Xzx/KRu+BGgFcR2htTsGCpJNQJCSUXNUZ50MUmSU9hzqhwbQWNXhV1MBTl6F7A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@floating-ui/react-dom": "^2.1.1", + "@mui/types": "^7.2.15", + "@mui/utils": "6.0.0-rc.0", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0", + "react": "^17.0.0 || ^18.0.0", + "react-dom": "^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/base/node_modules/@mui/utils": { + "version": "6.0.0-rc.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.0.0-rc.0.tgz", + "integrity": "sha512-tBp0ILEXDL0bbDDT8PnZOjCqSm5Dfk2N0Z45uzRw+wVl6fVvloC9zw8avl+OdX1Bg3ubs/ttKn8nRNv17bpM5A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@mui/types": "^7.2.15", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz", - "integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.1.3.tgz", + "integrity": "sha512-ajMUgdfhTb++rwqj134Cq9f4SRN8oXUqMRnY72YBnXiXai3olJLLqETheRlq3MM8wCKrbq7g6j7iWL1VvP44VQ==", "license": "MIT", "funding": { "type": "opencollective", @@ -1185,24 +1287,24 @@ } }, "node_modules/@mui/icons-material": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.16.7.tgz", - "integrity": "sha512-UrGwDJCXEszbDI7yV047BYU5A28eGJ79keTCP4cc74WyncuVrnurlmIRxaHL8YK+LI1Kzq+/JM52IAkNnv4u+Q==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.1.3.tgz", + "integrity": "sha512-QBQCCIMSAv6IkArTg4Hg8q2sJRhHOci8oPAlkHWFlt2ghBdy3EqyLbIELLE/bhpqhX+E/ZkPYGIUQCd5/L0owA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9" + "@babel/runtime": "^7.25.6" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@mui/material": "^5.0.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@mui/material": "^6.1.3", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -1210,27 +1312,22 @@ } } }, - "node_modules/@mui/material": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz", - "integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==", + "node_modules/@mui/lab": { + "version": "6.0.0-beta.11", + "resolved": "https://registry.npmjs.org/@mui/lab/-/lab-6.0.0-beta.11.tgz", + "integrity": "sha512-IoYzxAepMs0gnQ2tTMokEd8Bmqt+To/8HQyzjrQCbYZmKyYR/6aK3wm3Y5NpfSLuBo1UrkeXWyKsHeRcHreGdQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/core-downloads-tracker": "^5.16.7", - "@mui/system": "^5.16.7", - "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.6", - "@popperjs/core": "^2.11.8", - "@types/react-transition-group": "^4.4.10", - "clsx": "^2.1.0", - "csstype": "^3.1.3", - "prop-types": "^15.8.1", - "react-is": "^18.3.1", - "react-transition-group": "^4.4.5" + "@babel/runtime": "^7.25.6", + "@mui/base": "5.0.0-beta.58", + "@mui/system": "^6.1.3", + "@mui/types": "^7.2.18", + "@mui/utils": "^6.1.3", + "clsx": "^2.1.1", + "prop-types": "^15.8.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", @@ -1239,9 +1336,11 @@ "peerDependencies": { "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" + "@mui/material": "^6.1.3", + "@mui/material-pigment-css": "^6.1.3", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -1250,31 +1349,37 @@ "@emotion/styled": { "optional": true }, + "@mui/material-pigment-css": { + "optional": true + }, "@types/react": { "optional": true } } }, - "node_modules/@mui/material/node_modules/@mui/private-theming": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz", - "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==", + "node_modules/@mui/lab/node_modules/@mui/utils": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.3.tgz", + "integrity": "sha512-4JBpLkjprlKjN10DGb1aiy/ii9TKbQ601uSHtAmYFAS879QZgAD7vRnv/YBE4iBbc7NXzFgbQMCOFrupXWekIA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.16.6", - "prop-types": "^15.8.1" + "@babel/runtime": "^7.25.6", + "@mui/types": "^7.2.18", + "@types/prop-types": "^15.7.13", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -1282,28 +1387,39 @@ } } }, - "node_modules/@mui/material/node_modules/@mui/styled-engine": { - "version": "5.16.6", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz", - "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==", + "node_modules/@mui/material": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.1.3.tgz", + "integrity": "sha512-loV5MBoMKLrK80JeWINmQ1A4eWoLv51O2dBPLJ260IAhupkB3Wol8lEQTEvvR2vO3o6xRHuXe1WaQEP6N3riqg==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "@emotion/cache": "^11.11.0", + "@babel/runtime": "^7.25.6", + "@mui/core-downloads-tracker": "^6.1.3", + "@mui/system": "^6.1.3", + "@mui/types": "^7.2.18", + "@mui/utils": "^6.1.3", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", "csstype": "^3.1.3", - "prop-types": "^15.8.1" + "prop-types": "^15.8.1", + "react-is": "^18.3.1", + "react-transition-group": "^4.4.5" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@emotion/react": "^11.4.1", + "@emotion/react": "^11.5.0", "@emotion/styled": "^11.3.0", - "react": "^17.0.0 || ^18.0.0" + "@mui/material-pigment-css": "^6.1.3", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/react": { @@ -1311,58 +1427,53 @@ }, "@emotion/styled": { "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true } } }, - "node_modules/@mui/material/node_modules/@mui/system": { - "version": "5.16.7", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz", - "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==", + "node_modules/@mui/material/node_modules/@mui/utils": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.3.tgz", + "integrity": "sha512-4JBpLkjprlKjN10DGb1aiy/ii9TKbQ601uSHtAmYFAS879QZgAD7vRnv/YBE4iBbc7NXzFgbQMCOFrupXWekIA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.16.6", - "@mui/styled-engine": "^5.16.6", - "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.6", - "clsx": "^2.1.0", - "csstype": "^3.1.3", - "prop-types": "^15.8.1" + "@babel/runtime": "^7.25.6", + "@mui/types": "^7.2.18", + "@types/prop-types": "^15.7.13", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" }, "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, "@types/react": { "optional": true } } }, "node_modules/@mui/private-theming": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.1.tgz", - "integrity": "sha512-JlrjIdhyZUtewtdAuUsvi3ZnO0YS49IW4Mfz19ZWTlQ0sDGga6LNPVwHClWr2/zJK2we2BQx9/i8M32rgKuzrg==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.3.tgz", + "integrity": "sha512-XK5OYCM0x7gxWb/WBEySstBmn+dE3YKX7U7jeBRLm6vHU5fGUd7GiJWRirpivHjOK9mRH6E1MPIVd+ze5vguKQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.25.6", - "@mui/utils": "^6.1.1", + "@mui/utils": "^6.1.3", "prop-types": "^15.8.1" }, "engines": { @@ -1383,15 +1494,14 @@ } }, "node_modules/@mui/private-theming/node_modules/@mui/utils": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.1.tgz", - "integrity": "sha512-HlRrgdJSPbYDXPpoVMWZV8AE7WcFtAk13rWNWAEVWKSanzBBkymjz3km+Th/Srowsh4pf1fTSP1B0L116wQBYw==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.3.tgz", + "integrity": "sha512-4JBpLkjprlKjN10DGb1aiy/ii9TKbQ601uSHtAmYFAS879QZgAD7vRnv/YBE4iBbc7NXzFgbQMCOFrupXWekIA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.25.6", - "@mui/types": "^7.2.17", - "@types/prop-types": "^15.7.12", + "@mui/types": "^7.2.18", + "@types/prop-types": "^15.7.13", "clsx": "^2.1.1", "prop-types": "^15.8.1", "react-is": "^18.3.1" @@ -1414,14 +1524,14 @@ } }, "node_modules/@mui/styled-engine": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.1.tgz", - "integrity": "sha512-HJyIoMpFb11fnHuRtUILOXgq6vj4LhIlE8maG4SwP/W+E5sa7HFexhnB3vOMT7bKys4UKNxhobC8jwWxYilGsA==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.1.3.tgz", + "integrity": "sha512-i4yh9m+eMZE3cNERpDhVr6Wn73Yz6C7MH0eE2zZvw8d7EFkIJlCQNZd1xxGZqarD2DDq2qWHcjIOucWGhxACtA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.25.6", "@emotion/cache": "^11.13.1", + "@emotion/serialize": "^1.3.2", "@emotion/sheet": "^1.4.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1448,17 +1558,16 @@ } }, "node_modules/@mui/system": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.1.tgz", - "integrity": "sha512-PaYsCz2tUOcpu3T0okDEsSuP/yCDIj9JZ4Tox1JovRSKIjltHpXPsXZSGr3RiWdtM1MTQMFMCZzu0+CKbyy+Kw==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.1.3.tgz", + "integrity": "sha512-ILaD9UsLTBLjMcep3OumJMXh1PYr7aqnkHm/L47bH46+YmSL1zWAX6tWG8swEQROzW2GvYluEMp5FreoxOOC6w==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.25.6", - "@mui/private-theming": "^6.1.1", - "@mui/styled-engine": "^6.1.1", - "@mui/types": "^7.2.17", - "@mui/utils": "^6.1.1", + "@mui/private-theming": "^6.1.3", + "@mui/styled-engine": "^6.1.3", + "@mui/types": "^7.2.18", + "@mui/utils": "^6.1.3", "clsx": "^2.1.1", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -1489,15 +1598,14 @@ } }, "node_modules/@mui/system/node_modules/@mui/utils": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.1.tgz", - "integrity": "sha512-HlRrgdJSPbYDXPpoVMWZV8AE7WcFtAk13rWNWAEVWKSanzBBkymjz3km+Th/Srowsh4pf1fTSP1B0L116wQBYw==", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.3.tgz", + "integrity": "sha512-4JBpLkjprlKjN10DGb1aiy/ii9TKbQ601uSHtAmYFAS879QZgAD7vRnv/YBE4iBbc7NXzFgbQMCOFrupXWekIA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.25.6", - "@mui/types": "^7.2.17", - "@types/prop-types": "^15.7.12", + "@mui/types": "^7.2.18", + "@types/prop-types": "^15.7.13", "clsx": "^2.1.1", "prop-types": "^15.8.1", "react-is": "^18.3.1" @@ -1520,9 +1628,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.17", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.17.tgz", - "integrity": "sha512-oyumoJgB6jDV8JFzRqjBo2daUuHpzDjoO/e3IrRhhHo/FxJlaVhET6mcNrKHUq2E+R+q3ql0qAtvQ4rfWHhAeQ==", + "version": "7.2.18", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.18.tgz", + "integrity": "sha512-uvK9dWeyCJl/3ocVnTOS6nlji/Knj8/tVqVX03UVTpdmTJYu/s4jtDd9Kvv0nRGE0CUSNW1UYAci7PYypjealg==", "license": "MIT", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" @@ -4403,9 +4511,9 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "license": "MIT", "engines": { @@ -5555,9 +5663,9 @@ } }, "node_modules/express": { - "version": "4.21.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", - "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5566,7 +5674,7 @@ "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -8381,6 +8489,15 @@ "dev": true, "license": "MIT" }, + "node_modules/react-icons": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz", + "integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index dd7552d8..7eeb2e33 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,8 +6,9 @@ "dependencies": { "@emotion/react": "^11.13.3", "@emotion/styled": "^11.13.0", - "@mui/icons-material": "^5.15.19", - "@mui/material": "^5.16.5", + "@mui/icons-material": "^6.1.3", + "@mui/lab": "^6.0.0-beta.11", + "@mui/material": "^6.1.3", "@mui/x-date-pickers": "^7.3.1", "@mui/x-date-pickers-pro": "^7.3.1", "@vitejs/plugin-react-swc": "^3.6.0", @@ -19,6 +20,7 @@ "mui-color-input": "^4.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", + "react-icons": "^5.3.0", "react-quill": "^2.0.0", "react-redux": "^9.1.2", "react-router": "^6.23.0", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 6218b4ee..a9d1f51e 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -38,6 +38,7 @@ const App = () => { } /> } /> } /> + } /> } /> @@ -50,7 +51,7 @@ const App = () => { } /> } /> } /> - } /> + ); diff --git a/frontend/src/assets/theme.js b/frontend/src/assets/theme.jsx similarity index 87% rename from frontend/src/assets/theme.js rename to frontend/src/assets/theme.jsx index d68e1f3b..5774a539 100644 --- a/frontend/src/assets/theme.js +++ b/frontend/src/assets/theme.jsx @@ -20,6 +20,15 @@ export const lightTheme = createTheme({ }, }, }, + MuiTab: { + styleOverrides: { + root: { + textTransform: 'none', + fontSize: '14px', + padding: '3px 9px' + }, + }, + }, MuiDrawer: { styleOverrides: { paper: { diff --git a/frontend/src/components/DropdownMenu/DropdownMenu.jsx b/frontend/src/components/DropdownMenu/DropdownMenu.jsx index 39c892e0..8038abcc 100644 --- a/frontend/src/components/DropdownMenu/DropdownMenu.jsx +++ b/frontend/src/components/DropdownMenu/DropdownMenu.jsx @@ -22,7 +22,7 @@ const DropdownMenu = () => { const menuItems = [ { text: 'Profile', icon: }, - { text: 'Settings', icon: }, + { text: 'Password', icon: }, { text: 'Logout', icon: , onClick: handleLogoutClick }, ]; diff --git a/frontend/src/index.jsx b/frontend/src/index.jsx index c9a6f6dd..c250cf60 100644 --- a/frontend/src/index.jsx +++ b/frontend/src/index.jsx @@ -3,7 +3,7 @@ import ReactDOM from "react-dom/client"; import App from "./App.jsx"; import "./index.css"; import { BrowserRouter as Router} from "react-router-dom"; -import { lightTheme } from "./assets/theme.js"; +import { lightTheme } from "./assets/theme"; import { ThemeProvider } from "@mui/material"; import { AuthProvider } from "./services/authProvider.jsx"; import Toast from "./components/Toast/Toast.jsx"; diff --git a/frontend/src/scenes/settings/Settings.jsx b/frontend/src/scenes/settings/Settings.jsx index 89916d88..feef1687 100644 --- a/frontend/src/scenes/settings/Settings.jsx +++ b/frontend/src/scenes/settings/Settings.jsx @@ -1,12 +1,9 @@ import React from "react"; import SettingsTabs from "./SettingsTabs/SettingsTabs"; -import HomePageTemplate from "../../components/templates/HomePageTemplate"; const Settings = () => { return ( - - - + ); }; diff --git a/frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.css b/frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.css deleted file mode 100644 index faa72ee9..00000000 --- a/frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.css +++ /dev/null @@ -1,65 +0,0 @@ -*{ - font-size: 13px; -} -.form{ - padding-bottom: 20px; -} -.current-password-element{ - display: flex; - justify-content: space-between; - margin: 0px; -} -.form-elements{ - display: flex; - justify-content: space-between; - margin: 25px 0px; -} -.label{ - font-weight: 600; -} -.support-text{ - margin: 0; - font-weight: 400; - color: #667085; - padding-right: 25px; -} -.input{ - width: 452px; - height: 34px; - border: 1px solid #D0D5DD; - border-radius: 4px; - gap: 8px; -} -.update{ - color: #1976d2; - border: none; - background: none; - cursor: pointer; -} -.alert{ - display: flex; - justify-content: flex-end; -} -.alert-message{ - display: flex; - justify-content: flex-end; - width: 452px; - gap: 12px; - padding: 16px; - border: 1px solid #FEC84B; - color: #DC6803; -} -.save-button{ - display: flex; - align-items: flex-end; -} -.save{ - width: 160px; - height: 34px; - color: white; - background-color: #4C7DE7; - padding: 10px 16px; - border: 1px solid #175CD3; - border-radius: 4px; - cursor: pointer; -} \ No newline at end of file diff --git a/frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.jsx b/frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.jsx index 7b049771..f863efd5 100644 --- a/frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.jsx +++ b/frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.jsx @@ -1,55 +1,88 @@ -import React from "react"; +import React, { useState } from "react"; import { LuAlertTriangle } from "react-icons/lu"; -import "./PasswordTab.css"; +import styles from "./PasswordTab.module.css"; +import CustomTextField from "../../../../components/TextFieldComponents/CustomTextField/CustomTextField"; +import Button from "../../../../components/Button/Button"; const PasswordTab = () => { + const [currentPassword, setCurrentPassword] = useState(''); + const [newPassword, setNewPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + + const handleCurrentPasswordChange = (e) => { + setCurrentPassword(e.target.value); + }; + + const handleNewPasswordChange = (e) => { + setNewPassword(e.target.value); + }; + + const handleConfirmPasswordChange = (e) => { + setConfirmPassword(e.target.value); + }; + + const handleSubmit = (e) => { + e.preventDefault(); + // Add logic to handle password change + }; + return ( -
-
-
- - -
-
- - -
-
- - -
-
-

- - New password must contain at least 8 characters and must have at least one uppercase letter, one number and one symbol. -

-
-
- -
-
-
+
+
+
Current Password:
+ +
+
+
New Password:
+ +
+
+
Confirm New Password:
+ +
+
+

+ + + + New password must contain at least 8 characters and must have at least one uppercase letter, one number, and one symbol. +

+
+
+
+
); }; diff --git a/frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.module.css b/frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.module.css new file mode 100644 index 00000000..a3aa5d1d --- /dev/null +++ b/frontend/src/scenes/settings/SettingsTabs/PasswordTab/PasswordTab.module.css @@ -0,0 +1,37 @@ + +.form { + padding-bottom: 20px; + display: flex; + flex-direction: column; +} + +.label { + font-size: 13px; + font-weight: 700; + line-height: 20px; + text-align: left; + flex-grow: 1; + +} +.block{ + display: flex; + justify-content: space-between; + align-items: center; + +} + +.alert { + display: flex; + justify-content: flex-end; +} + +.alertMessage { + display: flex; + width: 450px; + gap: 12px; + padding: 16px; + border: 1px solid #FEC84B; + color: #DC6803; + font-size: 14px; + box-sizing: border-box; +} diff --git a/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.css b/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.css deleted file mode 100644 index 80ecd73d..00000000 --- a/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.css +++ /dev/null @@ -1,83 +0,0 @@ -*{ - font-size: 13px; -} -.form{ - padding-bottom: 20px; - border-bottom: 1px solid #EEEEEE; -} -.first-name-element{ - display: flex; - justify-content: space-between; - margin: 0px; -} -.form-elements{ - display: flex; - justify-content: space-between; - margin: 25px 0px; -} -.photo-elements{ - display: flex; - gap: 12px; - margin: 30px 0px; -} -.photo-options{ - display: flex; - gap: 20px; -} -.label-elements{ - display: flex; - flex-direction: column; -} -.label{ - font-weight: 600; -} -.support-text{ - margin: 0; - font-weight: 400; - color: #667085; - padding-right: 25px; -} -.input{ - width: 378px; - height: 34px; - border: 1px solid #D0D5DD; - border-radius: 4px; -} -.update{ - color: #1976d2; - border: none; - background: none; - cursor: pointer; -} -.button-options{ - display: flex; - gap: 16px; -} -.save-button{ - display: flex; - justify-content: flex-end; -} -.save{ - width: 160px; - height: 34px; - color: white; - background-color: #4C7DE7; - padding: 10px 16px; - border: 1px solid #175CD3; - border-radius: 4px; - cursor: pointer; -} -.delete-heading{ - margin-top: 10px; - margin-bottom: 0px; -} -.delete{ - width: 160px; - height: 34px; - color: white; - background-color: #DB504A; - border: 1px solid #DB504A; - margin-top: 20px; - border-radius: 4px; - cursor: pointer; -} \ No newline at end of file diff --git a/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx b/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx index 0915f25e..f0feee22 100644 --- a/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx +++ b/frontend/src/scenes/settings/SettingsTabs/ProfileTab/ProfileTab.jsx @@ -1,79 +1,99 @@ import React from "react"; import Avatar from "../../../../components/Avatar/Avatar"; -import "./ProfileTab.css"; +import styles from "./ProfileTab.module.css"; +import CustomTextField from "../../../../components/TextFieldComponents/CustomTextField/CustomTextField"; +import Button from "../../../../components/Button/Button"; const ProfileTab = () => { + const submitHandler = (e) => { + e.preventDefault(); + }; - const submitHandler = (e) => { - e.preventDefault() - } return ( -
-
-
-
-