From 0ad08f431ee84b6ed2d5baf549a9247fa714c66f Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Tue, 20 Aug 2024 20:33:28 +0330 Subject: [PATCH 1/6] Marshali data, logging it, creating post req, send to BE --- Client/package-lock.json | 2 +- Client/package.json | 2 +- .../CreateMaintenanceWindow/index.jsx | 25 +++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Client/package-lock.json b/Client/package-lock.json index 44e276f63..2f1543bba 100644 --- a/Client/package-lock.json +++ b/Client/package-lock.json @@ -18,7 +18,7 @@ "@mui/x-data-grid": "7.3.2", "@mui/x-date-pickers": "7.3.2", "@reduxjs/toolkit": "2.2.5", - "axios": "1.7.4", + "axios": "^1.7.4", "chart.js": "^4.4.3", "dayjs": "1.11.11", "joi": "17.13.1", diff --git a/Client/package.json b/Client/package.json index 769e1f4a6..22f15f7f9 100644 --- a/Client/package.json +++ b/Client/package.json @@ -20,7 +20,7 @@ "@mui/x-data-grid": "7.3.2", "@mui/x-date-pickers": "7.3.2", "@reduxjs/toolkit": "2.2.5", - "axios": "1.7.4", + "axios": "^1.7.4", "chart.js": "^4.4.3", "dayjs": "1.11.11", "joi": "17.13.1", diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx index 8fff6e4a1..a5cbfaf56 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx @@ -10,6 +10,7 @@ import dayjs from "dayjs"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { MobileTimePicker } from "@mui/x-date-pickers/MobileTimePicker"; import Field from "../../../Components/Inputs/Field"; +import axios from "axios"; const directory = { title: "Create a maintenance window", @@ -71,6 +72,29 @@ const CreateNewMaintenanceWindow = () => { })); }; + const handleSubmit = async () => { + const data = { + repeat: values.repeat, + date: values.date.format("YYYY-MM-DD"), + startTime: values.startTime.format("HH:mm"), + duration: values.duration, + unit: values.unit, + friendlyName: values.friendlyName, + addMonitors: values.AddMonitors, + }; + + console.log("Submitting data: ", data); + + await axios + .post("/address-of-the-route", data) + .then((res) => { + console.log("Response: ", res.data); + }) + .catch((err) => { + console.log("Error: ", err); + }); + }; + const configOptions = [ { title: "Repeat", @@ -246,6 +270,7 @@ const CreateNewMaintenanceWindow = () => { }} level="primary" label="Create" + onClick={handleSubmit} /> From b247fabde0168a8cf639a24f9a1f1d3161edd796 Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Wed, 21 Aug 2024 09:40:09 +0330 Subject: [PATCH 2/6] adding validations and toasts as validation error --- .../CreateMaintenanceWindow/index.jsx | 33 ++++++++---- Client/src/Validation/validation.js | 52 +++++++++++++++---- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx index a5cbfaf56..c4789f883 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx @@ -10,7 +10,9 @@ import dayjs from "dayjs"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { MobileTimePicker } from "@mui/x-date-pickers/MobileTimePicker"; import Field from "../../../Components/Inputs/Field"; -import axios from "axios"; +import { maintenanceWindowValidation } from "../../../Validation/validation"; +import { logger } from "../../../Utils/Logger"; +import { createToast } from "../../../Utils/toastUtils"; const directory = { title: "Create a maintenance window", @@ -63,6 +65,7 @@ const CreateNewMaintenanceWindow = () => { friendlyName: "", AddMonitors: "", }); + const [errors, setErrors] = useState({}); const handleChange = (event, name) => { const { value } = event.target; @@ -83,16 +86,26 @@ const CreateNewMaintenanceWindow = () => { addMonitors: values.AddMonitors, }; - console.log("Submitting data: ", data); - - await axios - .post("/address-of-the-route", data) - .then((res) => { - console.log("Response: ", res.data); - }) - .catch((err) => { - console.log("Error: ", err); + const { error } = maintenanceWindowValidation.validate(data, { + abortEarly: false, + }); + logger.log("error: ", error); + if (error) { + 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", + }); + logger.error("Validation errors:", error.details); + } + + logger.log("Submitting data: ", data); }; const configOptions = [ diff --git a/Client/src/Validation/validation.js b/Client/src/Validation/validation.js index ab2501199..6719c2c1c 100644 --- a/Client/src/Validation/validation.js +++ b/Client/src/Validation/validation.js @@ -72,14 +72,10 @@ const credentials = joi.object({ }); const monitorValidation = joi.object({ - url: joi - .string() - .uri({ allowRelative: true }) - .trim() - .messages({ - "string.empty": "This field is required.", - "string.uri": "The URL you provided is not valid.", - }), + url: joi.string().uri({ allowRelative: true }).trim().messages({ + "string.empty": "This field is required.", + "string.uri": "The URL you provided is not valid.", + }), name: joi.string().trim().max(50).allow("").messages({ "string.max": "This field should not exceed the 50 characters limit.", }), @@ -108,4 +104,42 @@ const imageValidation = joi.object({ }), }); -export { credentials, imageValidation, monitorValidation }; +const maintenanceWindowValidation = joi.object({ + repeat: joi.number().valid(1, 2, 3).required().messages({ + "number.base": "Repeat must be a number.", + "any.only": "Repeat must be one of [1, 2, 3].", + "any.required": "Repeat is required.", + }), + date: joi.date().required().messages({ + "date.base": "Date must be a valid date.", + "any.required": "Date is required.", + }), + startTime: joi.string().required().messages({ + "string.base": "Start time must be a valid time.", + "any.required": "Start time is required.", + }), + duration: joi.number().required().messages({ + "number.base": "Duration must be a number.", + "any.required": "Duration is required.", + }), + unit: joi.string().valid("minutes", "hours", "days").required().messages({ + "string.base": "Unit must be a string.", + "any.only": "Unit must be one of ['minutes', 'hours', 'days'].", + "any.required": "Unit is required.", + }), + friendlyName: joi.string().required().max(100).messages({ + "string.max": "Friendly name must be less than 100 characters.", + "any.required": "Friendly name is required.", + }), + addMonitors: joi.string().required().messages({ + "string.base": "Add monitors must be a string.", + "any.required": "Add monitors is required.", + }), +}); + +export { + credentials, + imageValidation, + monitorValidation, + maintenanceWindowValidation, +}; From aecddb22bbf34907bcf8e7b996a347f62b73829f Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Wed, 21 Aug 2024 22:50:42 +0330 Subject: [PATCH 3/6] validation helper texts and input type --- .../Maintenance/CreateMaintenanceWindow/index.jsx | 3 +++ Client/src/Validation/validation.js | 13 +++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx index c4789f883..eb19ba3d2 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.jsx @@ -163,6 +163,7 @@ const CreateNewMaintenanceWindow = () => { placeholder="60" onChange={(e) => handleChange(e, "duration")} value={values.duration} + error={errors.duration} /> handleChange(e, "unit")} From d81bb8fe89c4bf10adef00ee0bb2ed9c8e7ddbe0 Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Thu, 22 Aug 2024 20:23:17 +0330 Subject: [PATCH 5/6] fixes --- Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css index e0311d4e7..4ee17db72 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css +++ b/Client/src/Pages/Maintenance/CreateMaintenanceWindow/index.css @@ -23,7 +23,7 @@ } .duration-config .field-text .MuiTextField-root, -.duration-config .field { +.maintenance-options .duration-config .field { width: 70px; min-width: 70px; max-width: 70px; From f5e589886b1284a3d61870e424a6bb7001f0c01f Mon Sep 17 00:00:00 2001 From: Mohammad Khalilzadeh Date: Sat, 24 Aug 2024 10:11:13 +0330 Subject: [PATCH 6/6] adding the type number --- Client/src/Components/Inputs/Field/index.jsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Client/src/Components/Inputs/Field/index.jsx b/Client/src/Components/Inputs/Field/index.jsx index 0b2fe56fe..f44201e3f 100644 --- a/Client/src/Components/Inputs/Field/index.jsx +++ b/Client/src/Components/Inputs/Field/index.jsx @@ -177,7 +177,14 @@ const Field = forwardRef( ); Field.propTypes = { - type: PropTypes.oneOf(["text", "password", "url", "email", "description"]), + type: PropTypes.oneOf([ + "text", + "password", + "url", + "email", + "description", + "number", + ]), id: PropTypes.string.isRequired, label: PropTypes.string, https: PropTypes.bool,