From f152f490e30a0358eb05357dffa836dce488cafb Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Mon, 12 Aug 2024 12:27:51 -0400 Subject: [PATCH 01/15] Added fallback UI when there are no incidents recorded --- Client/src/Pages/Auth/Register/Register.jsx | 48 +++++------ Client/src/Pages/Auth/index.css | 3 + .../Pages/Incidents/IncidentTable/index.jsx | 84 +++++++++++-------- Client/src/Pages/Incidents/index.css | 6 ++ 4 files changed, 81 insertions(+), 60 deletions(-) diff --git a/Client/src/Pages/Auth/Register/Register.jsx b/Client/src/Pages/Auth/Register/Register.jsx index 77b3dd2fc..855cc3c54 100644 --- a/Client/src/Pages/Auth/Register/Register.jsx +++ b/Client/src/Pages/Auth/Register/Register.jsx @@ -107,18 +107,16 @@ const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => { />
- - - + @@ -267,21 +265,19 @@ const StepThree = ({ form, errors, onSubmit, onChange, onBack }) => { />
- - - + - + .MuiStack-root:nth-of-type(1) { height: var(--env-var-nav-bar-height); diff --git a/Client/src/Pages/Incidents/IncidentTable/index.jsx b/Client/src/Pages/Incidents/IncidentTable/index.jsx index 95230bb72..afc1d4ef6 100644 --- a/Client/src/Pages/Incidents/IncidentTable/index.jsx +++ b/Client/src/Pages/Incidents/IncidentTable/index.jsx @@ -9,6 +9,8 @@ import { Pagination, PaginationItem, Paper, + Typography, + Box, } from "@mui/material"; import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; @@ -105,41 +107,55 @@ const IncidentTable = ({ monitors, selectedMonitor, filter }) => { return ( <> - - - - - Monitor Name - Status - Date & Time - Message - - - - {checks.map((check) => { - const status = check.status === true ? "up" : "down"; - - return ( - - {monitors[check.monitorId]?.name} - - - - - {new Date(check.createdAt).toLocaleString()} - - {check.statusCode} + {checks?.length === 0 && selectedMonitor === "0" ? ( + + No incidents recorded yet. + + ) : checks?.length === 0 ? ( + + + The monitor you have selected, has no recorded incidents yet. + + + ) : ( + <> + +
+ + + Monitor Name + Status + Date & Time + Message - ); - })} - -
-
- {paginationComponent} + + + {checks.map((check) => { + const status = check.status === true ? "up" : "down"; + + return ( + + {monitors[check.monitorId]?.name} + + + + + {new Date(check.createdAt).toLocaleString()} + + {check.statusCode} + + ); + })} + + + + {paginationComponent} + + )} ); }; diff --git a/Client/src/Pages/Incidents/index.css b/Client/src/Pages/Incidents/index.css index 1f176d470..286552d22 100644 --- a/Client/src/Pages/Incidents/index.css +++ b/Client/src/Pages/Incidents/index.css @@ -17,6 +17,12 @@ .incidents .MuiPagination-root { background-color: var(--env-var-color-8); } +.incidents > .MuiBox-root { + background-color: var(--env-var-color-8); + border: solid 1px var(--env-var-color-6); + border-radius: var(--env-var-radius-1); + padding: 60px; +} /* remove later */ .incidents .MuiSelect-select { From 6cbca39e0fa4ad6ffc6b63a0d6c5a7bbf571a28b Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 12 Aug 2024 10:00:20 -0700 Subject: [PATCH 02/15] Refactored endpoint --- Server/controllers/authController.js | 47 +++++++-------------------- Server/db/mongo/modules/userModule.js | 7 ++-- 2 files changed, 15 insertions(+), 39 deletions(-) diff --git a/Server/controllers/authController.js b/Server/controllers/authController.js index 0f89e3371..d4a77fe4d 100644 --- a/Server/controllers/authController.js +++ b/Server/controllers/authController.js @@ -126,11 +126,12 @@ const loginController = async (req, res, next) => { return; } try { + const { email, password } = req.body; // Check if user exists - const user = await req.db.getUserByEmail(req, res); + const user = await req.db.getUserByEmail(email); // Compare password - const match = await user.comparePassword(req.body.password); + const match = await user.comparePassword(password); if (match !== true) { throw new Error(errorMessages.AUTH_INCORRECT_PASSWORD); } @@ -167,7 +168,7 @@ const logoutController = async (req, res, next) => { try { // Get user const { email } = req.body; - const userToLogout = await req.db.getUserByEmail({ body: { email } }, res); + const userToLogout = await req.db.getUserByEmail(email); userToLogout.authToken = null; await userToLogout.save(); @@ -216,7 +217,7 @@ const userEditController = async (req, res, next) => { // Add user email to body for DB operation req.body.email = email; // Get user - const user = await req.db.getUserByEmail(req, res); + const user = await req.db.getUserByEmail(email); // Compare passwords const match = await user.comparePassword(req.body.password); // If not a match, throw a 403 @@ -350,7 +351,8 @@ const recoveryRequestController = async (req, res, next) => { } try { - const user = await req.db.getUserByEmail(req, res); + const { email } = req.body; + const user = await req.db.getUserByEmail(email); if (user) { const recoveryToken = await req.db.requestRecoveryToken(req, res); const name = user.firstName; @@ -462,41 +464,16 @@ const deleteUserController = async (req, res, next) => { const decodedToken = jwt.decode(token); const { _id, email } = decodedToken; - // TODO fix this hack - const decodedTokenCastedAsRequest = { - query: {}, - params: { - userId: _id, - }, - body: { - email, - }, - }; - - // Validate user - try { - await deleteUserParamValidation.validateAsync( - decodedTokenCastedAsRequest.body - ); - } catch (error) { - error.status = 422; - error.service = SERVICE_NAME; - error.message = - error.details?.[0]?.message || error.message || "Validation Error"; - next(error); - return; - } - // Check if the user exists - const user = await req.db.getUserByEmail(decodedTokenCastedAsRequest); + const user = await req.db.getUserByEmail(email); if (!user) { throw new Error(errorMessages.DB_USER_NOT_FOUND); } // 1. Find all the monitors associated with the user id - const monitors = await req.db.getMonitorsByUserId( - decodedTokenCastedAsRequest - ); + const monitors = await req.db.getMonitorsByUserId({ + params: { userId: _id }, + }); if (monitors) { //2. Remove all jobs, delete checks and alerts @@ -514,7 +491,7 @@ const deleteUserController = async (req, res, next) => { await req.db.deleteMonitorsByUserId(user._id); // 4. Delete the user by id - await req.db.deleteUser(decodedTokenCastedAsRequest); + await req.db.deleteUser(user._id); return res.status(200).json({ success: true, diff --git a/Server/db/mongo/modules/userModule.js b/Server/db/mongo/modules/userModule.js index d626bcb9a..3dacfd943 100644 --- a/Server/db/mongo/modules/userModule.js +++ b/Server/db/mongo/modules/userModule.js @@ -51,11 +51,11 @@ const insertUser = async (req, res) => { * @returns {Promise} * @throws {Error} */ -const getUserByEmail = async (req, res) => { +const getUserByEmail = async (email) => { try { // Need the password to be able to compare, removed .select() // We can strip the hash before returing the user - const user = await UserModel.findOne({ email: req.body.email }).select( + const user = await UserModel.findOne({ email: email }).select( "-profileImage" ); if (user) { @@ -126,8 +126,7 @@ const updateUser = async (req, res) => { * @returns {Promise} * @throws {Error} */ -const deleteUser = async (req, res) => { - const userId = req.params.userId; +const deleteUser = async (userId) => { try { const deletedUser = await UserModel.findByIdAndDelete(userId); if (!deletedUser) { From 1d767454e219b9c22c70c844c88e76b89c882c9f Mon Sep 17 00:00:00 2001 From: Alexander Holliday Date: Mon, 12 Aug 2024 10:02:54 -0700 Subject: [PATCH 03/15] Removed comma --- Client/src/Pages/Incidents/IncidentTable/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Pages/Incidents/IncidentTable/index.jsx b/Client/src/Pages/Incidents/IncidentTable/index.jsx index afc1d4ef6..44a30decc 100644 --- a/Client/src/Pages/Incidents/IncidentTable/index.jsx +++ b/Client/src/Pages/Incidents/IncidentTable/index.jsx @@ -114,7 +114,7 @@ const IncidentTable = ({ monitors, selectedMonitor, filter }) => { ) : checks?.length === 0 ? ( - The monitor you have selected, has no recorded incidents yet. + The monitor you have selected has no recorded incidents yet. ) : ( From 938226015da36b586f83daf927f63e9742ee5276 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Mon, 12 Aug 2024 13:16:02 -0400 Subject: [PATCH 04/15] Added bluewave icon and initial design --- Client/src/Pages/Auth/ForgotPassword.jsx | 57 ++++++++++++++++++------ Client/src/Pages/Auth/index.css | 8 ---- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/Client/src/Pages/Auth/ForgotPassword.jsx b/Client/src/Pages/Auth/ForgotPassword.jsx index 86db72076..fa1f216ed 100644 --- a/Client/src/Pages/Auth/ForgotPassword.jsx +++ b/Client/src/Pages/Auth/ForgotPassword.jsx @@ -1,18 +1,19 @@ -import "./index.css"; -import background from "../../assets/Images/background_pattern_decorative.png"; -import Logomark from "../../assets/icons/key.svg?react"; -import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; +import { Stack, Typography } from "@mui/material"; +import { useTheme } from "@emotion/react"; +import { createToast } from "../../Utils/toastUtils"; +import { useDispatch, useSelector } from "react-redux"; +import { forgotPassword } from "../../Features/Auth/authSlice"; import { useState } from "react"; import { credentials } from "../../Validation/validation"; import { useNavigate } from "react-router-dom"; import Field from "../../Components/Inputs/Field"; -import { createToast } from "../../Utils/toastUtils"; -import { useDispatch, useSelector } from "react-redux"; -import { forgotPassword } from "../../Features/Auth/authSlice"; import ButtonSpinner from "../../Components/ButtonSpinner"; -import { Stack, Typography } from "@mui/material"; -import { useTheme } from "@emotion/react"; import Button from "../../Components/Button"; +import Logo from "../../assets/icons/bwu-icon.svg?react"; +import Key from "../../assets/icons/key.svg?react"; +import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; +import background from "../../assets/Images/background_pattern_decorative.png"; +import "./index.css"; const ForgotPassword = () => { const navigate = useNavigate(); @@ -92,13 +93,43 @@ const ForgotPassword = () => { }; return ( -
+ background pattern -
+ + + BlueWave Uptime + + .MuiStack-root": { + border: 1, + borderRadius: theme.shape.borderRadius, + borderColor: theme.palette.otherColors.graishWhite, + backgroundColor: theme.palette.otherColors.white, + padding: { + xs: theme.gap.large, + sm: theme.gap.xl, + }, + }, + }} + > + {/* @@ -135,8 +166,8 @@ const ForgotPassword = () => { onClick={() => navigate("/login")} /> -
-
+ */} +
); }; diff --git a/Client/src/Pages/Auth/index.css b/Client/src/Pages/Auth/index.css index 577f27799..45efc6ce3 100644 --- a/Client/src/Pages/Auth/index.css +++ b/Client/src/Pages/Auth/index.css @@ -3,7 +3,6 @@ /* ////// */ .set-new-password-page, .password-confirmed-page, -.forgot-password-page, .check-email-page { display: flex; justify-content: center; @@ -11,7 +10,6 @@ } .set-new-password-page h1.MuiTypography-root, .password-confirmed-page h1.MuiTypography-root, -.forgot-password-page h1.MuiTypography-root, .check-email-page h1.MuiTypography-root { font-size: var(--env-var-font-size-large); color: var(--env-var-color-1); @@ -21,8 +19,6 @@ .set-new-password-page button, .password-confirmed-page p.MuiTypography-root, .password-confirmed-page button, -.forgot-password-page p.MuiTypography-root, -.forgot-password-page button, .check-email-page p.MuiTypography-root, .check-email-page button, .check-email-page span.MuiTypography-root { @@ -30,7 +26,6 @@ } .set-new-password-page button:not(.MuiIconButton-root), .password-confirmed-page button:not(.MuiIconButton-root), -.forgot-password-page button:not(.MuiIconButton-root), .check-email-page button:not(.MuiIconButton-root) { height: 34px; border-radius: var(--env-var-radius-2); @@ -39,21 +34,18 @@ .set-new-password-form, .password-confirmed-form, -.forgot-password-form, .check-email-form { margin-top: 65px; width: var(--env-var-width-2); } .set-new-password-page p.MuiTypography-root, .password-confirmed-page p.MuiTypography-root, -.forgot-password-page p.MuiTypography-root, .check-email-page p.MuiTypography-root { color: var(--env-var-color-2); } .set-new-password-page button:not(.MuiIconButton-root) svg, .password-confirmed-page button:not(.MuiIconButton-root) svg, -.forgot-password-page button svg, .check-email-page button svg { margin-right: 5px; } From 12992c8ae168e28985b2c31c83fef89e21cf9aa0 Mon Sep 17 00:00:00 2001 From: Daniel Cojocea Date: Mon, 12 Aug 2024 13:58:18 -0400 Subject: [PATCH 05/15] Final auth design --- Client/src/Pages/Auth/ForgotPassword.jsx | 117 +++++++++++------------ Client/src/Pages/Auth/index.css | 4 + 2 files changed, 60 insertions(+), 61 deletions(-) diff --git a/Client/src/Pages/Auth/ForgotPassword.jsx b/Client/src/Pages/Auth/ForgotPassword.jsx index fa1f216ed..ab8728f8c 100644 --- a/Client/src/Pages/Auth/ForgotPassword.jsx +++ b/Client/src/Pages/Auth/ForgotPassword.jsx @@ -1,4 +1,4 @@ -import { Stack, Typography } from "@mui/material"; +import { Box, Stack, Typography } from "@mui/material"; import { useTheme } from "@emotion/react"; import { createToast } from "../../Utils/toastUtils"; import { useDispatch, useSelector } from "react-redux"; @@ -8,10 +8,8 @@ import { credentials } from "../../Validation/validation"; import { useNavigate } from "react-router-dom"; import Field from "../../Components/Inputs/Field"; import ButtonSpinner from "../../Components/ButtonSpinner"; -import Button from "../../Components/Button"; import Logo from "../../assets/icons/bwu-icon.svg?react"; import Key from "../../assets/icons/key.svg?react"; -import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; import background from "../../assets/Images/background_pattern_decorative.png"; import "./index.css"; @@ -26,10 +24,6 @@ const ForgotPassword = () => { email: "", }); - const idMap = { - "forgot-password-email-input": "email", - }; - const handleSubmit = async (event) => { event.preventDefault(); @@ -41,11 +35,9 @@ const ForgotPassword = () => { error.details && error.details.length > 0 ? error.details[0].message : "Error validating data."; - setErrors(err); + setErrors({ email: err }); createToast({ - variant: "info", body: err, - hasIcon: false, }); } else { const action = await dispatch(forgotPassword(form)); @@ -72,24 +64,16 @@ const ForgotPassword = () => { }; const handleChange = (event) => { - const { value, id } = event.target; - const name = idMap[id]; - setForm((prev) => ({ - ...prev, - [name]: value, - })); + const { value } = event.target; + setForm({ email: value }); const { error } = credentials.validate( - { [name]: value }, + { email: value }, { abortEarly: false } ); - setErrors((prev) => { - const prevErrors = { ...prev }; - if (error) prevErrors[name] = error.details[0].message; - else delete prevErrors[name]; - return prevErrors; - }); + if (error) setErrors({ email: error.details[0].message }); + else delete errors.email; }; return ( @@ -128,45 +112,56 @@ const ForgotPassword = () => { }, }, }} - >
- {/*
- - - - Forgot password? - - - No worries, we'll send you reset instructions. - + > + + + + Forgot password? + + No worries, we'll send you reset instructions. + + + + + + + + - - - -