diff --git a/.chores.md b/.chores.md
new file mode 100644
index 000000000..ba0fd4dd7
--- /dev/null
+++ b/.chores.md
@@ -0,0 +1,12 @@
+- [ ] Take validation out from the component.
+ - [ ] SetNewPassword
+ - [ ] Register
+- [ ] Create Check with highlight component. Check receives: status and message
+- [ ] Split some of these user feedbacks? Like:
+ - [ ] Must contain at least one special character,
+ - [ ] Must contain at least one number,
+ - [ ] Must contain at least one upper character,
+ - [ ] Must contain at least one lower character
+- [ ] Pass mismatching password user feedback as the other messages, for consistency
+- [ ] Get rid of toast message
+- [ ] Do it on blur
diff --git a/Client/src/App.jsx b/Client/src/App.jsx
index 98772ecca..6cb2f433a 100644
--- a/Client/src/App.jsx
+++ b/Client/src/App.jsx
@@ -1,7 +1,10 @@
+import { useEffect } from "react";
import { Routes, Route } from "react-router-dom";
+import { useSelector } from "react-redux";
+import { useDispatch } from "react-redux";
+// import "./App.css";
import "react-toastify/dist/ReactToastify.css";
import { ToastContainer } from "react-toastify";
-// import "./App.css";
import NotFound from "./Pages/NotFound";
import Login from "./Pages/Auth/Login";
import Register from "./Pages/Auth/Register/Register";
@@ -21,21 +24,18 @@ import ProtectedRoute from "./Components/ProtectedRoute";
import Details from "./Pages/Monitors/Details";
import AdvancedSettings from "./Pages/AdvancedSettings";
import Maintenance from "./Pages/Maintenance";
-import withAdminCheck from "./HOC/withAdminCheck";
-import withAdminProp from "./HOC/withAdminProp";
import Configure from "./Pages/Monitors/Configure";
import PageSpeed from "./Pages/PageSpeed";
import CreatePageSpeed from "./Pages/PageSpeed/CreatePageSpeed";
import CreateNewMaintenanceWindow from "./Pages/Maintenance/CreateMaintenance";
import PageSpeedDetails from "./Pages/PageSpeed/Details";
import PageSpeedConfigure from "./Pages/PageSpeed/Configure";
+import withAdminCheck from "./HOC/withAdminCheck";
+import withAdminProp from "./HOC/withAdminProp";
import { ThemeProvider } from "@emotion/react";
import lightTheme from "./Utils/Theme/lightTheme";
import darkTheme from "./Utils/Theme/darkTheme";
-import { useSelector } from "react-redux";
import { CssBaseline } from "@mui/material";
-import { useEffect } from "react";
-import { useDispatch } from "react-redux";
import { getAppSettings } from "./Features/Settings/settingsSlice";
import { logger } from "./Utils/Logger"; // Import the logger
import { networkService } from "./main";
@@ -181,16 +181,18 @@ function App() {
path="/register"
element={}
/>
+
}
/>
- {/* } /> */}
+
}
/>
+
}
diff --git a/Client/src/Components/Check/Check.jsx b/Client/src/Components/Check/Check.jsx
index 7ef51137e..9c1ec57fb 100644
--- a/Client/src/Components/Check/Check.jsx
+++ b/Client/src/Components/Check/Check.jsx
@@ -20,7 +20,7 @@ import { useTheme } from "@emotion/react";
*
* @returns {React.Element} The `Check` component with a check icon and a label, defined by the `text` prop.
*/
-const Check = ({ text, variant = "info", outlined = false }) => {
+const Check = ({ text, noHighlightText, variant = "info", outlined = false }) => {
const theme = useTheme();
const colors = {
success: theme.palette.success.main,
@@ -54,7 +54,7 @@ const Check = ({ text, variant = "info", outlined = false }) => {
opacity: 0.8,
}}
>
- {text}
+ {noHighlightText} {text}
);
@@ -62,6 +62,7 @@ const Check = ({ text, variant = "info", outlined = false }) => {
Check.propTypes = {
text: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired,
+ noHighlightText: PropTypes.string,
variant: PropTypes.oneOf(["info", "error", "success"]),
outlined: PropTypes.bool,
};
diff --git a/Client/src/Pages/Auth/SetNewPassword.jsx b/Client/src/Pages/Auth/SetNewPassword.jsx
index 6c8f7418e..9d1497b47 100644
--- a/Client/src/Pages/Auth/SetNewPassword.jsx
+++ b/Client/src/Pages/Auth/SetNewPassword.jsx
@@ -1,20 +1,20 @@
+import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
+import { useNavigate } from "react-router-dom";
+import { useParams } from "react-router-dom";
+import { useTheme } from "@emotion/react";
+import { Box, Stack, Typography } from "@mui/material";
+import LoadingButton from "@mui/lab/LoadingButton";
import { setNewPassword } from "../../Features/Auth/authSlice";
import { createToast } from "../../Utils/toastUtils";
-import { Box, Stack, Typography } from "@mui/material";
-import { useTheme } from "@emotion/react";
-import { useParams } from "react-router-dom";
-import { useState } from "react";
import { credentials } from "../../Validation/validation";
-import { useNavigate } from "react-router-dom";
import Check from "../../Components/Check/Check";
import Field from "../../Components/Inputs/Field";
-import LockIcon from "../../assets/icons/lock.svg?react";
-import Background from "../../assets/Images/background-grid.svg?react";
-import Logo from "../../assets/icons/bwu-icon.svg?react";
-import LoadingButton from "@mui/lab/LoadingButton";
-import "./index.css";
import { IconBox } from "./styled";
+import LockIcon from "../../assets/icons/lock.svg?react";
+import Logo from "../../assets/icons/bwu-icon.svg?react";
+import Background from "../../assets/Images/background-grid.svg?react";
+import "./index.css";
const SetNewPassword = () => {
const navigate = useNavigate();
@@ -27,11 +27,6 @@ const SetNewPassword = () => {
confirm: "",
});
- const idMap = {
- "register-password-input": "password",
- "confirm-password-input": "confirm",
- };
-
const { isLoading } = useSelector((state) => state.auth);
const { token } = useParams();
@@ -41,7 +36,7 @@ const SetNewPassword = () => {
const passwordForm = { ...form };
const { error } = credentials.validate(passwordForm, {
abortEarly: false,
- context: { password: form.password },
+ /* context: { password: form.password }, */
});
if (error) {
@@ -82,8 +77,8 @@ const SetNewPassword = () => {
};
const handleChange = (event) => {
- const { value, id } = event.target;
- const name = idMap[id];
+ //TODO Change from id to name
+ const { value, name } = event.target;
setForm((prev) => ({
...prev,
[name]: value,
@@ -91,15 +86,35 @@ const SetNewPassword = () => {
const { error } = credentials.validate(
{ [name]: value },
- { abortEarly: false, context: { password: form.password } }
+ {
+ abortEarly: false,
+ context: { password: form.password },
+ }
);
- setErrors((prev) => {
- const prevErrors = { ...prev };
- if (error) prevErrors[name] = error.details[0].message;
- else delete prevErrors[name];
- return prevErrors;
- });
+ const errors = error.details.map((error) => error.message);
+
+ setErrors((prev) => ({ ...prev, [name]: errors }));
+ };
+
+ console.log(errors);
+
+ /* function getCheckStatus() */
+
+ const feedbacks = {
+ length: "info" /* !errors.password
+ ? "info"
+ : errors.password === "length" || errors.password === "empty"
+ ? "error"
+ : "success", */,
+ special: "info" /* !errors
+ ? "info"
+ : errors.password === "length" || errors.password === "empty"
+ ? "error"
+ : "success", */,
+ number: "info",
+ upper: "success",
+ lower: "error",
};
return (
@@ -189,7 +204,7 @@ const SetNewPassword = () => {
>
{
>
{
characters long
>
}
- variant={
- errors?.password === "Password is required"
- ? "error"
- : form.password === ""
- ? "info"
- : form.password.length < 8
- ? "error"
- : "success"
- }
- />
-
- Must contain one special
- character and a number
- >
- }
- variant={
- errors?.password === "Password is required"
- ? "error"
- : form.password === ""
- ? "info"
- : !/^(?=.*[!@#$%^&*(),.?":{}|])(?=.*\d).+$/.test(form.password)
- ? "error"
- : "success"
- }
+ variant={feedbacks.length}
/>
Must contain at least one
- upper and lower character
+ special character
>
}
- variant={
- errors?.password === "Password is required"
- ? "error"
- : form.password === ""
- ? "info"
- : !/^(?=.*[A-Z])(?=.*[a-z]).+$/.test(form.password)
- ? "error"
- : "success"
+ variant={feedbacks.special}
+ />
+
+ Must contain at least one
+ one number
+ >
}
+ variant={feedbacks.number}
+ />
+
+ Must contain at least one
+ upper character
+ >
+ }
+ variant={feedbacks.upper}
+ />
+
+ Must contain at least one
+ lower character
+ >
+ }
+ variant={feedbacks.lower}
/>
diff --git a/Client/src/Validation/validation.js b/Client/src/Validation/validation.js
index c620bdf43..82dee8541 100644
--- a/Client/src/Validation/validation.js
+++ b/Client/src/Validation/validation.js
@@ -17,26 +17,33 @@ const passwordSchema = joi
.trim()
.min(8)
.messages({
- "string.empty": "Password is required",
- "string.min": "Password must be at least 8 characters long",
+ "string.empty": "empty",
+ "string.min": "length",
})
.custom((value, helpers) => {
if (!/[A-Z]/.test(value)) {
- return helpers.message("Password must contain at least one uppercase letter");
+ return helpers.message("uppercase");
}
+ return value;
+ })
+ .custom((value, helpers) => {
if (!/[a-z]/.test(value)) {
- return helpers.message("Password must contain at least one lowercase letter");
+ return helpers.message("lowercase");
}
+ return value;
+ })
+ .custom((value, helpers) => {
if (!/\d/.test(value)) {
- return helpers.message("Password must contain at least one number");
+ return helpers.message("number");
}
+ return value;
+ })
+ .custom((value, helpers) => {
if (!/[!@#$%^&*]/.test(value)) {
- return helpers.message("Password must contain at least one special character");
+ return helpers.message("special");
}
-
return value;
});
-
const credentials = joi.object({
firstName: nameSchema,
lastName: nameSchema,
@@ -61,12 +68,12 @@ const credentials = joi.object({
.string()
.trim()
.messages({
- "string.empty": "Password confirmation is required",
+ "string.empty": "empty",
})
.custom((value, helpers) => {
const { password } = helpers.prefs.context;
if (value !== password) {
- return helpers.message("Passwords do not match");
+ return helpers.message("different");
}
return value;
}),