From 55225ad2212df49e25f8cb7fb83d83b318386fcf Mon Sep 17 00:00:00 2001 From: Peter Carl Pardo Date: Sun, 15 Dec 2024 23:11:50 +0800 Subject: [PATCH 01/64] feat: initial dark theme switch component --- .../Components/ThemeSwitch/SunAndMoonIcon.jsx | 95 +++++++++++++++++++ Client/src/Components/ThemeSwitch/index.css | 77 +++++++++++++++ Client/src/Components/ThemeSwitch/index.jsx | 49 ++++++++++ Client/src/index.css | 1 + 4 files changed, 222 insertions(+) create mode 100644 Client/src/Components/ThemeSwitch/SunAndMoonIcon.jsx create mode 100644 Client/src/Components/ThemeSwitch/index.css create mode 100644 Client/src/Components/ThemeSwitch/index.jsx diff --git a/Client/src/Components/ThemeSwitch/SunAndMoonIcon.jsx b/Client/src/Components/ThemeSwitch/SunAndMoonIcon.jsx new file mode 100644 index 000000000..91d54df22 --- /dev/null +++ b/Client/src/Components/ThemeSwitch/SunAndMoonIcon.jsx @@ -0,0 +1,95 @@ +import "./index.css"; + +const SunAndMoonIcon = () => { + return ( + + ); +}; + +export default SunAndMoonIcon; diff --git a/Client/src/Components/ThemeSwitch/index.css b/Client/src/Components/ThemeSwitch/index.css new file mode 100644 index 000000000..23a76bc2c --- /dev/null +++ b/Client/src/Components/ThemeSwitch/index.css @@ -0,0 +1,77 @@ +.sun-and-moon > :is(.moon, .sun, .sun-beams) { + transform-origin: center; +} + +.sun-and-moon > :is(.moon, .sun) { + fill: var(--icon-fill); +} + +.theme-toggle:is(:hover, :focus-visible) > .sun-and-moon > :is(.moon, .sun) { + fill: var(--icon-fill-hover); +} + +.sun-and-moon > .sun-beams { + stroke: var(--icon-fill); + stroke-width: 2px; +} + +.theme-toggle:is(:hover, :focus-visible) .sun-and-moon > .sun-beams { + stroke: var(--icon-fill-hover); +} + +[data-theme="dark"] .sun-and-moon > .sun { + transform: scale(1.75); +} + +[data-theme="dark"] .sun-and-moon > .sun-beams { + opacity: 0; +} + +[data-theme="dark"] .sun-and-moon > .moon > circle { + transform: translateX(-7px); +} + +@supports (cx: 1) { + [data-theme="dark"] .sun-and-moon > .moon > circle { + cx: 17; + transform: translateX(0); + } +} + +@media (prefers-reduced-motion: no-preference) { + .sun-and-moon > .sun { + transition: transform 0.5s var(--ease-elastic-3); + } + + .sun-and-moon > .sun-beams { + transition: + transform 0.5s var(--ease-elastic-4), + opacity 0.5s var(--ease-3); + } + + .sun-and-moon .moon > circle { + transition: transform 0.25s var(--ease-out-5); + } + + @supports (cx: 1) { + .sun-and-moon .moon > circle { + transition: cx 0.25s var(--ease-out-5); + } + } + + [data-theme="dark"] .sun-and-moon > .sun { + transition-timing-function: var(--ease-3); + transition-duration: 0.25s; + transform: scale(1.75); + } + + [data-theme="dark"] .sun-and-moon > .sun-beams { + transition-duration: 0.15s; + transform: rotateZ(-25deg); + } + + [data-theme="dark"] .sun-and-moon > .moon > circle { + transition-duration: 0.5s; + transition-delay: 0.25s; + } +} diff --git a/Client/src/Components/ThemeSwitch/index.jsx b/Client/src/Components/ThemeSwitch/index.jsx new file mode 100644 index 000000000..b25b72218 --- /dev/null +++ b/Client/src/Components/ThemeSwitch/index.jsx @@ -0,0 +1,49 @@ +import React, { useEffect, useState } from "react"; +// import "./index.css"; +import { IconButton } from "@mui/material"; +import SunAndMoonIcon from "./SunAndMoonIcon"; +// import SunAndMoonIcon from "./SunAndMoonIcon"; + +const ThemeSwitch = () => { + const [currentTheme, setCurrentTheme] = useState("light"); + const toggleTheme = () => + setCurrentTheme((prevState) => (prevState === "light" ? "dark" : "light")); + + useEffect(() => { + document.body.setAttribute("data-theme", currentTheme); + console.log(currentTheme); + }, [currentTheme]); + + return ( + circle": { + // transform: currentTheme === "dark" ? "translateX(-7px)" : "none", + // transition: "transform 0.25s ease", + // }, + }} + > + + + ); +}; + +export default ThemeSwitch; diff --git a/Client/src/index.css b/Client/src/index.css index 173551ba6..f821df6ee 100644 --- a/Client/src/index.css +++ b/Client/src/index.css @@ -1,4 +1,5 @@ @import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap"); +@import "https://unpkg.com/open-props/easings.min.css"; * { box-sizing: border-box; From 6d6a13a833be75c11557be54f7c0fd55709c331f Mon Sep 17 00:00:00 2001 From: Peter Carl Pardo Date: Sun, 15 Dec 2024 23:46:16 +0800 Subject: [PATCH 02/64] feat: fix sun beams icon bug --- Client/src/Components/ThemeSwitch/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Components/ThemeSwitch/index.css b/Client/src/Components/ThemeSwitch/index.css index 23a76bc2c..2f3814702 100644 --- a/Client/src/Components/ThemeSwitch/index.css +++ b/Client/src/Components/ThemeSwitch/index.css @@ -10,7 +10,7 @@ fill: var(--icon-fill-hover); } -.sun-and-moon > .sun-beams { +.theme-toggle .sun-and-moon > .sun-beams { stroke: var(--icon-fill); stroke-width: 2px; } From dd488fecb42c35e1153e552db1fc2c724856f298 Mon Sep 17 00:00:00 2001 From: Peter Carl Pardo Date: Sun, 15 Dec 2024 23:50:48 +0800 Subject: [PATCH 03/64] feat: cleanup --- Client/src/Components/ThemeSwitch/index.jsx | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/Client/src/Components/ThemeSwitch/index.jsx b/Client/src/Components/ThemeSwitch/index.jsx index b25b72218..533b026b2 100644 --- a/Client/src/Components/ThemeSwitch/index.jsx +++ b/Client/src/Components/ThemeSwitch/index.jsx @@ -1,8 +1,7 @@ import React, { useEffect, useState } from "react"; -// import "./index.css"; +import "./index.css"; import { IconButton } from "@mui/material"; import SunAndMoonIcon from "./SunAndMoonIcon"; -// import SunAndMoonIcon from "./SunAndMoonIcon"; const ThemeSwitch = () => { const [currentTheme, setCurrentTheme] = useState("light"); @@ -11,7 +10,6 @@ const ThemeSwitch = () => { useEffect(() => { document.body.setAttribute("data-theme", currentTheme); - console.log(currentTheme); }, [currentTheme]); return ( @@ -27,18 +25,6 @@ const ThemeSwitch = () => { display: "flex", alignItems: "center", justifyContent: "center", - // "& .sun-and-moon": { - // transformOrigin: "center", - // }, - // "& .sun": { - // fill: "var(--icon-fill)", - // transition: "transform 0.5s ease", - // ...(currentTheme === "dark" && { transform: "scale(1.75)" }), - // }, - // "& .moon > circle": { - // transform: currentTheme === "dark" ? "translateX(-7px)" : "none", - // transition: "transform 0.25s ease", - // }, }} > From efa106f732878917d54dae7ea2620154ffdeb321 Mon Sep 17 00:00:00 2001 From: Peter Carl Pardo Date: Sun, 15 Dec 2024 23:51:53 +0800 Subject: [PATCH 04/64] feat: add comment for temporary theme logic --- Client/src/Components/ThemeSwitch/index.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/Client/src/Components/ThemeSwitch/index.jsx b/Client/src/Components/ThemeSwitch/index.jsx index 533b026b2..e5758eab1 100644 --- a/Client/src/Components/ThemeSwitch/index.jsx +++ b/Client/src/Components/ThemeSwitch/index.jsx @@ -4,6 +4,7 @@ import { IconButton } from "@mui/material"; import SunAndMoonIcon from "./SunAndMoonIcon"; const ThemeSwitch = () => { + // TODO: change to use the MUI theme const [currentTheme, setCurrentTheme] = useState("light"); const toggleTheme = () => setCurrentTheme((prevState) => (prevState === "light" ? "dark" : "light")); From a97b2f0887d0c44cda362f149c401a1826f6bced Mon Sep 17 00:00:00 2001 From: Peter Carl Pardo Date: Sun, 15 Dec 2024 23:52:07 +0800 Subject: [PATCH 05/64] feat: cleanup --- Client/src/Components/ThemeSwitch/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Components/ThemeSwitch/index.jsx b/Client/src/Components/ThemeSwitch/index.jsx index e5758eab1..df3c813ab 100644 --- a/Client/src/Components/ThemeSwitch/index.jsx +++ b/Client/src/Components/ThemeSwitch/index.jsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react"; -import "./index.css"; import { IconButton } from "@mui/material"; import SunAndMoonIcon from "./SunAndMoonIcon"; +import "./index.css"; const ThemeSwitch = () => { // TODO: change to use the MUI theme From 3ab8b1241e950599571c7abb5250f8c1e5d72652 Mon Sep 17 00:00:00 2001 From: Peter Carl Pardo Date: Mon, 16 Dec 2024 14:05:56 +0800 Subject: [PATCH 06/64] feat: Add theme switch in login page --- Client/src/Pages/Auth/Login.jsx | 49 ++++++++++++++++----------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/Client/src/Pages/Auth/Login.jsx b/Client/src/Pages/Auth/Login.jsx index a7554a7c1..b07f7aa84 100644 --- a/Client/src/Pages/Auth/Login.jsx +++ b/Client/src/Pages/Auth/Login.jsx @@ -17,6 +17,7 @@ import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; import PropTypes from "prop-types"; import { logger } from "../../Utils/Logger"; import "./index.css"; +import ThemeSwitch from "../../Components/ThemeSwitch"; const DEMO = import.meta.env.VITE_APP_DEMO; /** @@ -327,33 +328,25 @@ const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => { - - - Forgot password? - - - Reset password - - + + + Forgot password? + + + Reset password + + ); }; @@ -520,6 +513,7 @@ const Login = () => { px={{ xs: theme.spacing(12), lg: theme.spacing(20) }} pb={theme.spacing(20)} mx="auto" + gap={theme.spacing(8)} sx={{ "& > .MuiStack-root": { border: 1, @@ -554,6 +548,9 @@ const Login = () => { /> ) )} + + + ); From cdcefb1106744323cec9c00c1c946f17d8165235 Mon Sep 17 00:00:00 2001 From: Peter Carl Pardo Date: Mon, 16 Dec 2024 14:16:58 +0800 Subject: [PATCH 07/64] feat: add theme switch in sidebar --- Client/src/Components/Sidebar/index.jsx | 48 ++++++++++++++----------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/Client/src/Components/Sidebar/index.jsx b/Client/src/Components/Sidebar/index.jsx index 95abe1d20..feed25f24 100644 --- a/Client/src/Components/Sidebar/index.jsx +++ b/Client/src/Components/Sidebar/index.jsx @@ -21,6 +21,7 @@ import { useDispatch, useSelector } from "react-redux"; import { clearAuthState } from "../../Features/Auth/authSlice"; import { toggleSidebar } from "../../Features/UI/uiSlice"; import { clearUptimeMonitorState } from "../../Features/UptimeMonitors/uptimeMonitorsSlice"; +import ThemeSwitch from "../ThemeSwitch"; import Avatar from "../Avatar"; import LockSvg from "../../assets/icons/lock.svg?react"; import UserSvg from "../../assets/icons/user.svg?react"; @@ -551,28 +552,35 @@ function Sidebar() { {authState.user?.role} - - openPopup(event, "logout")} + + - - - + openPopup(event, "logout")} + > + + + + )} Date: Mon, 16 Dec 2024 14:28:58 +0800 Subject: [PATCH 08/64] cleanup --- Client/src/Pages/Auth/Login.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Pages/Auth/Login.jsx b/Client/src/Pages/Auth/Login.jsx index b07f7aa84..f007600f7 100644 --- a/Client/src/Pages/Auth/Login.jsx +++ b/Client/src/Pages/Auth/Login.jsx @@ -548,7 +548,7 @@ const Login = () => { /> ) )} - + From 663f2334d1c703bb67bbf3c2fb2a9d995e859304 Mon Sep 17 00:00:00 2001 From: Peter Carl Pardo Date: Tue, 17 Dec 2024 01:24:15 +0800 Subject: [PATCH 09/64] feat: added dark mode functionality --- .../Components/ThemeSwitch/SunAndMoonIcon.jsx | 11 +++++++---- Client/src/Components/ThemeSwitch/index.css | 13 ------------- Client/src/Components/ThemeSwitch/index.jsx | 16 ++++++++++------ 3 files changed, 17 insertions(+), 23 deletions(-) diff --git a/Client/src/Components/ThemeSwitch/SunAndMoonIcon.jsx b/Client/src/Components/ThemeSwitch/SunAndMoonIcon.jsx index 91d54df22..820daeb3f 100644 --- a/Client/src/Components/ThemeSwitch/SunAndMoonIcon.jsx +++ b/Client/src/Components/ThemeSwitch/SunAndMoonIcon.jsx @@ -1,6 +1,9 @@ +import { useTheme } from "@mui/material"; import "./index.css"; const SunAndMoonIcon = () => { + const theme = useTheme(); + return ( { y="0" width="100%" height="100%" - fill="white" + fill="#fff" /> { cx="12" cy="12" r="6" - fill="currentColor" + fill={theme.palette.text.secondary} mask="url(#moon-mask)" /> :is(.moon, .sun) { - fill: var(--icon-fill); -} - -.theme-toggle:is(:hover, :focus-visible) > .sun-and-moon > :is(.moon, .sun) { - fill: var(--icon-fill-hover); -} - .theme-toggle .sun-and-moon > .sun-beams { - stroke: var(--icon-fill); stroke-width: 2px; } -.theme-toggle:is(:hover, :focus-visible) .sun-and-moon > .sun-beams { - stroke: var(--icon-fill-hover); -} - [data-theme="dark"] .sun-and-moon > .sun { transform: scale(1.75); } diff --git a/Client/src/Components/ThemeSwitch/index.jsx b/Client/src/Components/ThemeSwitch/index.jsx index df3c813ab..1e98dfe27 100644 --- a/Client/src/Components/ThemeSwitch/index.jsx +++ b/Client/src/Components/ThemeSwitch/index.jsx @@ -2,16 +2,20 @@ import React, { useEffect, useState } from "react"; import { IconButton } from "@mui/material"; import SunAndMoonIcon from "./SunAndMoonIcon"; import "./index.css"; +import { useDispatch, useSelector } from "react-redux"; +import { setMode } from "../../Features/UI/uiSlice"; const ThemeSwitch = () => { - // TODO: change to use the MUI theme - const [currentTheme, setCurrentTheme] = useState("light"); - const toggleTheme = () => - setCurrentTheme((prevState) => (prevState === "light" ? "dark" : "light")); + const mode = useSelector((state) => state.ui.mode); + const dispatch = useDispatch(); + + const toggleTheme = () => { + dispatch(setMode(mode === "light" ? "dark" : "light")); + }; useEffect(() => { - document.body.setAttribute("data-theme", currentTheme); - }, [currentTheme]); + document.body.setAttribute("data-theme", mode); + }, [mode]); return ( Date: Mon, 16 Dec 2024 18:59:29 +0000 Subject: [PATCH 10/64] modified radio button visibility --- Client/src/Components/Inputs/Radio/index.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Client/src/Components/Inputs/Radio/index.jsx b/Client/src/Components/Inputs/Radio/index.jsx index 7a700e2b7..6291485f0 100644 --- a/Client/src/Components/Inputs/Radio/index.jsx +++ b/Client/src/Components/Inputs/Radio/index.jsx @@ -42,6 +42,9 @@ const Radio = (props) => { width: 16, height: 16, boxShadow: `inset 0 0 0 1px ${theme.palette.secondary.main}`, + "&:not(.Mui-checked)": { + boxShadow: `inset 0 0 0 1px ${theme.palette.text.primary}70`, // Use theme text color for the outline + }, mt: theme.spacing(0.5), }} /> From acefedd6e76dd04a66e38ef6555874b8cb1d62f9 Mon Sep 17 00:00:00 2001 From: Peter Carl Pardo Date: Tue, 17 Dec 2024 23:57:12 +0800 Subject: [PATCH 11/64] feat: add attribution for theme switch --- Client/src/Components/ThemeSwitch/index.jsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Client/src/Components/ThemeSwitch/index.jsx b/Client/src/Components/ThemeSwitch/index.jsx index 1e98dfe27..4cb6c3a14 100644 --- a/Client/src/Components/ThemeSwitch/index.jsx +++ b/Client/src/Components/ThemeSwitch/index.jsx @@ -1,4 +1,15 @@ -import React, { useEffect, useState } from "react"; +/** + * ThemeSwitch Component + * Dark and Light Theme Switch + * Original Code: https://web.dev/patterns/theming/theme-switch + * License: Apache License 2.0 + * Copyright © Google LLC + * + * This code has been adapted for use in this project. + * Apache License: https://www.apache.org/licenses/LICENSE-2.0 + */ + +import React, { useEffect } from "react"; import { IconButton } from "@mui/material"; import SunAndMoonIcon from "./SunAndMoonIcon"; import "./index.css"; From a507e1282e833c480a2b15ebbe0f70d949b1a279 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 13:10:28 -0800 Subject: [PATCH 12/64] Fix links in login page --- Client/src/Pages/Auth/Login/Login.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Client/src/Pages/Auth/Login/Login.jsx b/Client/src/Pages/Auth/Login/Login.jsx index 1b3a420ea..c1687a0ec 100644 --- a/Client/src/Pages/Auth/Login/Login.jsx +++ b/Client/src/Pages/Auth/Login/Login.jsx @@ -11,8 +11,8 @@ import Background from "../../../assets/Images/background-grid.svg?react"; import Logo from "../../../assets/icons/bwu-icon.svg?react"; import { logger } from "../../../Utils/Logger"; import "../index.css"; -import EmailStep from "./Components/EmailStep"; -import PasswordStep from "./Components/PasswordStep"; +import EmailStep from "./Components/EmailStep"; +import PasswordStep from "./Components/PasswordStep"; const DEMO = import.meta.env.VITE_APP_DEMO; @@ -42,7 +42,7 @@ const Login = () => { useEffect(() => { if (authToken) { - navigate("/monitors"); + navigate("/uptime"); return; } networkService @@ -108,7 +108,7 @@ const Login = () => { } else { const action = await dispatch(login(form)); if (action.payload.success) { - navigate("/monitors"); + navigate("/uptime"); createToast({ body: "Welcome back! You're successfully logged in.", }); From 1f823fc672cadc2d8cac5b05981204b29477670f Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 13:10:40 -0800 Subject: [PATCH 13/64] remove old login page --- Client/src/Pages/Auth/Login.jsx | 562 -------------------------------- 1 file changed, 562 deletions(-) delete mode 100644 Client/src/Pages/Auth/Login.jsx diff --git a/Client/src/Pages/Auth/Login.jsx b/Client/src/Pages/Auth/Login.jsx deleted file mode 100644 index a7554a7c1..000000000 --- a/Client/src/Pages/Auth/Login.jsx +++ /dev/null @@ -1,562 +0,0 @@ -import { useState, useEffect, useRef } from "react"; -import { useNavigate } from "react-router-dom"; -import { Box, Button, Stack, Typography } from "@mui/material"; -import { useTheme } from "@emotion/react"; -import { credentials } from "../../Validation/validation"; -import { login } from "../../Features/Auth/authSlice"; -import LoadingButton from "@mui/lab/LoadingButton"; -import { useDispatch, useSelector } from "react-redux"; -import { createToast } from "../../Utils/toastUtils"; -import { networkService } from "../../main"; -import TextInput from "../../Components/Inputs/TextInput"; -import { PasswordEndAdornment } from "../../Components/Inputs/TextInput/Adornments"; -import Background from "../../assets/Images/background-grid.svg?react"; -import Logo from "../../assets/icons/bwu-icon.svg?react"; -import Mail from "../../assets/icons/mail.svg?react"; -import ArrowBackRoundedIcon from "@mui/icons-material/ArrowBackRounded"; -import PropTypes from "prop-types"; -import { logger } from "../../Utils/Logger"; -import "./index.css"; -const DEMO = import.meta.env.VITE_APP_DEMO; - -/** - * Displays the initial landing page. - * - * @param {Object} props - * @param {Function} props.onContinue - Callback function to handle "Continue with Email" button click. - * @returns {JSX.Element} - */ -const LandingPage = ({ onContinue }) => { - const theme = useTheme(); - - return ( - <> - - - Log In - We are pleased to see you again! - - - - - - - By continuing, you agree to our{" "} - { - window.open( - "https://bluewavelabs.ca/terms-of-service-open-source", - "_blank", - "noreferrer" - ); - }} - sx={{ - "&:hover": { - color: theme.palette.text.tertiary, - }, - }} - > - Terms of Service - {" "} - and{" "} - { - window.open( - "https://bluewavelabs.ca/privacy-policy-open-source", - "_blank", - "noreferrer" - ); - }} - sx={{ - "&:hover": { - color: theme.palette.text.tertiary, - }, - }} - > - Privacy Policy. - - - - - - ); -}; - -LandingPage.propTypes = { - onContinue: PropTypes.func.isRequired, -}; - -/** - * Renders the first step of the login process. - * - * @param {Object} props - * @param {Object} props.form - Form state object. - * @param {Object} props.errors - Object containing form validation errors. - * @param {Function} props.onSubmit - Callback function to handle form submission. - * @param {Function} props.onChange - Callback function to handle form input changes. - * @param {Function} props.onBack - Callback function to handle "Back" button click. - * @returns {JSX.Element} - */ -const StepOne = ({ form, errors, onSubmit, onChange, onBack }) => { - const theme = useTheme(); - const inputRef = useRef(null); - - useEffect(() => { - if (inputRef.current) { - inputRef.current.focus(); - } - }, []); - - return ( - <> - - - Log In - Enter your email address - - - (e.target.value = e.target.value.toLowerCase())} - onChange={onChange} - error={errors.email ? true : false} - helperText={errors.email} - ref={inputRef} - /> - - - - - - - - ); -}; - -StepOne.propTypes = { - form: PropTypes.object.isRequired, - errors: PropTypes.object.isRequired, - onSubmit: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - onBack: PropTypes.func.isRequired, -}; - -/** - * Renders the second step of the login process, including a password input field. - * - * @param {Object} props - * @param {Object} props.form - Form state object. - * @param {Object} props.errors - Object containing form validation errors. - * @param {Function} props.onSubmit - Callback function to handle form submission. - * @param {Function} props.onChange - Callback function to handle form input changes. - * @param {Function} props.onBack - Callback function to handle "Back" button click. - * @returns {JSX.Element} - */ -const StepTwo = ({ form, errors, onSubmit, onChange, onBack }) => { - const theme = useTheme(); - const navigate = useNavigate(); - const inputRef = useRef(null); - const authState = useSelector((state) => state.auth); - - useEffect(() => { - if (inputRef.current) { - inputRef.current.focus(); - } - }, []); - - const handleNavigate = () => { - if (form.email !== "" && !errors.email) { - sessionStorage.setItem("email", form.email); - } - navigate("/forgot-password"); - }; - - return ( - <> - - - Log In - Enter your password - - - } - /> - - - - Continue - - - - - - Forgot password? - - - Reset password - - - - - ); -}; - -StepTwo.propTypes = { - form: PropTypes.object.isRequired, - errors: PropTypes.object.isRequired, - onSubmit: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - onBack: PropTypes.func.isRequired, -}; - -const Login = () => { - const dispatch = useDispatch(); - const navigate = useNavigate(); - const theme = useTheme(); - - const authState = useSelector((state) => state.auth); - const { authToken } = authState; - - const idMap = { - "login-email-input": "email", - "login-password-input": "password", - }; - - const [form, setForm] = useState({ - email: DEMO !== undefined ? "uptimedemo@demo.com" : "", - password: DEMO !== undefined ? "Demouser1!" : "", - }); - const [errors, setErrors] = useState({}); - const [step, setStep] = useState(0); - - useEffect(() => { - if (authToken) { - navigate("/uptime"); - return; - } - networkService - .doesSuperAdminExist() - .then((response) => { - if (response.data.data === false) { - navigate("/register"); - } - }) - .catch((error) => { - logger.error(error); - }); - }, [authToken, navigate]); - - const handleChange = (event) => { - const { value, id } = event.target; - const name = idMap[id]; - setForm((prev) => ({ - ...prev, - [name]: value, - })); - - const { error } = credentials.validate({ [name]: value }, { abortEarly: false }); - - setErrors((prev) => { - const prevErrors = { ...prev }; - if (error) prevErrors[name] = error.details[0].message; - else delete prevErrors[name]; - return prevErrors; - }); - }; - - const handleSubmit = async (event) => { - event.preventDefault(); - - if (step === 1) { - const { error } = credentials.validate( - { email: form.email }, - { abortEarly: false } - ); - if (error) { - setErrors((prev) => ({ ...prev, email: error.details[0].message })); - createToast({ body: error.details[0].message }); - } else { - setStep(2); - } - } else if (step === 2) { - const { error } = credentials.validate(form, { abortEarly: false }); - - if (error) { - // validation errors - const newErrors = {}; - error.details.forEach((err) => { - newErrors[err.path[0]] = err.message; - }); - setErrors(newErrors); - createToast({ - body: - error.details && error.details.length > 0 - ? error.details[0].message - : "Error validating data.", - }); - } else { - const action = await dispatch(login(form)); - if (action.payload.success) { - navigate("/uptime"); - createToast({ - body: "Welcome back! You're successfully logged in.", - }); - } else { - if (action.payload) { - if (action.payload.msg === "Incorrect password") - setErrors({ - password: "The password you provided does not match our records", - }); - // dispatch errors - createToast({ - body: action.payload.msg, - }); - } else { - // unknown errors - createToast({ - body: "Unknown error.", - }); - } - } - } - } - }; - - return ( - - - - - - - BlueWave Uptime - - .MuiStack-root": { - border: 1, - borderRadius: theme.spacing(5), - borderColor: theme.palette.border.light, - backgroundColor: theme.palette.background.main, - padding: { - xs: theme.spacing(12), - sm: theme.spacing(20), - }, - }, - }} - > - {step === 0 ? ( - setStep(1)} /> - ) : step === 1 ? ( - setStep(0)} - /> - ) : ( - step === 2 && ( - setStep(1)} - /> - ) - )} - - - ); -}; - -export default Login; From f631fb16ac44416e41466af3005663e93b7ffc44 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 13:39:55 -0800 Subject: [PATCH 14/64] fix login import --- Client/src/Routes/index.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Routes/index.jsx b/Client/src/Routes/index.jsx index 5fc764b6a..784b44609 100644 --- a/Client/src/Routes/index.jsx +++ b/Client/src/Routes/index.jsx @@ -3,7 +3,7 @@ import HomeLayout from "../Components/Layouts/HomeLayout"; import { Infrastructure } from "../Pages/Infrastructure"; import InfrastructureDetails from "../Pages/Infrastructure/Details"; import NotFound from "../Pages/NotFound"; -import Login from "../Pages/Auth/Login"; +import Login from "../Pages/Auth/Login/Login"; import Register from "../Pages/Auth/Register/Register"; import Account from "../Pages/Account"; import Monitors from "../Pages/Uptime/Home"; From 1e6b3394832ef04b1fd904a22a1217c364bf527e Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 13:50:55 -0800 Subject: [PATCH 15/64] Add empty message to BasicTable component --- Client/src/Components/BasicTable/index.jsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Client/src/Components/BasicTable/index.jsx b/Client/src/Components/BasicTable/index.jsx index e519a079f..9f9a5b9da 100644 --- a/Client/src/Components/BasicTable/index.jsx +++ b/Client/src/Components/BasicTable/index.jsx @@ -115,7 +115,7 @@ TablePaginationActions.propTypes = { * @param {boolean} [props.paginated=false] - Flag to enable pagination. * @param {boolean} [props.reversed=false] - Flag to enable reverse order. * @param {number} props.rowsPerPage- Number of rows per page (table). - * + * @param {string} props.emptyMessage - Message to display when there is no data. * @example * const data = { * cols: [ @@ -149,7 +149,7 @@ TablePaginationActions.propTypes = { * */ -const BasicTable = ({ data, paginated, reversed, table }) => { +const BasicTable = ({ data, paginated, reversed, table, emptyMessage = "No data" }) => { const DEFAULT_ROWS_PER_PAGE = 5; const theme = useTheme(); const dispatch = useDispatch(); @@ -228,6 +228,16 @@ const BasicTable = ({ data, paginated, reversed, table }) => { ); })} + {displayData.length === 0 && ( + + + {emptyMessage} + + + )} @@ -317,6 +327,7 @@ BasicTable.propTypes = { reversed: PropTypes.bool, rowPerPage: PropTypes.number, table: PropTypes.string, + emptyMessage: PropTypes.string, }; export default BasicTable; From f880c2623c24d2ed9ece9370cfd31eb382d9d1c5 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 17 Dec 2024 13:51:03 -0800 Subject: [PATCH 16/64] Supply empty message to basic table --- .../TabPanels/Account/TeamPanel.jsx | 84 ++----------------- 1 file changed, 5 insertions(+), 79 deletions(-) diff --git a/Client/src/Components/TabPanels/Account/TeamPanel.jsx b/Client/src/Components/TabPanels/Account/TeamPanel.jsx index 209dbeaed..bbc6c4305 100644 --- a/Client/src/Components/TabPanels/Account/TeamPanel.jsx +++ b/Client/src/Components/TabPanels/Account/TeamPanel.jsx @@ -64,7 +64,7 @@ const TeamPanel = () => { }; fetchTeam(); - }, [user]); + }, [authToken]); useEffect(() => { let team = members; @@ -81,8 +81,6 @@ const TeamPanel = () => { { id: 1, name: "NAME" }, { id: 2, name: "EMAIL" }, { id: 3, name: "ROLE" }, - // FEATURE STILL TO BE IMPLEMENTED - // { id: 4, name: "ACTION" }, ], rows: team?.map((member, idx) => { const roles = member.role.map((role) => roleMap[role]).join(","); @@ -104,45 +102,19 @@ const TeamPanel = () => { }, { id: idx + 1, data: member.email }, { - // TODO - Add select dropdown id: idx + 2, data: roles, }, - // FEATURE STILL TO BE IMPLEMENTED - // { - // // TODO - Add delete onClick - // id: idx + 3, - // data: ( - // - // - // - // ), - // }, ], }; }), }; setTableData(data); - }, [members, filter]); + }, [filter, members, roleMap, theme]); useEffect(() => { setIsDisabled(Object.keys(errors).length !== 0 || toInvite.email === ""); }, [errors, toInvite.email]); - - // RENAME ORGANIZATION - // const toggleEdit = () => { - // setOrgStates((prev) => ({ ...prev, isEdit: !prev.isEdit })); - // }; - // const handleRename = () => {}; - - // INVITE MEMBER const [isOpen, setIsOpen] = useState(false); const handleChange = (event) => { @@ -226,58 +198,11 @@ const TeamPanel = () => { }, }} > - {/* FEATURE STILL TO BE IMPLEMENTED */} - {/* - - Organization name - - - - setOrgStates((prev) => ({ - ...prev, - name: event.target.value, - })) - } - disabled={!orgStates.isEdit} - sx={{ - color: theme.palette.otherColors.bluishGray, - "& .Mui-disabled": { - WebkitTextFillColor: "initial !important", - }, - "& .Mui-disabled fieldset": { - borderColor: "transparent !important", - }, - }} - inputProps={{ - sx: { textAlign: "end", padding: theme.spacing(4) }, - }} - /> - : ""} - onClick={() => toggleEdit()} - sx={{ - minWidth: 0, - paddingX: theme.spacing(4), - ml: orgStates.isEdit ? theme.spacing(4) : 0, - }} - /> - - - */} Team members { paginated={false} reversed={true} table={"team"} + emptyMessage={"There are no team members with this role"} /> @@ -341,7 +267,7 @@ const TeamPanel = () => { theme={theme} > Date: Tue, 17 Dec 2024 14:04:42 -0800 Subject: [PATCH 17/64] remove advanced status page --- Client/src/Pages/AdvancedSettings/index.css | 0 Client/src/Pages/AdvancedSettings/index.jsx | 361 -------------------- Client/src/Pages/Settings/index.jsx | 23 +- Client/src/Routes/index.jsx | 5 - 4 files changed, 1 insertion(+), 388 deletions(-) delete mode 100644 Client/src/Pages/AdvancedSettings/index.css delete mode 100644 Client/src/Pages/AdvancedSettings/index.jsx diff --git a/Client/src/Pages/AdvancedSettings/index.css b/Client/src/Pages/AdvancedSettings/index.css deleted file mode 100644 index e69de29bb..000000000 diff --git a/Client/src/Pages/AdvancedSettings/index.jsx b/Client/src/Pages/AdvancedSettings/index.jsx deleted file mode 100644 index 433829f28..000000000 --- a/Client/src/Pages/AdvancedSettings/index.jsx +++ /dev/null @@ -1,361 +0,0 @@ -import { useTheme } from "@emotion/react"; -import { Box, Stack, Typography } from "@mui/material"; -import TextInput from "../../Components/Inputs/TextInput"; -import Link from "../../Components/Link"; -import "./index.css"; -import { useDispatch, useSelector } from "react-redux"; -import { createToast } from "../../Utils/toastUtils"; -import PropTypes from "prop-types"; -import LoadingButton from "@mui/lab/LoadingButton"; -import { ConfigBox } from "../Settings/styled"; -import { useNavigate } from "react-router"; -import { getAppSettings, updateAppSettings } from "../../Features/Settings/settingsSlice"; -import { useState, useEffect } from "react"; -import Select from "../../Components/Inputs/Select"; -import { advancedSettingsValidation } from "../../Validation/validation"; -import { buildErrors, hasValidationErrors } from "../../Validation/error"; -import { useIsAdmin } from "../../Hooks/useIsAdmin"; - -const AdvancedSettings = () => { - const navigate = useNavigate(); - const isAdmin = useIsAdmin(); - useEffect(() => { - if (!isAdmin) { - navigate("/"); - } - }, [navigate, isAdmin]); - const [errors, setErrors] = useState({}); - const theme = useTheme(); - const { authToken } = useSelector((state) => state.auth); - const dispatch = useDispatch(); - const settings = useSelector((state) => state.settings); - const [localSettings, setLocalSettings] = useState({ - apiBaseUrl: "", - logLevel: "debug", - systemEmailHost: "", - systemEmailPort: "", - systemEmailAddress: "", - systemEmailPassword: "", - jwtTTLNum: 99, - jwtTTLUnits: "days", - jwtTTL: "99d", - dbType: "", - redisHost: "", - redisPort: "", - pagespeedApiKey: "", - }); - - const parseJWTTTL = (data) => { - if (data.jwtTTL) { - const len = data.jwtTTL.length; - data.jwtTTLNum = data.jwtTTL.substring(0, len - 1); - data.jwtTTLUnits = unitItems.filter( - (itm) => itm._id == data.jwtTTL.substring(len - 1) - )[0].name; - } - }; - - useEffect(() => { - const getSettings = async () => { - const action = await dispatch(getAppSettings({ authToken })); - if (action.payload.success) { - parseJWTTTL(action.payload.data); - setLocalSettings(action.payload.data); - } else { - createToast({ body: "Failed to get settings" }); - } - }; - getSettings(); - }, [authToken, dispatch]); - - const logItems = [ - { _id: 1, name: "none" }, - { _id: 2, name: "debug" }, - { _id: 3, name: "error" }, - { _id: 4, name: "warn" }, - ]; - - const logItemLookup = { - none: 1, - debug: 2, - error: 3, - warn: 4, - }; - - const unitItemLookup = { - days: "d", - hours: "h", - }; - const unitItems = Object.keys(unitItemLookup).map((key) => ({ - _id: unitItemLookup[key], - name: key, - })); - - const handleLogLevel = (e) => { - const id = e.target.value; - const newLogLevel = logItems.find((item) => item._id === id).name; - setLocalSettings({ ...localSettings, logLevel: newLogLevel }); - }; - - const handleJWTTTLUnits = (e) => { - const id = e.target.value; - const newUnits = unitItems.find((item) => item._id === id).name; - setLocalSettings({ ...localSettings, jwtTTLUnits: newUnits }); - }; - - const handleBlur = (event) => { - const { value, id } = event.target; - const { error } = advancedSettingsValidation.validate( - { [id]: value }, - { - abortEarly: false, - } - ); - setErrors((prev) => { - return buildErrors(prev, id, error); - }); - }; - const handleChange = (event) => { - const { value, id } = event.target; - setLocalSettings({ ...localSettings, [id]: value }); - }; - - const handleSave = async () => { - localSettings.jwtTTL = - localSettings.jwtTTLNum + unitItemLookup[localSettings.jwtTTLUnits]; - if (hasValidationErrors(localSettings, advancedSettingsValidation, setErrors)) { - return; - } - const action = await dispatch( - updateAppSettings({ settings: localSettings, authToken }) - ); - let body = ""; - if (action.payload.success) { - parseJWTTTL(action.payload.data); - setLocalSettings(action.payload.data); - body = "Settings saved successfully"; - } else { - body = "Failed to save settings"; - } - createToast({ body }); - }; - - return ( - - - - - Client settings - - Modify client settings here. - - - - - - - - - - Email settings - - Set your host email settings here. These settings are used for sending - system emails. - - - - - - - - - - - - Server settings - - Modify server settings here. - - - - - - - - - - - - - - - - About - - - BlueWave Uptime v1.0.0 - - Developed by Bluewave Labs. - - - - - - - Save - - - - - ); -}; - -AdvancedSettings.propTypes = { - isAdmin: PropTypes.bool, -}; -export default AdvancedSettings; diff --git a/Client/src/Pages/Settings/index.jsx b/Client/src/Pages/Settings/index.jsx index aab9fa537..f3fcb8376 100644 --- a/Client/src/Pages/Settings/index.jsx +++ b/Client/src/Pages/Settings/index.jsx @@ -324,28 +324,7 @@ const Settings = () => { /> )} - {isAdmin && ( - - - Advanced settings - - Click here to modify advanced settings - - - - - - - - - )} + About diff --git a/Client/src/Routes/index.jsx b/Client/src/Routes/index.jsx index 784b44609..7d444f2ab 100644 --- a/Client/src/Routes/index.jsx +++ b/Client/src/Routes/index.jsx @@ -19,7 +19,6 @@ import SetNewPassword from "../Pages/Auth/SetNewPassword"; import NewPasswordConfirmed from "../Pages/Auth/NewPasswordConfirmed"; import ProtectedRoute from "../Components/ProtectedRoute"; import Details from "../Pages/Uptime/Details"; -import AdvancedSettings from "../Pages/AdvancedSettings"; import Maintenance from "../Pages/Maintenance"; import Configure from "../Pages/Uptime/Configure"; import PageSpeed from "../Pages/PageSpeed"; @@ -114,10 +113,6 @@ const Routes = () => { path="settings" element={} /> - } - /> } From 7c5c3507d8c332bf469d758b69641f7f8950bb76 Mon Sep 17 00:00:00 2001 From: Peter Carl Pardo Date: Wed, 18 Dec 2024 18:57:38 +0800 Subject: [PATCH 18/64] feat: removed useEffect in toggling theme --- Client/src/Components/ThemeSwitch/index.css | 14 +++++++------- Client/src/Components/ThemeSwitch/index.jsx | 14 +++++--------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/Client/src/Components/ThemeSwitch/index.css b/Client/src/Components/ThemeSwitch/index.css index c80a0f2d1..2519a0be8 100644 --- a/Client/src/Components/ThemeSwitch/index.css +++ b/Client/src/Components/ThemeSwitch/index.css @@ -6,20 +6,20 @@ stroke-width: 2px; } -[data-theme="dark"] .sun-and-moon > .sun { +.theme-dark .sun-and-moon > .sun { transform: scale(1.75); } -[data-theme="dark"] .sun-and-moon > .sun-beams { +.theme-dark .sun-and-moon > .sun-beams { opacity: 0; } -[data-theme="dark"] .sun-and-moon > .moon > circle { +.theme-dark .sun-and-moon > .moon > circle { transform: translateX(-7px); } @supports (cx: 1) { - [data-theme="dark"] .sun-and-moon > .moon > circle { + .theme-dark .sun-and-moon > .moon > circle { cx: 17; transform: translateX(0); } @@ -46,18 +46,18 @@ } } - [data-theme="dark"] .sun-and-moon > .sun { + .theme-dark .sun-and-moon > .sun { transition-timing-function: var(--ease-3); transition-duration: 0.25s; transform: scale(1.75); } - [data-theme="dark"] .sun-and-moon > .sun-beams { + .theme-dark .sun-and-moon > .sun-beams { transition-duration: 0.15s; transform: rotateZ(-25deg); } - [data-theme="dark"] .sun-and-moon > .moon > circle { + .theme-dark .sun-and-moon > .moon > circle { transition-duration: 0.5s; transition-delay: 0.25s; } diff --git a/Client/src/Components/ThemeSwitch/index.jsx b/Client/src/Components/ThemeSwitch/index.jsx index 4cb6c3a14..b751f542a 100644 --- a/Client/src/Components/ThemeSwitch/index.jsx +++ b/Client/src/Components/ThemeSwitch/index.jsx @@ -9,14 +9,13 @@ * Apache License: https://www.apache.org/licenses/LICENSE-2.0 */ -import React, { useEffect } from "react"; import { IconButton } from "@mui/material"; import SunAndMoonIcon from "./SunAndMoonIcon"; -import "./index.css"; import { useDispatch, useSelector } from "react-redux"; import { setMode } from "../../Features/UI/uiSlice"; +import "./index.css"; -const ThemeSwitch = () => { +const ThemeSwitch = ({ width = 48, height = 48 }) => { const mode = useSelector((state) => state.ui.mode); const dispatch = useDispatch(); @@ -24,20 +23,17 @@ const ThemeSwitch = () => { dispatch(setMode(mode === "light" ? "dark" : "light")); }; - useEffect(() => { - document.body.setAttribute("data-theme", mode); - }, [mode]); - return ( Date: Wed, 18 Dec 2024 13:33:35 +0000 Subject: [PATCH 19/64] fix(deps): update dependency bullmq to v5.34.3 --- Server/package-lock.json | 8 ++++---- Server/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Server/package-lock.json b/Server/package-lock.json index 3f57f737a..9c1315867 100644 --- a/Server/package-lock.json +++ b/Server/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "axios": "^1.7.2", "bcrypt": "^5.1.1", - "bullmq": "5.34.2", + "bullmq": "5.34.3", "cors": "^2.8.5", "dockerode": "4.0.2", "dotenv": "^16.4.5", @@ -1223,9 +1223,9 @@ } }, "node_modules/bullmq": { - "version": "5.34.2", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.2.tgz", - "integrity": "sha512-eUzeCswrKbQDE1WY8h4ZTBtynOzCU5qx9felFdYOmIJrsy0warDahHKUiCZ6dUCs6ZxYMGtcaciIMcAf1L54yw==", + "version": "5.34.3", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.34.3.tgz", + "integrity": "sha512-S8/V11w7p6jYAGvv+00skLza/4inTOupWPe0uCD8mZSUiYKzvmW4/YEB+KVjZI2CC2oD3KJ3t7/KkUd31MxMig==", "license": "MIT", "dependencies": { "cron-parser": "^4.6.0", diff --git a/Server/package.json b/Server/package.json index 93d4d6be8..c480aea4c 100644 --- a/Server/package.json +++ b/Server/package.json @@ -14,7 +14,7 @@ "dependencies": { "axios": "^1.7.2", "bcrypt": "^5.1.1", - "bullmq": "5.34.2", + "bullmq": "5.34.3", "cors": "^2.8.5", "dockerode": "4.0.2", "dotenv": "^16.4.5", From 6e29e37241f20a3704f00df363bb06d14bd777b0 Mon Sep 17 00:00:00 2001 From: Shemy Gan Date: Wed, 18 Dec 2024 10:42:41 -0500 Subject: [PATCH 20/64] - Add divider for setting --- Client/src/Pages/Settings/styled.jsx | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Client/src/Pages/Settings/styled.jsx b/Client/src/Pages/Settings/styled.jsx index 269706a27..aeefdaebb 100644 --- a/Client/src/Pages/Settings/styled.jsx +++ b/Client/src/Pages/Settings/styled.jsx @@ -5,19 +5,27 @@ export const ConfigBox = styled(Stack)(({ theme }) => ({ flexDirection: "row", justifyContent: "space-between", gap: theme.spacing(20), - paddingTop: theme.spacing(12), - paddingInline: theme.spacing(15), - paddingBottom: theme.spacing(25), backgroundColor: theme.palette.background.main, border: 1, borderStyle: "solid", borderColor: theme.palette.border.light, borderRadius: theme.spacing(2), + "& > *": { + paddingTop: theme.spacing(12), + paddingBottom: theme.spacing(18), + }, "& > div:first-of-type": { flex: 0.7, + borderRight: 1, + borderRightStyle: "solid", + borderRightColor: theme.palette.border.light, + paddingRight: theme.spacing(15), + paddingLeft: theme.spacing(15), }, "& > div:last-of-type": { flex: 1, + paddingRight: theme.spacing(20), + paddingLeft: theme.spacing(18), }, "& h1, & h2": { color: theme.palette.text.secondary, From 7f7423aed830ab9bdff0587e15841023d1c36d01 Mon Sep 17 00:00:00 2001 From: Anand Roy Date: Wed, 18 Dec 2024 17:46:44 +0000 Subject: [PATCH 21/64] reset password link added --- .../Pages/Auth/Login/Components/EmailStep.jsx | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/Client/src/Pages/Auth/Login/Components/EmailStep.jsx b/Client/src/Pages/Auth/Login/Components/EmailStep.jsx index f78193186..08ae51c4f 100644 --- a/Client/src/Pages/Auth/Login/Components/EmailStep.jsx +++ b/Client/src/Pages/Auth/Login/Components/EmailStep.jsx @@ -1,8 +1,9 @@ -import { useRef, useEffect } from "react"; +import { useRef, useEffect } from "react"; import { Box, Button, Stack, Typography } from "@mui/material"; import { useTheme } from "@emotion/react"; import TextInput from "../../../../Components/Inputs/TextInput"; import PropTypes from "prop-types"; +import { useNavigate } from "react-router"; /** * Renders the email step of the login process which includes an email field. @@ -18,6 +19,7 @@ import PropTypes from "prop-types"; const EmailStep = ({ form, errors, onSubmit, onChange }) => { const theme = useTheme(); const inputRef = useRef(null); + const navigate = useNavigate(); useEffect(() => { if (inputRef.current) { @@ -25,11 +27,19 @@ const EmailStep = ({ form, errors, onSubmit, onChange }) => { } }, []); + const handleNavigate = () => { + if (form.email !== "" && !errors.email) { + sessionStorage.setItem("email", form.email); + } + navigate("/forgot-password"); + }; + return ( <> Log In @@ -80,6 +90,32 @@ const EmailStep = ({ form, errors, onSubmit, onChange }) => { + + + Forgot password? + + + Reset password + + ); @@ -92,4 +128,4 @@ EmailStep.propTypes = { onChange: PropTypes.func.isRequired, }; -export default EmailStep; \ No newline at end of file +export default EmailStep; From bd5bc2617c031c78909cc5165b643f32aa52c4ec Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 18 Dec 2024 12:19:21 -0800 Subject: [PATCH 22/64] Add a config box component --- Client/src/Components/ConfigBox/index.jsx | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Client/src/Components/ConfigBox/index.jsx diff --git a/Client/src/Components/ConfigBox/index.jsx b/Client/src/Components/ConfigBox/index.jsx new file mode 100644 index 000000000..7650dd47f --- /dev/null +++ b/Client/src/Components/ConfigBox/index.jsx @@ -0,0 +1,38 @@ +import { Stack, styled } from "@mui/material"; + +const ConfigBox = styled(Stack)(({ theme }) => ({ + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + gap: theme.spacing(20), + backgroundColor: theme.palette.background.main, + border: 1, + borderStyle: "solid", + borderColor: theme.palette.border.light, + borderRadius: theme.spacing(2), + "& > *": { + paddingTop: theme.spacing(12), + paddingBottom: theme.spacing(18), + }, + "& > div:first-of-type": { + flex: 0.7, + borderRight: 1, + borderRightStyle: "solid", + borderRightColor: theme.palette.border.light, + paddingRight: theme.spacing(15), + paddingLeft: theme.spacing(15), + }, + "& > div:last-of-type": { + flex: 1, + paddingRight: theme.spacing(20), + paddingLeft: theme.spacing(18), + }, + "& h1, & h2": { + color: theme.palette.text.secondary, + }, + "& p": { + color: theme.palette.text.tertiary, + }, +})); + +export default ConfigBox; From c47ec6ce8bb6925ea6f29965f41066a2cf757541 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Wed, 18 Dec 2024 12:20:09 -0800 Subject: [PATCH 23/64] refactor create maintenance to use new ConfigBox --- .../Maintenance/CreateMaintenance/index.jsx | 232 ++++++++---------- .../Maintenance/CreateMaintenance/styled.jsx | 25 -- 2 files changed, 99 insertions(+), 158 deletions(-) delete mode 100644 Client/src/Pages/Maintenance/CreateMaintenance/styled.jsx diff --git a/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx index f41603330..c832d463a 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx @@ -2,7 +2,7 @@ import { Box, Button, Stack, Typography } from "@mui/material"; import { useSelector } from "react-redux"; import { useTheme } from "@emotion/react"; import { useEffect, useState } from "react"; -import { ConfigBox } from "./styled"; +import ConfigBox from "../../../Components/ConfigBox"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { LocalizationProvider } from "@mui/x-date-pickers"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; @@ -321,18 +321,27 @@ const CreateMaintenance = () => { Your pings won't be sent during this time frame - - - General Settings - - + + + + General Settings + + + + { + handleFormChange("name", event.target.value); + }} + error={errors["name"] ? true : false} + helperText={errors["name"]} + />